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 35 struct _profileInt { 36 LPCSTR section; 37 LPCSTR key; 38 LPCSTR value; 39 LPCSTR iniFile; 40 INT defaultVal; 41 UINT result; 42 UINT result9x; 43 }; 44 45 static void test_profile_int(void) 46 { 47 struct _profileInt profileInt[]={ 48 { NULL, NULL, NULL, NULL, 70, 0 , 0}, /* 0 */ 49 { NULL, NULL, NULL, TESTFILE, -1, 4294967295U, 0}, 50 { NULL, NULL, NULL, TESTFILE, 1, 1 , 0}, 51 { SECTION, NULL, NULL, TESTFILE, -1, 4294967295U, 0}, 52 { SECTION, NULL, NULL, TESTFILE, 1, 1 , 0}, 53 { NULL, KEY, NULL, TESTFILE, -1, 4294967295U, 0}, /* 5 */ 54 { NULL, KEY, NULL, TESTFILE, 1, 1 , 0}, 55 { SECTION, KEY, NULL, TESTFILE, -1, 4294967295U, 4294967295U}, 56 { SECTION, KEY, NULL, TESTFILE, 1, 1 , 1}, 57 { SECTION, KEY, "-1", TESTFILE, -1, 4294967295U, 4294967295U}, 58 { SECTION, KEY, "-1", TESTFILE, 1, 4294967295U, 4294967295U}, /* 10 */ 59 { SECTION, KEY, "1", TESTFILE, -1, 1 , 1}, 60 { SECTION, KEY, "1", TESTFILE, 1, 1 , 1}, 61 { SECTION, KEY, "+1", TESTFILE, -1, 1 , 0}, 62 { SECTION, KEY, "+1", TESTFILE, 1, 1 , 0}, 63 { SECTION, KEY, "4294967296", TESTFILE, -1, 0 , 0}, /* 15 */ 64 { SECTION, KEY, "4294967296", TESTFILE, 1, 0 , 0}, 65 { SECTION, KEY, "4294967297", TESTFILE, -1, 1 , 1}, 66 { SECTION, KEY, "4294967297", TESTFILE, 1, 1 , 1}, 67 { SECTION, KEY, "-4294967297", TESTFILE, -1, 4294967295U, 4294967295U}, 68 { SECTION, KEY, "-4294967297", TESTFILE, 1, 4294967295U, 4294967295U}, /* 20 */ 69 { SECTION, KEY, "42A94967297", TESTFILE, -1, 42 , 42}, 70 { SECTION, KEY, "42A94967297", TESTFILE, 1, 42 , 42}, 71 { SECTION, KEY, "B4294967297", TESTFILE, -1, 0 , 0}, 72 { SECTION, KEY, "B4294967297", TESTFILE, 1, 0 , 0}, 73 }; 74 int i, num_test = (sizeof(profileInt)/sizeof(struct _profileInt)); 75 UINT res; 76 77 DeleteFileA( TESTFILE); 78 79 for (i=0; i < num_test; i++) { 80 if (profileInt[i].value) 81 WritePrivateProfileStringA(SECTION, KEY, profileInt[i].value, 82 profileInt[i].iniFile); 83 84 res = GetPrivateProfileIntA(profileInt[i].section, profileInt[i].key, 85 profileInt[i].defaultVal, profileInt[i].iniFile); 86 ok((res == profileInt[i].result) || (res == profileInt[i].result9x), 87 "test<%02d>: ret<%010u> exp<%010u><%010u>\n", 88 i, res, profileInt[i].result, profileInt[i].result9x); 89 } 90 91 DeleteFileA( TESTFILE); 92 } 93 94 static void test_profile_string(void) 95 { 96 static WCHAR emptyW[] = { 0 }; /* if "const", GetPrivateProfileStringW(emptyW, ...) crashes on win2k */ 97 static const WCHAR keyW[] = { 'k','e','y',0 }; 98 static const WCHAR sW[] = { 's',0 }; 99 static const WCHAR TESTFILE2W[] = {'.','\\','t','e','s','t','w','i','n','e','2','.','i','n','i',0}; 100 static const WCHAR valsectionW[] = {'v','a','l','_','e','_','s','e','c','t','i','o','n',0 }; 101 static const WCHAR valnokeyW[] = {'v','a','l','_','n','o','_','k','e','y',0}; 102 HANDLE h; 103 int ret; 104 DWORD count; 105 char buf[100]; 106 WCHAR bufW[100]; 107 char *p; 108 /* test that lines without an '=' will not be enumerated */ 109 /* in the case below, name2 is a key while name3 is not. */ 110 char content[]="[s]\r\nname1=val1\r\nname2=\r\nname3\r\nname4=val4\r\n"; 111 char content2[]="\r\nkey=val_no_section\r\n[]\r\nkey=val_e_section\r\n" 112 "[s]\r\n=val_no_key\r\n[t]\r\n"; 113 DeleteFileA( TESTFILE2); 114 h = CreateFileA( TESTFILE2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 115 FILE_ATTRIBUTE_NORMAL, NULL); 116 ok( h != INVALID_HANDLE_VALUE, " cannot create %s\n", TESTFILE2); 117 if( h == INVALID_HANDLE_VALUE) return; 118 WriteFile( h, content, sizeof(content), &count, NULL); 119 CloseHandle( h); 120 121 /* enumerate the keys */ 122 ret=GetPrivateProfileStringA( "s", NULL, "", buf, sizeof(buf), 123 TESTFILE2); 124 for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1) 125 p[-1] = ','; 126 /* and test */ 127 ok( ret == 18 && !strcmp( buf, "name1,name2,name4"), "wrong keys returned(%d): %s\n", ret, 128 buf); 129 130 /* add a new key to test that the file is quite usable */ 131 WritePrivateProfileStringA( "s", "name5", "val5", TESTFILE2); 132 ret=GetPrivateProfileStringA( "s", NULL, "", buf, sizeof(buf), 133 TESTFILE2); 134 for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1) 135 p[-1] = ','; 136 ok( ret == 24 && !strcmp( buf, "name1,name2,name4,name5"), "wrong keys returned(%d): %s\n", 137 ret, buf); 138 139 h = CreateFileA( TESTFILE2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 140 FILE_ATTRIBUTE_NORMAL, NULL); 141 ok( h != INVALID_HANDLE_VALUE, " cannot create %s\n", TESTFILE2); 142 if( h == INVALID_HANDLE_VALUE) return; 143 WriteFile( h, content2, sizeof(content2), &count, NULL); 144 CloseHandle( h); 145 146 /* works only in unicode, ascii crashes */ 147 ret=GetPrivateProfileStringW(emptyW, keyW, emptyW, bufW, 148 sizeof(bufW)/sizeof(bufW[0]), TESTFILE2W); 149 todo_wine 150 ok(ret == 13, "expected 13, got %u\n", ret); 151 todo_wine 152 ok(!lstrcmpW(valsectionW,bufW), "expected %s, got %s\n", 153 wine_dbgstr_w(valsectionW), wine_dbgstr_w(bufW) ); 154 155 /* works only in unicode, ascii crashes */ 156 ret=GetPrivateProfileStringW(sW, emptyW, emptyW, bufW, 157 sizeof(bufW)/sizeof(bufW[0]), TESTFILE2W); 158 ok(ret == 10, "expected 10, got %u\n", ret); 159 ok(!lstrcmpW(valnokeyW,bufW), "expected %s, got %s\n", 160 wine_dbgstr_w(valnokeyW), wine_dbgstr_w(bufW) ); 161 162 DeleteFileA( TESTFILE2); 163 } 164 165 static void test_profile_sections(void) 166 { 167 HANDLE h; 168 int ret; 169 DWORD count; 170 char buf[100]; 171 char *p; 172 static const char content[]="[section1]\r\nname1=val1\r\nname2=\r\nname3\r\nname4=val4\r\n[section2]\r\n"; 173 static const char testfile4[]=".\\testwine4.ini"; 174 BOOL on_win98 = FALSE; 175 176 DeleteFileA( testfile4 ); 177 h = CreateFileA( testfile4, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 178 ok( h != INVALID_HANDLE_VALUE, " cannot create %s\n", testfile4); 179 if( h == INVALID_HANDLE_VALUE) return; 180 WriteFile( h, content, sizeof(content), &count, NULL); 181 CloseHandle( h); 182 183 /* Some parameter checking */ 184 SetLastError(0xdeadbeef); 185 ret = GetPrivateProfileSectionA( NULL, NULL, 0, NULL ); 186 ok( ret == 0, "expected return size 0, got %d\n", ret ); 187 ok( GetLastError() == ERROR_INVALID_PARAMETER || 188 GetLastError() == 0xdeadbeef /* Win98 */, 189 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); 190 if (GetLastError() == 0xdeadbeef) on_win98 = TRUE; 191 192 SetLastError(0xdeadbeef); 193 ret = GetPrivateProfileSectionA( NULL, NULL, 0, testfile4 ); 194 ok( ret == 0, "expected return size 0, got %d\n", ret ); 195 ok( GetLastError() == ERROR_INVALID_PARAMETER || 196 GetLastError() == 0xdeadbeef /* Win98 */, 197 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); 198 199 if (!on_win98) 200 { 201 SetLastError(0xdeadbeef); 202 ret = GetPrivateProfileSectionA( "section1", NULL, 0, testfile4 ); 203 ok( ret == 0, "expected return size 0, got %d\n", ret ); 204 ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); 205 } 206 207 SetLastError(0xdeadbeef); 208 ret = GetPrivateProfileSectionA( NULL, buf, sizeof(buf), testfile4 ); 209 ok( ret == 0, "expected return size 0, got %d\n", ret ); 210 ok( GetLastError() == ERROR_INVALID_PARAMETER || 211 broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ 212 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); 213 214 SetLastError(0xdeadbeef); 215 ret = GetPrivateProfileSectionA( "section1", buf, sizeof(buf), NULL ); 216 ok( ret == 0, "expected return size 0, got %d\n", ret ); 217 todo_wine 218 ok( GetLastError() == ERROR_FILE_NOT_FOUND || 219 broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ 220 "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 221 222 /* Existing empty section with no keys */ 223 SetLastError(0xdeadbeef); 224 ret=GetPrivateProfileSectionA("section2", buf, sizeof(buf), testfile4); 225 ok( ret == 0, "expected return size 0, got %d\n", ret ); 226 ok( GetLastError() == ERROR_SUCCESS || 227 broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ 228 "expected ERROR_SUCCESS, got %d\n", GetLastError()); 229 230 /* Existing section with keys and values*/ 231 SetLastError(0xdeadbeef); 232 ret=GetPrivateProfileSectionA("section1", buf, sizeof(buf), testfile4); 233 for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1) 234 p[-1] = ','; 235 ok( ret == 35 && !strcmp( buf, "name1=val1,name2=,name3,name4=val4"), "wrong section returned(%d): %s\n", 236 ret, buf); 237 ok( buf[ret-1] == 0 && buf[ret] == 0, "returned buffer not terminated with double-null\n" ); 238 ok( GetLastError() == ERROR_SUCCESS || 239 broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ 240 "expected ERROR_SUCCESS, got %d\n", GetLastError()); 241 242 /* Overflow*/ 243 ret=GetPrivateProfileSectionA("section1", buf, 24, testfile4); 244 for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1) 245 p[-1] = ','; 246 ok( ret == 22 && !strcmp( buf, "name1=val1,name2=,name"), "wrong section returned(%d): %s\n", 247 ret, buf); 248 ok( buf[ret] == 0 && buf[ret+1] == 0, "returned buffer not terminated with double-null\n" ); 249 250 DeleteFileA( testfile4 ); 251 } 252 253 static void test_profile_sections_names(void) 254 { 255 HANDLE h; 256 int ret; 257 DWORD count; 258 char buf[100]; 259 WCHAR bufW[100]; 260 static const char content[]="[section1]\r\n[section2]\r\n[section3]\r\n"; 261 static const char testfile3[]=".\\testwine3.ini"; 262 static const WCHAR testfile3W[]={ '.','\\','t','e','s','t','w','i','n','e','3','.','i','n','i',0 }; 263 static const WCHAR not_here[] = {'.','\\','n','o','t','_','h','e','r','e','.','i','n','i',0}; 264 DeleteFileA( testfile3 ); 265 h = CreateFileA( testfile3, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 266 FILE_ATTRIBUTE_NORMAL, NULL); 267 ok( h != INVALID_HANDLE_VALUE, " cannot create %s\n", testfile3); 268 if( h == INVALID_HANDLE_VALUE) return; 269 WriteFile( h, content, sizeof(content), &count, NULL); 270 CloseHandle( h); 271 272 /* Test with sufficiently large buffer */ 273 memset(buf, 0xc, sizeof(buf)); 274 ret = GetPrivateProfileSectionNamesA( buf, 29, testfile3 ); 275 ok( ret == 27 || 276 broken(ret == 28), /* Win9x, WinME */ 277 "expected return size 27, got %d\n", ret ); 278 ok( (buf[ret-1] == 0 && buf[ret] == 0) || 279 broken(buf[ret-1] == 0 && buf[ret-2] == 0), /* Win9x, WinME */ 280 "returned buffer not terminated with double-null\n" ); 281 282 /* Test with exactly fitting buffer */ 283 memset(buf, 0xc, sizeof(buf)); 284 ret = GetPrivateProfileSectionNamesA( buf, 28, testfile3 ); 285 ok( ret == 26 || 286 broken(ret == 28), /* Win9x, WinME */ 287 "expected return size 26, got %d\n", ret ); 288 todo_wine 289 ok( (buf[ret+1] == 0 && buf[ret] == 0) || /* W2K3 and higher */ 290 broken(buf[ret+1] == 0xc && buf[ret] == 0) || /* NT4, W2K, WinXP */ 291 broken(buf[ret-1] == 0 && buf[ret-2] == 0), /* Win9x, WinME */ 292 "returned buffer not terminated with double-null\n" ); 293 294 /* Test with a buffer too small */ 295 memset(buf, 0xc, sizeof(buf)); 296 ret = GetPrivateProfileSectionNamesA( buf, 27, testfile3 ); 297 ok( ret == 25, "expected return size 25, got %d\n", ret ); 298 /* Win9x and WinME only fills the buffer with complete section names (double-null terminated) */ 299 count = strlen("section1") + sizeof(CHAR) + strlen("section2"); 300 todo_wine 301 ok( (buf[ret+1] == 0 && buf[ret] == 0) || 302 broken(buf[count] == 0 && buf[count+1] == 0), /* Win9x, WinME */ 303 "returned buffer not terminated with double-null\n" ); 304 305 /* Tests on nonexistent file */ 306 memset(buf, 0xc, sizeof(buf)); 307 ret = GetPrivateProfileSectionNamesA( buf, 10, ".\\not_here.ini" ); 308 ok( ret == 0 || 309 broken(ret == 1), /* Win9x, WinME */ 310 "expected return size 0, got %d\n", ret ); 311 ok( buf[0] == 0, "returned buffer not terminated with null\n" ); 312 ok( buf[1] != 0, "returned buffer terminated with double-null\n" ); 313 314 /* Test with sufficiently large buffer */ 315 SetLastError(0xdeadbeef); 316 memset(bufW, 0xcc, sizeof(bufW)); 317 ret = GetPrivateProfileSectionNamesW( bufW, 29, testfile3W ); 318 if (ret == 0 && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) 319 { 320 win_skip("GetPrivateProfileSectionNamesW is not implemented\n"); 321 DeleteFileA( testfile3 ); 322 return; 323 } 324 ok( ret == 27, "expected return size 27, got %d\n", ret ); 325 ok( bufW[ret-1] == 0 && bufW[ret] == 0, "returned buffer not terminated with double-null\n" ); 326 327 /* Test with exactly fitting buffer */ 328 memset(bufW, 0xcc, sizeof(bufW)); 329 ret = GetPrivateProfileSectionNamesW( bufW, 28, testfile3W ); 330 ok( ret == 26, "expected return size 26, got %d\n", ret ); 331 ok( (bufW[ret+1] == 0 && bufW[ret] == 0) || /* W2K3 and higher */ 332 broken(bufW[ret+1] == 0xcccc && bufW[ret] == 0), /* NT4, W2K, WinXP */ 333 "returned buffer not terminated with double-null\n" ); 334 335 /* Test with a buffer too small */ 336 memset(bufW, 0xcc, sizeof(bufW)); 337 ret = GetPrivateProfileSectionNamesW( bufW, 27, testfile3W ); 338 ok( ret == 25, "expected return size 25, got %d\n", ret ); 339 ok( bufW[ret+1] == 0 && bufW[ret] == 0, "returned buffer not terminated with double-null\n" ); 340 341 DeleteFileA( testfile3 ); 342 343 /* Tests on nonexistent file */ 344 memset(bufW, 0xcc, sizeof(bufW)); 345 ret = GetPrivateProfileSectionNamesW( bufW, 10, not_here ); 346 ok( ret == 0, "expected return size 0, got %d\n", ret ); 347 ok( bufW[0] == 0, "returned buffer not terminated with null\n" ); 348 ok( bufW[1] != 0, "returned buffer terminated with double-null\n" ); 349 } 350 351 /* If the ini-file has already been opened with CreateFile, WritePrivateProfileString failed in wine with an error ERROR_SHARING_VIOLATION, some testing here */ 352 static void test_profile_existing(void) 353 { 354 static const char *testfile1 = ".\\winesharing1.ini"; 355 static const char *testfile2 = ".\\winesharing2.ini"; 356 357 static const struct { 358 DWORD dwDesiredAccess; 359 DWORD dwShareMode; 360 DWORD write_error; 361 BOOL read_error; 362 DWORD broken_error; 363 } pe[] = { 364 {GENERIC_READ, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE }, 365 {GENERIC_READ, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE }, 366 {GENERIC_WRITE, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE }, 367 {GENERIC_WRITE, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE }, 368 {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE }, 369 {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE }, 370 {GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */}, 371 {GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */}, 372 /*Thief demo (bug 5024) opens .ini file like this*/ 373 {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */} 374 }; 375 376 int i; 377 BOOL ret; 378 DWORD size; 379 HANDLE h = 0; 380 char buffer[MAX_PATH]; 381 382 for (i=0; i < sizeof(pe)/sizeof(pe[0]); i++) 383 { 384 h = CreateFileA(testfile1, pe[i].dwDesiredAccess, pe[i].dwShareMode, NULL, 385 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 386 ok(INVALID_HANDLE_VALUE != h, "%d: CreateFile failed\n",i); 387 SetLastError(0xdeadbeef); 388 389 ret = WritePrivateProfileStringA(SECTION, KEY, "12345", testfile1); 390 if (!pe[i].write_error) 391 { 392 if (!ret) 393 ok( broken(GetLastError() == pe[i].broken_error), 394 "%d: WritePrivateProfileString failed with error %u\n", i, GetLastError() ); 395 CloseHandle(h); 396 size = GetPrivateProfileStringA(SECTION, KEY, 0, buffer, MAX_PATH, testfile1); 397 if (ret) 398 ok( size == 5, "%d: test failed, number of characters copied: %d instead of 5\n", i, size ); 399 else 400 ok( !size, "%d: test failed, number of characters copied: %d instead of 0\n", i, size ); 401 } 402 else 403 { 404 DWORD err = GetLastError(); 405 ok( !ret, "%d: WritePrivateProfileString succeeded\n", i ); 406 if (!ret) 407 ok( err == pe[i].write_error, "%d: WritePrivateProfileString failed with error %u/%u\n", 408 i, err, pe[i].write_error ); 409 CloseHandle(h); 410 size = GetPrivateProfileStringA(SECTION, KEY, 0, buffer, MAX_PATH, testfile1); 411 ok( !size, "%d: test failed, number of characters copied: %d instead of 0\n", i, size ); 412 } 413 414 ok( DeleteFileA(testfile1), "delete failed\n" ); 415 } 416 417 h = CreateFileA(testfile2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 418 sprintf( buffer, "[%s]\r\n%s=123\r\n", SECTION, KEY ); 419 ok( WriteFile( h, buffer, strlen(buffer), &size, NULL ), "failed to write\n" ); 420 CloseHandle( h ); 421 422 for (i=0; i < sizeof(pe)/sizeof(pe[0]); i++) 423 { 424 h = CreateFileA(testfile2, pe[i].dwDesiredAccess, pe[i].dwShareMode, NULL, 425 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 426 ok(INVALID_HANDLE_VALUE != h, "%d: CreateFile failed\n",i); 427 SetLastError(0xdeadbeef); 428 ret = GetPrivateProfileStringA(SECTION, KEY, NULL, buffer, MAX_PATH, testfile2); 429 /* Win9x and WinME returns 0 for all cases except the first one */ 430 if (!pe[i].read_error) 431 ok( ret || 432 broken(!ret && GetLastError() == 0xdeadbeef), /* Win9x, WinME */ 433 "%d: GetPrivateProfileString failed with error %u\n", i, GetLastError() ); 434 else 435 ok( !ret, "%d: GetPrivateProfileString succeeded\n", i ); 436 CloseHandle(h); 437 } 438 ok( DeleteFileA(testfile2), "delete failed\n" ); 439 } 440 441 static void test_profile_delete_on_close(void) 442 { 443 HANDLE h; 444 DWORD size, res; 445 static const CHAR testfile[] = ".\\testwine5.ini"; 446 static const char contents[] = "[" SECTION "]\n" KEY "=123\n"; 447 448 h = CreateFileA(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, 449 CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); 450 res = WriteFile( h, contents, sizeof contents - 1, &size, NULL ); 451 ok( res, "Cannot write test file: %x\n", GetLastError() ); 452 ok( size == sizeof contents - 1, "Test file: partial write\n"); 453 454 SetLastError(0xdeadbeef); 455 res = GetPrivateProfileIntA(SECTION, KEY, 0, testfile); 456 ok( res == 123 || 457 broken(res == 0 && GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x, WinME */ 458 "Got %d instead of 123\n", res); 459 460 /* This also deletes the file */ 461 CloseHandle(h); 462 } 463 464 static void test_profile_refresh(void) 465 { 466 static const CHAR testfile[] = ".\\winetest4.ini"; 467 HANDLE h; 468 DWORD size, res; 469 static const char contents1[] = "[" SECTION "]\n" KEY "=123\n"; 470 static const char contents2[] = "[" SECTION "]\n" KEY "=124\n"; 471 472 h = CreateFileA(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, 473 CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); 474 res = WriteFile( h, contents1, sizeof contents1 - 1, &size, NULL ); 475 ok( res, "Cannot write test file: %x\n", GetLastError() ); 476 ok( size == sizeof contents1 - 1, "Test file: partial write\n"); 477 478 SetLastError(0xdeadbeef); 479 res = GetPrivateProfileIntA(SECTION, KEY, 0, testfile); 480 ok( res == 123 || 481 broken(res == 0 && GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x, WinME */ 482 "Got %d instead of 123\n", res); 483 484 CloseHandle(h); 485 486 /* Test proper invalidation of wine's profile file cache */ 487 488 h = CreateFileA(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, 489 CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); 490 res = WriteFile( h, contents2, sizeof contents2 - 1, &size, NULL ); 491 ok( res, "Cannot write test file: %x\n", GetLastError() ); 492 ok( size == sizeof contents2 - 1, "Test file: partial write\n"); 493 494 SetLastError(0xdeadbeef); 495 res = GetPrivateProfileIntA(SECTION, KEY, 0, testfile); 496 ok( res == 124 || 497 broken(res == 0 && GetLastError() == 0xdeadbeef), /* Win9x, WinME */ 498 "Got %d instead of 124\n", res); 499 500 /* This also deletes the file */ 501 CloseHandle(h); 502 503 /* Cache must be invalidated if file no longer exists and default must be returned */ 504 SetLastError(0xdeadbeef); 505 res = GetPrivateProfileIntA(SECTION, KEY, 421, testfile); 506 ok( res == 421 || 507 broken(res == 0 && GetLastError() == 0xdeadbeef), /* Win9x, WinME */ 508 "Got %d instead of 421\n", res); 509 } 510 511 static 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 522 static 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 536 static 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: %d\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: %d\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: %d\n", GetLastError()); 569 } 570 571 static void test_GetPrivateProfileString(const char *content, const char *descript) 572 { 573 DWORD ret, len; 574 CHAR buf[MAX_PATH]; 575 CHAR def_val[MAX_PATH]; 576 CHAR path[MAX_PATH]; 577 CHAR windir[MAX_PATH]; 578 /* NT series crashes on r/o empty strings, so pass an r/w 579 empty string and check for modification */ 580 CHAR emptystr[MAX_PATH] = ""; 581 LPSTR tempfile; 582 583 static const char filename[] = ".\\winetest.ini"; 584 585 trace("test_GetPrivateProfileStringA: %s\n", descript); 586 587 if(!lstrcmpA(descript, "CR only")) 588 { 589 SetLastError(0xdeadbeef); 590 ret = GetPrivateProfileStringW(NULL, NULL, NULL, 591 NULL, 0, NULL); 592 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 593 { 594 win_skip("Win9x and WinME don't handle 'CR only' correctly\n"); 595 return; 596 } 597 } 598 599 create_test_file(filename, content, lstrlenA(content)); 600 601 /* Run this test series with caching. Wine won't cache profile 602 files younger than 2.1 seconds. */ 603 Sleep(2500); 604 605 /* lpAppName is NULL */ 606 memset(buf, 0xc, sizeof(buf)); 607 lstrcpyA(buf, "kumquat"); 608 ret = GetPrivateProfileStringA(NULL, "name1", "default", 609 buf, MAX_PATH, filename); 610 ok(ret == 18 || 611 broken(ret == 19), /* Win9x and WinME */ 612 "Expected 18, got %d\n", ret); 613 len = lstrlenA("section1") + sizeof(CHAR) + lstrlenA("section2") + 2 * sizeof(CHAR); 614 ok(!memcmp(buf, "section1\0section2\0\0", len), 615 "Expected \"section1\\0section2\\0\\0\", got \"%s\"\n", buf); 616 617 /* lpAppName is empty */ 618 memset(buf, 0xc, sizeof(buf)); 619 lstrcpyA(buf, "kumquat"); 620 ret = GetPrivateProfileStringA(emptystr, "name1", "default", 621 buf, MAX_PATH, filename); 622 ok(ret == 7, "Expected 7, got %d\n", ret); 623 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); 624 ok(emptystr_ok(emptystr), "AppName modified\n"); 625 626 /* lpAppName is missing */ 627 memset(buf, 0xc,sizeof(buf)); 628 lstrcpyA(buf, "kumquat"); 629 ret = GetPrivateProfileStringA("notasection", "name1", "default", 630 buf, MAX_PATH, filename); 631 ok(ret == 7, "Expected 7, got %d\n", ret); 632 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); 633 634 /* lpAppName is empty, lpDefault is NULL */ 635 memset(buf, 0xc,sizeof(buf)); 636 lstrcpyA(buf, "kumquat"); 637 ret = GetPrivateProfileStringA(emptystr, "name1", NULL, 638 buf, MAX_PATH, filename); 639 ok(ret == 0, "Expected 0, got %d\n", ret); 640 ok(!lstrcmpA(buf, "") || 641 broken(!lstrcmpA(buf, "kumquat")), /* Win9x, WinME */ 642 "Expected \"\", got \"%s\"\n", buf); 643 ok(emptystr_ok(emptystr), "AppName modified\n"); 644 645 /* lpAppName is empty, lpDefault is empty */ 646 memset(buf, 0xc,sizeof(buf)); 647 lstrcpyA(buf, "kumquat"); 648 ret = GetPrivateProfileStringA(emptystr, "name1", "", 649 buf, MAX_PATH, filename); 650 ok(ret == 0, "Expected 0, got %d\n", ret); 651 ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); 652 ok(emptystr_ok(emptystr), "AppName modified\n"); 653 654 /* lpAppName is empty, lpDefault has trailing blank characters */ 655 memset(buf, 0xc,sizeof(buf)); 656 lstrcpyA(buf, "kumquat"); 657 /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */ 658 lstrcpyA(def_val, "default "); 659 ret = GetPrivateProfileStringA(emptystr, "name1", def_val, 660 buf, MAX_PATH, filename); 661 ok(ret == 7, "Expected 7, got %d\n", ret); 662 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); 663 ok(emptystr_ok(emptystr), "AppName modified\n"); 664 665 /* lpAppName is empty, many blank characters in lpDefault */ 666 memset(buf, 0xc,sizeof(buf)); 667 lstrcpyA(buf, "kumquat"); 668 /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */ 669 lstrcpyA(def_val, "one two "); 670 ret = GetPrivateProfileStringA(emptystr, "name1", def_val, 671 buf, MAX_PATH, filename); 672 ok(ret == 7, "Expected 7, got %d\n", ret); 673 ok(!lstrcmpA(buf, "one two"), "Expected \"one two\", got \"%s\"\n", buf); 674 ok(emptystr_ok(emptystr), "AppName modified\n"); 675 676 /* lpAppName is empty, blank character but not trailing in lpDefault */ 677 memset(buf, 0xc,sizeof(buf)); 678 lstrcpyA(buf, "kumquat"); 679 ret = GetPrivateProfileStringA(emptystr, "name1", "one two", 680 buf, MAX_PATH, filename); 681 ok(ret == 7, "Expected 7, got %d\n", ret); 682 ok(!lstrcmpA(buf, "one two"), "Expected \"one two\", got \"%s\"\n", buf); 683 ok(emptystr_ok(emptystr), "AppName modified\n"); 684 685 /* lpKeyName is NULL */ 686 memset(buf, 0xc,sizeof(buf)); 687 lstrcpyA(buf, "kumquat"); 688 ret = GetPrivateProfileStringA("section1", NULL, "default", 689 buf, MAX_PATH, filename); 690 ok(ret == 18, "Expected 18, got %d\n", ret); 691 ok(!memcmp(buf, "name1\0name2\0name4\0", ret + 1), 692 "Expected \"name1\\0name2\\0name4\\0\", got \"%s\"\n", buf); 693 694 /* lpKeyName is empty */ 695 memset(buf, 0xc,sizeof(buf)); 696 lstrcpyA(buf, "kumquat"); 697 ret = GetPrivateProfileStringA("section1", emptystr, "default", 698 buf, MAX_PATH, filename); 699 ok(ret == 7, "Expected 7, got %d\n", ret); 700 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); 701 ok(emptystr_ok(emptystr), "KeyName modified\n"); 702 703 /* lpKeyName is missing */ 704 memset(buf, 0xc,sizeof(buf)); 705 lstrcpyA(buf, "kumquat"); 706 ret = GetPrivateProfileStringA("section1", "notakey", "default", 707 buf, MAX_PATH, filename); 708 ok(ret == 7, "Expected 7, got %d\n", ret); 709 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); 710 711 /* lpKeyName is empty, lpDefault is NULL */ 712 memset(buf, 0xc,sizeof(buf)); 713 lstrcpyA(buf, "kumquat"); 714 ret = GetPrivateProfileStringA("section1", emptystr, NULL, 715 buf, MAX_PATH, filename); 716 ok(ret == 0, "Expected 0, got %d\n", ret); 717 ok(!lstrcmpA(buf, "") || 718 broken(!lstrcmpA(buf, "kumquat")), /* Win9x, WinME */ 719 "Expected \"\", got \"%s\"\n", buf); 720 ok(emptystr_ok(emptystr), "KeyName modified\n"); 721 722 /* lpKeyName is empty, lpDefault is empty */ 723 memset(buf, 0xc,sizeof(buf)); 724 lstrcpyA(buf, "kumquat"); 725 ret = GetPrivateProfileStringA("section1", emptystr, "", 726 buf, MAX_PATH, filename); 727 ok(ret == 0, "Expected 0, got %d\n", ret); 728 ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); 729 ok(emptystr_ok(emptystr), "KeyName modified\n"); 730 731 /* lpKeyName is empty, lpDefault has trailing blank characters */ 732 memset(buf, 0xc,sizeof(buf)); 733 lstrcpyA(buf, "kumquat"); 734 /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */ 735 lstrcpyA(def_val, "default "); 736 ret = GetPrivateProfileStringA("section1", emptystr, def_val, 737 buf, MAX_PATH, filename); 738 ok(ret == 7, "Expected 7, got %d\n", ret); 739 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); 740 ok(emptystr_ok(emptystr), "KeyName modified\n"); 741 742 if (0) /* crashes */ 743 { 744 /* lpReturnedString is NULL */ 745 ret = GetPrivateProfileStringA("section1", "name1", "default", 746 NULL, MAX_PATH, filename); 747 } 748 749 /* lpFileName is NULL */ 750 memset(buf, 0xc,sizeof(buf)); 751 lstrcpyA(buf, "kumquat"); 752 ret = GetPrivateProfileStringA("section1", "name1", "default", 753 buf, MAX_PATH, NULL); 754 ok(ret == 7 || 755 broken(ret == 0), /* Win9x, WinME */ 756 "Expected 7, got %d\n", ret); 757 ok(!lstrcmpA(buf, "default") || 758 broken(!lstrcmpA(buf, "kumquat")), /* Win9x, WinME */ 759 "Expected \"default\", got \"%s\"\n", buf); 760 761 /* lpFileName is empty */ 762 memset(buf, 0xc,sizeof(buf)); 763 lstrcpyA(buf, "kumquat"); 764 ret = GetPrivateProfileStringA("section1", "name1", "default", 765 buf, MAX_PATH, ""); 766 ok(ret == 7, "Expected 7, got %d\n", ret); 767 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); 768 769 /* lpFileName is nonexistent */ 770 memset(buf, 0xc,sizeof(buf)); 771 lstrcpyA(buf, "kumquat"); 772 ret = GetPrivateProfileStringA("section1", "name1", "default", 773 buf, MAX_PATH, "nonexistent"); 774 ok(ret == 7, "Expected 7, got %d\n", ret); 775 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); 776 777 /* nSize is 0 */ 778 memset(buf, 0xc,sizeof(buf)); 779 lstrcpyA(buf, "kumquat"); 780 ret = GetPrivateProfileStringA("section1", "name1", "default", 781 buf, 0, filename); 782 ok(ret == 0, "Expected 0, got %d\n", ret); 783 ok(!lstrcmpA(buf, "kumquat"), "Expected buf to be unchanged, got \"%s\"\n", buf); 784 785 /* nSize is exact size of output */ 786 memset(buf, 0xc,sizeof(buf)); 787 lstrcpyA(buf, "kumquat"); 788 ret = GetPrivateProfileStringA("section1", "name1", "default", 789 buf, 4, filename); 790 ok(ret == 3, "Expected 3, got %d\n", ret); 791 ok(!lstrcmpA(buf, "val"), "Expected \"val\", got \"%s\"\n", buf); 792 793 /* nSize has room for NULL terminator */ 794 memset(buf, 0xc,sizeof(buf)); 795 lstrcpyA(buf, "kumquat"); 796 ret = GetPrivateProfileStringA("section1", "name1", "default", 797 buf, 5, filename); 798 ok(ret == 4, "Expected 4, got %d\n", ret); 799 ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); 800 801 /* output is 1 character */ 802 memset(buf, 0xc,sizeof(buf)); 803 lstrcpyA(buf, "kumquat"); 804 ret = GetPrivateProfileStringA("section1", "name4", "default", 805 buf, MAX_PATH, filename); 806 ok(ret == 1, "Expected 1, got %d\n", ret); 807 ok(!lstrcmpA(buf, "a"), "Expected \"a\", got \"%s\"\n", buf); 808 809 /* output is 1 character, no room for NULL terminator */ 810 memset(buf, 0xc,sizeof(buf)); 811 lstrcpyA(buf, "kumquat"); 812 ret = GetPrivateProfileStringA("section1", "name4", "default", 813 buf, 1, filename); 814 ok(ret == 0, "Expected 0, got %d\n", ret); 815 ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); 816 817 /* lpAppName is NULL, not enough room for final section name */ 818 memset(buf, 0xc,sizeof(buf)); 819 lstrcpyA(buf, "kumquat"); 820 ret = GetPrivateProfileStringA(NULL, "name1", "default", 821 buf, 16, filename); 822 ok(ret == 14, "Expected 14, got %d\n", ret); 823 len = lstrlenA("section1") + 2 * sizeof(CHAR); 824 todo_wine 825 ok(!memcmp(buf, "section1\0secti\0\0", ret + 2) || 826 broken(!memcmp(buf, "section1\0\0", len)), /* Win9x, WinME */ 827 "Expected \"section1\\0secti\\0\\0\", got \"%s\"\n", buf); 828 829 /* lpKeyName is NULL, not enough room for final key name */ 830 memset(buf, 0xc,sizeof(buf)); 831 lstrcpyA(buf, "kumquat"); 832 ret = GetPrivateProfileStringA("section1", NULL, "default", 833 buf, 16, filename); 834 ok(ret == 14, "Expected 14, got %d\n", ret); 835 todo_wine 836 ok(!memcmp(buf, "name1\0name2\0na\0\0", ret + 2) || 837 broken(!memcmp(buf, "name1\0name2\0n\0\0", ret + 1)), /* Win9x, WinME */ 838 "Expected \"name1\\0name2\\0na\\0\\0\", got \"%s\"\n", buf); 839 840 /* key value has quotation marks which are stripped */ 841 memset(buf, 0xc,sizeof(buf)); 842 lstrcpyA(buf, "kumquat"); 843 ret = GetPrivateProfileStringA("section1", "name2", "default", 844 buf, MAX_PATH, filename); 845 ok(ret == 4, "Expected 4, got %d\n", ret); 846 ok(!lstrcmpA(buf, "val2"), "Expected \"val2\", got \"%s\"\n", buf); 847 848 /* case does not match */ 849 memset(buf, 0xc,sizeof(buf)); 850 lstrcpyA(buf, "kumquat"); 851 ret = GetPrivateProfileStringA("section1", "NaMe1", "default", 852 buf, MAX_PATH, filename); 853 ok(ret == 4, "Expected 4, got %d\n", ret); 854 ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); 855 856 /* only filename is used */ 857 memset(buf, 0xc,sizeof(buf)); 858 lstrcpyA(buf, "kumquat"); 859 ret = GetPrivateProfileStringA("section1", "NaMe1", "default", 860 buf, MAX_PATH, "winetest.ini"); 861 ok(ret == 7, "Expected 7, got %d\n", ret); 862 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); 863 864 GetWindowsDirectoryA(windir, MAX_PATH); 865 SetLastError(0xdeadbeef); 866 ret = GetTempFileNameA(windir, "pre", 0, path); 867 if (!ret && GetLastError() == ERROR_ACCESS_DENIED) 868 { 869 skip("Not allowed to create a file in the Windows directory\n"); 870 DeleteFileA(filename); 871 return; 872 } 873 tempfile = strrchr(path, '\\') + 1; 874 create_test_file(path, content, lstrlenA(content)); 875 876 /* only filename is used, file exists in windows directory */ 877 memset(buf, 0xc,sizeof(buf)); 878 lstrcpyA(buf, "kumquat"); 879 ret = GetPrivateProfileStringA("section1", "NaMe1", "default", 880 buf, MAX_PATH, tempfile); 881 ok(ret == 4, "Expected 4, got %d\n", ret); 882 ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); 883 884 /* successful case */ 885 memset(buf, 0xc,sizeof(buf)); 886 lstrcpyA(buf, "kumquat"); 887 ret = GetPrivateProfileStringA("section1", "name1", "default", 888 buf, MAX_PATH, filename); 889 ok(ret == 4, "Expected 4, got %d\n", ret); 890 ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); 891 892 /* Existing section with no keys in an existing file */ 893 memset(buf, 0xc,sizeof(buf)); 894 SetLastError(0xdeadbeef); 895 ret=GetPrivateProfileStringA("section2", "DoesntExist", "", 896 buf, MAX_PATH, filename); 897 ok( ret == 0, "expected return size 0, got %d\n", ret ); 898 ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); 899 todo_wine 900 ok( GetLastError() == 0xdeadbeef || 901 GetLastError() == ERROR_FILE_NOT_FOUND /* Win 7 */, 902 "expected 0xdeadbeef or ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 903 904 905 DeleteFileA(path); 906 DeleteFileA(filename); 907 } 908 909 static BOOL check_binary_file_data(LPCSTR path, const VOID *data, DWORD size) 910 { 911 HANDLE file; 912 CHAR buf[MAX_PATH]; 913 BOOL ret; 914 915 file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); 916 if (file == INVALID_HANDLE_VALUE) 917 return FALSE; 918 919 if(size != GetFileSize(file, NULL) ) 920 { 921 CloseHandle(file); 922 return FALSE; 923 } 924 925 ret = ReadFile(file, buf, size, &size, NULL); 926 CloseHandle(file); 927 if (!ret) 928 return FALSE; 929 930 return !memcmp(buf, data, size); 931 } 932 933 static BOOL check_file_data(LPCSTR path, LPCSTR data) 934 { 935 return check_binary_file_data(path, data, lstrlenA(data)); 936 } 937 938 static void test_WritePrivateProfileString(void) 939 { 940 BOOL ret; 941 LPCSTR data; 942 CHAR path[MAX_PATH]; 943 CHAR temp[MAX_PATH]; 944 945 SetLastError(0xdeadbeef); 946 ret = WritePrivateProfileStringW(NULL, NULL, NULL, NULL); 947 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 948 { 949 /* Win9x/WinME needs (variable) timeouts between tests and even long timeouts don't 950 * guarantee a correct result. 951 * Win9x/WinMe also produces different ini files where there is always a newline before 952 * a section start (except for the first one). 953 */ 954 win_skip("WritePrivateProfileString on Win9x/WinME is hard to test reliably\n"); 955 return; 956 } 957 958 GetTempPathA(MAX_PATH, temp); 959 GetTempFileNameA(temp, "wine", 0, path); 960 DeleteFileA(path); 961 962 /* path is not created yet */ 963 964 /* NULL lpAppName */ 965 SetLastError(0xdeadbeef); 966 ret = WritePrivateProfileStringA(NULL, "key", "string", path); 967 ok(ret == FALSE, "Expected FALSE, got %d\n", ret); 968 ok(GetLastError() == ERROR_FILE_NOT_FOUND || 969 broken(GetLastError() == ERROR_INVALID_PARAMETER) || /* NT4 */ 970 broken(GetLastError() == 0xdeadbeef), /* Win9x and WinME */ 971 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 972 ok(GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES, 973 "Expected path to not exist\n"); 974 975 GetTempFileNameA(temp, "wine", 0, path); 976 977 /* NULL lpAppName, path exists */ 978 data = ""; 979 SetLastError(0xdeadbeef); 980 ret = WritePrivateProfileStringA(NULL, "key", "string", path); 981 ok(ret == FALSE, "Expected FALSE, got %d\n", ret); 982 ok(GetLastError() == ERROR_FILE_NOT_FOUND || 983 broken(GetLastError() == ERROR_INVALID_PARAMETER) || /* NT4 */ 984 broken(GetLastError() == 0xdeadbeef), /* Win9x and WinME */ 985 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 986 ok(check_file_data(path, data), "File doesn't match\n"); 987 DeleteFileA(path); 988 989 if (0) 990 { 991 /* empty lpAppName, crashes on NT4 and higher */ 992 data = "[]\r\n" 993 "key=string\r\n"; 994 ret = WritePrivateProfileStringA("", "key", "string", path); 995 ok(ret == TRUE, "Expected TRUE, got %d\n", ret); 996 ok(check_file_data(path, data), "File doesn't match\n"); 997 DeleteFileA(path); 998 } 999 1000 /* NULL lpKeyName */ 1001 data = ""; 1002 ret = WritePrivateProfileStringA("App", NULL, "string", path); 1003 ok(ret == TRUE, "Expected TRUE, got %d\n", ret); 1004 todo_wine 1005 { 1006 ok(check_file_data(path, data), "File doesn't match\n"); 1007 } 1008 DeleteFileA(path); 1009 1010 if (0) 1011 { 1012 /* empty lpKeyName, crashes on NT4 and higher */ 1013 data = "[App]\r\n" 1014 "=string\r\n"; 1015 ret = WritePrivateProfileStringA("App", "", "string", path); 1016 ok(ret == TRUE, "Expected TRUE, got %d\n", ret); 1017 todo_wine 1018 { 1019 ok(check_file_data(path, data), "File doesn't match\n"); 1020 } 1021 DeleteFileA(path); 1022 } 1023 1024 /* NULL lpString */ 1025 data = ""; 1026 ret = WritePrivateProfileStringA("App", "key", NULL, path); 1027 ok(ret == TRUE, "Expected TRUE, got %d\n", ret); 1028 todo_wine 1029 { 1030 ok(check_file_data(path, data) || 1031 (broken(GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES)), /* Win9x and WinME */ 1032 "File doesn't match\n"); 1033 } 1034 DeleteFileA(path); 1035 1036 /* empty lpString */ 1037 data = "[App]\r\n" 1038 "key=\r\n"; 1039 ret = WritePrivateProfileStringA("App", "key", "", path); 1040 ok(ret == TRUE || 1041 broken(!ret), /* Win9x and WinME */ 1042 "Expected TRUE, got %d\n", ret); 1043 ok(check_file_data(path, data) || 1044 (broken(GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES)), /* Win9x and WinME */ 1045 "File doesn't match\n"); 1046 DeleteFileA(path); 1047 1048 /* empty lpFileName */ 1049 SetLastError(0xdeadbeef); 1050 ret = WritePrivateProfileStringA("App", "key", "string", ""); 1051 ok(ret == FALSE, "Expected FALSE, got %d\n", ret); 1052 ok(GetLastError() == ERROR_ACCESS_DENIED || 1053 broken(GetLastError() == ERROR_PATH_NOT_FOUND), /* Win9x and WinME */ 1054 "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); 1055 1056 /* Relative paths are relative to X:\\%WINDIR% */ 1057 GetWindowsDirectoryA(temp, MAX_PATH); 1058 GetTempFileNameA(temp, "win", 1, path); 1059 if (GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES) 1060 skip("Not allowed to create a file in the Windows directory\n"); 1061 else 1062 { 1063 DeleteFileA(path); 1064 1065 data = "[App]\r\n" 1066 "key=string\r\n"; 1067 ret = WritePrivateProfileStringA("App", "key", "string", "win1.tmp"); 1068 ok(ret == TRUE, "Expected TRUE, got %d, le=%u\n", ret, GetLastError()); 1069 ok(check_file_data(path, data), "File doesn't match\n"); 1070 DeleteFileA(path); 1071 } 1072 1073 GetTempPathA(MAX_PATH, temp); 1074 GetTempFileNameA(temp, "wine", 0, path); 1075 1076 /* build up an INI file */ 1077 WritePrivateProfileStringA("App1", "key1", "string1", path); 1078 WritePrivateProfileStringA("App1", "key2", "string2", path); 1079 WritePrivateProfileStringA("App1", "key3", "string3", path); 1080 WritePrivateProfileStringA("App2", "key4", "string4", path); 1081 1082 /* make an addition and verify the INI */ 1083 data = "[App1]\r\n" 1084 "key1=string1\r\n" 1085 "key2=string2\r\n" 1086 "key3=string3\r\n" 1087 "[App2]\r\n" 1088 "key4=string4\r\n" 1089 "[App3]\r\n" 1090 "key5=string5\r\n"; 1091 ret = WritePrivateProfileStringA("App3", "key5", "string5", path); 1092 ok(ret == TRUE, "Expected TRUE, got %d\n", ret); 1093 ok(check_file_data(path, data), "File doesn't match\n"); 1094 1095 /* lpString is NULL, key2 key is deleted */ 1096 data = "[App1]\r\n" 1097 "key1=string1\r\n" 1098 "key3=string3\r\n" 1099 "[App2]\r\n" 1100 "key4=string4\r\n" 1101 "[App3]\r\n" 1102 "key5=string5\r\n"; 1103 ret = WritePrivateProfileStringA("App1", "key2", NULL, path); 1104 ok(ret == TRUE, "Expected TRUE, got %d\n", ret); 1105 ok(check_file_data(path, data), "File doesn't match\n"); 1106 1107 /* try to delete key2 again */ 1108 data = "[App1]\r\n" 1109 "key1=string1\r\n" 1110 "key3=string3\r\n" 1111 "[App2]\r\n" 1112 "key4=string4\r\n" 1113 "[App3]\r\n" 1114 "key5=string5\r\n"; 1115 ret = WritePrivateProfileStringA("App1", "key2", NULL, path); 1116 ok(ret == TRUE, "Expected TRUE, got %d\n", ret); 1117 ok(check_file_data(path, data), "File doesn't match\n"); 1118 1119 /* lpKeyName is NULL, App1 section is deleted */ 1120 data = "[App2]\r\n" 1121 "key4=string4\r\n" 1122 "[App3]\r\n" 1123 "key5=string5\r\n"; 1124 ret = WritePrivateProfileStringA("App1", NULL, "string1", path); 1125 ok(ret == TRUE, "Expected TRUE, got %d\n", ret); 1126 ok(check_file_data(path, data), "File doesn't match\n"); 1127 1128 /* lpString is not needed to delete a section */ 1129 data = "[App3]\r\n" 1130 "key5=string5\r\n"; 1131 ret = WritePrivateProfileStringA("App2", NULL, NULL, path); 1132 ok(ret == TRUE, "Expected TRUE, got %d\n", ret); 1133 ok(check_file_data(path, data), "File doesn't match\n"); 1134 1135 /* leave just the section */ 1136 data = "[App3]\r\n"; 1137 ret = WritePrivateProfileStringA("App3", "key5", NULL, path); 1138 ok(ret == TRUE, "Expected TRUE, got %d\n", ret); 1139 ok(check_file_data(path, data), "File doesn't match\n"); 1140 DeleteFileA(path); 1141 1142 /* NULLs in file before first section. Should be preserved in output */ 1143 data = "Data \0 before \0 first \0 section" /* 31 bytes */ 1144 "\r\n[section1]\r\n" /* 14 bytes */ 1145 "key1=string1\r\n"; /* 14 bytes */ 1146 GetTempFileNameA(temp, "wine", 0, path); 1147 create_test_file(path, data, 31); 1148 ret = WritePrivateProfileStringA("section1", "key1", "string1", path); 1149 ok(ret == TRUE, "Expected TRUE, got %d\n", ret); 1150 todo_wine 1151 ok( check_binary_file_data(path, data, 59) || 1152 broken( check_binary_file_data(path, /* Windows 9x */ 1153 "Data \0 before \0 first \0 section" /* 31 bytes */ 1154 "\r\n\r\n[section1]\r\n" /* 14 bytes */ 1155 "key1=string1" /* 14 bytes */ 1156 , 59)), "File doesn't match\n"); 1157 DeleteFileA(path); 1158 } 1159 1160 START_TEST(profile) 1161 { 1162 test_profile_int(); 1163 test_profile_string(); 1164 test_profile_sections(); 1165 test_profile_sections_names(); 1166 test_profile_existing(); 1167 test_profile_delete_on_close(); 1168 test_profile_refresh(); 1169 test_profile_directory_readonly(); 1170 test_GetPrivateProfileString( 1171 "[section1]\r\n" 1172 "name1=val1\r\n" 1173 "name2=\"val2\"\r\n" 1174 "name3\r\n" 1175 "name4=a\r\n" 1176 "[section2]\r\n", 1177 "CR+LF"); 1178 test_GetPrivateProfileString( 1179 "[section1]\r" 1180 "name1=val1\r" 1181 "name2=\"val2\"\r" 1182 "name3\r" 1183 "name4=a\r" 1184 "[section2]\r", 1185 "CR only"); 1186 test_WritePrivateProfileString(); 1187 } 1188