From b17882ecd89394011acfe1c43399edcbf94d9ec3 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Mon, 12 May 2008 08:33:26 +0000 Subject: [PATCH] Kamil Hornicek - Update tests to Wine head (as of 11th of May, 2008). svn path=/trunk/; revision=33464 --- rostests/winetests/directory.rbuild | 4 +- rostests/winetests/netapi32/access.c | 9 +- rostests/winetests/netapi32/netapi32.rbuild | 2 +- rostests/winetests/netapi32/wksta.c | 12 +- rostests/winetests/ntdll/atom.c | 204 ++-- rostests/winetests/ntdll/change.c | 22 +- rostests/winetests/ntdll/env.c | 45 +- rostests/winetests/ntdll/error.c | 35 +- rostests/winetests/ntdll/exception.c | 759 ++++++++++++- rostests/winetests/ntdll/file.c | 627 +++++++++++ rostests/winetests/ntdll/generated.c | 105 +- rostests/winetests/ntdll/info.c | 389 ++++--- rostests/winetests/ntdll/large_int.c | 61 +- rostests/winetests/ntdll/ntdll.rbuild | 7 + rostests/winetests/ntdll/ntdll_test.h | 2 +- rostests/winetests/ntdll/om.c | 185 ++-- rostests/winetests/ntdll/path.c | 25 +- rostests/winetests/ntdll/port.c | 39 +- rostests/winetests/ntdll/reg.c | 287 +++-- rostests/winetests/ntdll/rtl.c | 149 +-- rostests/winetests/ntdll/rtlbitmap.c | 14 +- rostests/winetests/ntdll/rtlstr.c | 162 ++- rostests/winetests/ntdll/string.c | 124 ++- rostests/winetests/ntdll/testlist.c | 4 +- rostests/winetests/ntdll/time.c | 6 +- rostests/winetests/odbccp32/misc.c | 2 +- rostests/winetests/odbccp32/odbccp32.rbuild | 2 +- rostests/winetests/ole32/clipboard.c | 101 ++ rostests/winetests/ole32/marshal.c | 103 +- rostests/winetests/ole32/moniker.c | 45 + rostests/winetests/ole32/ole32.rbuild | 2 +- rostests/winetests/psapi/psapi.rbuild | 4 + rostests/winetests/psapi/psapi_main.c | 56 +- rostests/winetests/riched20/editor.c | 557 +++++++++- rostests/winetests/riched20/riched20.rbuild | 2 +- rostests/winetests/riched32/editor.c | 602 +++++++++- rostests/winetests/riched32/riched32.rbuild | 2 +- rostests/winetests/rpcrt4/cstub.c | 2 + rostests/winetests/rpcrt4/generated.c | 2 +- rostests/winetests/rpcrt4/ndr_marshall.c | 314 +++++- rostests/winetests/rpcrt4/rpc.c | 280 +++++ rostests/winetests/rpcrt4/rpc_async.c | 91 ++ rostests/winetests/rpcrt4/rpcrt4.rbuild | 3 +- rostests/winetests/rpcrt4/server.c | 113 +- rostests/winetests/rpcrt4/server.idl | 19 + rostests/winetests/rpcrt4/testlist.c | 2 + rostests/winetests/rsabase/rsabase.rbuild | 2 +- rostests/winetests/rsaenh/rsaenh.c | 44 +- rostests/winetests/rsaenh/rsaenh.rbuild | 2 +- rostests/winetests/schannel/main.c | 20 +- rostests/winetests/schannel/schannel.rbuild | 2 +- rostests/winetests/setupapi/devinst.c | 1096 +++++++++++++++++++ rostests/winetests/setupapi/install.c | 425 +++++-- rostests/winetests/setupapi/misc.c | 595 ++++++++++ rostests/winetests/setupapi/parser.c | 306 +++++- rostests/winetests/setupapi/query.c | 243 +++- rostests/winetests/setupapi/setupapi.rbuild | 7 + rostests/winetests/setupapi/stringtable.c | 64 +- rostests/winetests/setupapi/testlist.c | 4 + rostests/winetests/shlwapi/istream.c | 122 +-- rostests/winetests/shlwapi/shlwapi.rbuild | 2 +- rostests/winetests/shlwapi/url.c | 125 ++- rostests/winetests/urlmon/misc.c | 20 +- rostests/winetests/urlmon/url.c | 3 +- rostests/winetests/urlmon/urlmon.rbuild | 2 +- rostests/winetests/usp10/usp10.c | 239 +++- rostests/winetests/usp10/usp10.rbuild | 4 + rostests/winetests/uxtheme/system.c | 4 +- rostests/winetests/uxtheme/uxtheme.rbuild | 2 +- rostests/winetests/version/info.c | 29 +- rostests/winetests/version/version.rbuild | 2 +- rostests/winetests/wininet/ftp.c | 25 +- rostests/winetests/wininet/http.c | 268 ++++- rostests/winetests/wininet/internet.c | 23 +- rostests/winetests/wininet/testlist.c | 2 + rostests/winetests/wininet/url.c | 12 +- rostests/winetests/wininet/urlcache.c | 172 +++ rostests/winetests/wininet/wininet.rbuild | 3 +- 78 files changed, 8097 insertions(+), 1354 deletions(-) create mode 100644 rostests/winetests/ntdll/file.c create mode 100644 rostests/winetests/rpcrt4/rpc_async.c create mode 100644 rostests/winetests/setupapi/devinst.c create mode 100644 rostests/winetests/setupapi/misc.c create mode 100644 rostests/winetests/wininet/urlcache.c diff --git a/rostests/winetests/directory.rbuild b/rostests/winetests/directory.rbuild index 45973de379b..983cb14b7b4 100644 --- a/rostests/winetests/directory.rbuild +++ b/rostests/winetests/directory.rbuild @@ -67,10 +67,10 @@ - diff --git a/rostests/winetests/netapi32/access.c b/rostests/winetests/netapi32/access.c index 7d5f55a9074..b1036a9d787 100644 --- a/rostests/winetests/netapi32/access.c +++ b/rostests/winetests/netapi32/access.c @@ -50,8 +50,8 @@ static WCHAR sTooLongPassword[] = {'a','b','c','d','e','f','g','h','a','b','c',' 'a', 0}; static WCHAR sTestUserName[] = {'t', 'e', 's', 't', 'u', 's', 'e', 'r', 0}; -static WCHAR sTestUserOldPass[] = {'o', 'l', 'd', 'p', 'a', 's', 's', 0}; -static WCHAR sTestUserNewPass[] = {'n', 'e', 'w', 'p', 'a', 's', 's', 0}; +static WCHAR sTestUserOldPass[] = {'O', 'l', 'd', 'P', 'a', 's', 's', 'W', '0', 'r', 'd', 'S', 'e', 't', '!', '~', 0}; +static WCHAR sTestUserNewPass[] = {'N', 'e', 'w', 'P', 'a', 's', 's', 'W', '0', 'r', 'd', 'S', 'e', 't', '!', '~', 0}; static const WCHAR sBadNetPath[] = {'\\','\\','B','a',' ',' ','p','a','t','h',0}; static const WCHAR sInvalidName[] = {'\\',0}; static const WCHAR sInvalidName2[] = {'\\','\\',0}; @@ -301,7 +301,10 @@ static void run_userhandling_tests(void) ret = pNetUserChangePassword(NULL, sTestUserName, sTestUserOldPass, sTestUserOldPass); - ok(ret == NERR_Success, + /* Apparently NERR_PasswordTooShort can be returned on windows xp if a + * strict password policy is enforced + */ + ok(ret == NERR_Success || ret == NERR_PasswordTooShort, "Changing old password to old password returned 0x%08x.\n", ret); ret = pNetUserChangePassword(NULL, sTestUserName, sTestUserNewPass, diff --git a/rostests/winetests/netapi32/netapi32.rbuild b/rostests/winetests/netapi32/netapi32.rbuild index 42143d0bab6..b8774cde957 100644 --- a/rostests/winetests/netapi32/netapi32.rbuild +++ b/rostests/winetests/netapi32/netapi32.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/netapi32/wksta.c b/rostests/winetests/netapi32/wksta.c index 5eefba4e552..01d0d6f7f38 100644 --- a/rostests/winetests/netapi32/wksta.c +++ b/rostests/winetests/netapi32/wksta.c @@ -80,7 +80,17 @@ static void run_wkstausergetinfo_tests(void) /* Level 0 */ ok(pNetWkstaUserGetInfo(NULL, 0, (LPBYTE *)&ui0) == NERR_Success, - "NetWkstaUserGetInfo is successful\n"); + "NetWkstaUserGetInfo is unsuccessful\n"); + + ok(ui0 != NULL, "ui0 is NULL\n"); + /* This failure occured when I ran sshd as service and didn't authenticate + * Since the test dereferences ui0, the rest of this test is worthless + */ + if (!ui0) + { + return; + } + ok(!lstrcmpW(user_name, ui0->wkui0_username), "This is really user name\n"); pNetApiBufferSize(ui0, &dwSize); ok(dwSize >= (sizeof(WKSTA_USER_INFO_0) + diff --git a/rostests/winetests/ntdll/atom.c b/rostests/winetests/ntdll/atom.c index 6ef6ee87e7e..87ea222a8f7 100755 --- a/rostests/winetests/ntdll/atom.c +++ b/rostests/winetests/ntdll/atom.c @@ -25,7 +25,7 @@ #include #include "ntstatus.h" -/* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro +/* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro * definition errors when we get to winnt.h */ #define WIN32_NO_STATUS @@ -89,7 +89,7 @@ static void InitFunctionPtr(void) } } -static DWORD RtlAtomTestThread(LPVOID Table) +static DWORD WINAPI RtlAtomTestThread(LPVOID Table) { RTL_ATOM_TABLE AtomTable = *(PRTL_ATOM_TABLE)Table; RTL_ATOM Atom; @@ -98,30 +98,30 @@ static DWORD RtlAtomTestThread(LPVOID Table) WCHAR Name[64]; res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &Atom); - ok(!res, "Unable to find atom from another thread, retval: %lx\n", res); + ok(!res, "Unable to find atom from another thread, retval: %x\n", res); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom2, &Atom); - ok(!res, "Unable to lookup pinned atom in table, retval: %lx\n", res); + ok(!res, "Unable to lookup pinned atom in table, retval: %x\n", res); res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, Name, &Len); - ok(res == STATUS_BUFFER_TOO_SMALL, "We got wrong retval: %lx\n", res); + ok(res == STATUS_BUFFER_TOO_SMALL, "We got wrong retval: %x\n", res); Len = 64; res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, Name, &Len); - ok(!res, "Failed with longenough buffer, retval: %lx\n", res); - ok(RefCount == 1, "Refcount was not 1 but %lx\n", RefCount); - ok(PinCount == 1, "Pincount was not 1 but %lx\n", PinCount); + ok(!res, "Failed with longenough buffer, retval: %x\n", res); + ok(RefCount == 1, "Refcount was not 1 but %x\n", RefCount); + ok(PinCount == 1, "Pincount was not 1 but %x\n", PinCount); ok(!lstrcmpW(Name, testAtom2), "We found wrong atom!!\n"); - ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %ld\n", Len); + ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %d\n", Len); Len = 64; res = pRtlQueryAtomInAtomTable(AtomTable, Atom, NULL, NULL, Name, &Len); - ok(!res, "RtlQueryAtomInAtomTable with optional args invalid failed, retval: %lx\n", res); + ok(!res, "RtlQueryAtomInAtomTable with optional args invalid failed, retval: %x\n", res); ok(!lstrcmpW(Name, testAtom2), "Found Wrong atom!\n"); - ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %ld\n", Len); + ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %d\n", Len); res = pRtlPinAtomInAtomTable(AtomTable, Atom); - ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res); + ok(!res, "Unable to pin atom in atom table, retval: %x\n", res); return 0; } @@ -143,140 +143,140 @@ static void test_NtAtom(void) if (!res) { res = pRtlDestroyAtomTable(AtomTable); - ok(!res, "We could create the atom table, but we couldn't destroy it! retval: %lx\n", res); + ok(!res, "We could create the atom table, but we couldn't destroy it! retval: %x\n", res); } AtomTable = NULL; res = pRtlCreateAtomTable(37, &AtomTable); - ok(!res, "We're unable to create an atom table with a valid table size retval: %lx\n", res); + ok(!res, "We're unable to create an atom table with a valid table size retval: %x\n", res); if (!res) { res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom1); - ok(!res, "We were unable to add a simple atom to the atom table, retval: %lx\n", res); + ok(!res, "We were unable to add a simple atom to the atom table, retval: %x\n", res); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1Cap, &testAtom); - ok(!res, "We were unable to find capital version of the atom, retval: %lx\n", res); + ok(!res, "We were unable to find capital version of the atom, retval: %x\n", res); ok(Atom1 == testAtom, "Found wrong atom in table when querying capital atom\n"); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1Low, &testAtom); - ok(!res, "Unable to find lowercase version of the atom, retval: %lx\n", res); + ok(!res, "Unable to find lowercase version of the atom, retval: %x\n", res); ok(testAtom == Atom1, "Found wrong atom when querying lowercase atom\n"); res = pRtlAddAtomToAtomTable(AtomTable, EmptyAtom, &testEAtom); - ok(res == STATUS_OBJECT_NAME_INVALID, "Got wrong retval, retval: %lx\n", res); + ok(res == STATUS_OBJECT_NAME_INVALID, "Got wrong retval, retval: %x\n", res); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom); - ok(!res, "Failed to find totally legitimate atom, retval: %lx\n", res); + ok(!res, "Failed to find totally legitimate atom, retval: %x\n", res); ok(testAtom == Atom1, "Found wrong atom!\n"); res = pRtlAddAtomToAtomTable(AtomTable, testAtom2, &Atom2); - ok(!res, "Unable to add other legitimate atom to table, retval: %lx\n", res); + ok(!res, "Unable to add other legitimate atom to table, retval: %x\n", res); res = pRtlPinAtomInAtomTable(AtomTable, Atom2); - ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res); + ok(!res, "Unable to pin atom in atom table, retval: %x\n", res); - testThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RtlAtomTestThread, &AtomTable, 0, NULL); + testThread = CreateThread(NULL, 0, RtlAtomTestThread, &AtomTable, 0, NULL); WaitForSingleObject(testThread, INFINITE); Len = 64; res = pRtlQueryAtomInAtomTable(AtomTable, Atom2, &RefCount, &PinCount, Name, &Len); - ok(!res, "Unable to query atom in atom table, retval: %lx\n", res); - ok(RefCount == 1, "RefCount is not 1 but %lx\n", RefCount); - ok(PinCount == 1, "PinCount is not 1 but %lx\n", PinCount); + ok(!res, "Unable to query atom in atom table, retval: %x\n", res); + ok(RefCount == 1, "RefCount is not 1 but %x\n", RefCount); + ok(PinCount == 1, "PinCount is not 1 but %x\n", PinCount); ok(!lstrcmpW(Name, testAtom2), "We found wrong atom\n"); - ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %ld\n", Len); + ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %d\n", Len); res = pRtlEmptyAtomTable(AtomTable, FALSE); - ok(!res, "Unable to empty atom table, retval %lx\n", res); + ok(!res, "Unable to empty atom table, retval %x\n", res); Len = 64; res = pRtlQueryAtomInAtomTable(AtomTable, Atom2, &RefCount, &PinCount, Name, &Len); - ok(!res, "It seems RtlEmptyAtomTable deleted our pinned atom eaven though we asked it not to, retval: %lx\n", res); - ok(RefCount == 1, "RefCount is not 1 but %lx\n", RefCount); - ok(PinCount == 1, "PinCount is not 1 but %lx\n", PinCount); + ok(!res, "It seems RtlEmptyAtomTable deleted our pinned atom eaven though we asked it not to, retval: %x\n", res); + ok(RefCount == 1, "RefCount is not 1 but %x\n", RefCount); + ok(PinCount == 1, "PinCount is not 1 but %x\n", PinCount); ok(!lstrcmpW(Name, testAtom2), "We found wrong atom\n"); - ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %ld\n", Len); + ok((lstrlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %d\n", Len); Len = 8; - Name[0] = Name[1] = Name[2] = Name[3] = Name[4] = 0x55AA; + Name[0] = Name[1] = Name[2] = Name[3] = Name[4] = 0x1337; res = pRtlQueryAtomInAtomTable(AtomTable, Atom2, NULL, NULL, Name, &Len); - ok(!res, "query atom %lx\n", res); - ok(Len == 6, "wrong length %lu\n", Len); + ok(!res, "query atom %x\n", res); + ok(Len == 6, "wrong length %u\n", Len); ok(!memcmp(Name, testAtom2, Len), "wrong atom string\n"); ok(!Name[3], "wrong string termination\n"); - ok(Name[4] == 0x55AA, "buffer overwrite\n"); + ok(Name[4] == 0x1337, "buffer overwrite\n"); Len = lstrlenW(testAtom2) * sizeof(WCHAR); memset(Name, '.', sizeof(Name)); res = pRtlQueryAtomInAtomTable( AtomTable, Atom2, NULL, NULL, Name, &Len ); - ok(!res, "query atom %lx\n", res); - ok(Len == (lstrlenW(testAtom2) - 1) * sizeof(WCHAR), "wrong length %lu\n", Len); + ok(!res, "query atom %x\n", res); + ok(Len == (lstrlenW(testAtom2) - 1) * sizeof(WCHAR), "wrong length %u\n", Len); ok(!memcmp(testAtom2, Name, (lstrlenW(testAtom2) - 1) * sizeof(WCHAR)), "wrong atom name\n"); ok(Name[lstrlenW(testAtom2) - 1] == '\0', "wrong char\n"); ok(Name[lstrlenW(testAtom2)] == ('.' << 8) + '.', "wrong char\n"); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom2, &testAtom); - ok(!res, "We can't find our pinned atom!! retval: %lx\n", res); + ok(!res, "We can't find our pinned atom!! retval: %x\n", res); ok(testAtom == Atom2, "We found wrong atom!!!\n"); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom); - ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "We found the atom in our table eaven though we asked RtlEmptyAtomTable to remove it, retval: %lx\n", res); + ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "We found the atom in our table eaven though we asked RtlEmptyAtomTable to remove it, retval: %x\n", res); res = pRtlAddAtomToAtomTable(AtomTable, testAtom3, &Atom3); - ok(!res, "Unable to add atom to table, retval: %lx\n", res); + ok(!res, "Unable to add atom to table, retval: %x\n", res); res = pRtlEmptyAtomTable(AtomTable, TRUE); - ok(!res, "Unable to empty atom table, retval: %lx\n", res); + ok(!res, "Unable to empty atom table, retval: %x\n", res); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom2, &testAtom); - ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "The pinned atom should be removed, retval: %lx\n", res); + ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "The pinned atom should be removed, retval: %x\n", res); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom3, &testAtom); - ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Non pinned atom should also be removed, retval: %lx\n", res); + ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Non pinned atom should also be removed, retval: %x\n", res); res = pRtlDestroyAtomTable(AtomTable); - ok(!res, "Can't destroy atom table, retval: %lx\n", res); + ok(!res, "Can't destroy atom table, retval: %x\n", res); } AtomTable = NULL; res = pRtlCreateAtomTable(37, &AtomTable); - ok(!res, "Unable to create atom table, retval: %lx\n", res); + ok(!res, "Unable to create atom table, retval: %x\n", res); if (!res) { res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom); - ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Didn't get expected retval with querying an empty atom table, retval: %lx\n", res); + ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Didn't get expected retval with querying an empty atom table, retval: %x\n", res); res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom1); - ok(!res, "Unable to add atom to atom table, retval %lx\n", res); + ok(!res, "Unable to add atom to atom table, retval %x\n", res); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom); - ok(!res, "Can't find previously added atom in table, retval: %lx\n", res); - ok(testAtom == Atom1, "Found wrong atom! retval: %lx\n", res); + ok(!res, "Can't find previously added atom in table, retval: %x\n", res); + ok(testAtom == Atom1, "Found wrong atom! retval: %x\n", res); res = pRtlDeleteAtomFromAtomTable(AtomTable, Atom1); - ok(!res, "Unable to delete atom from table, retval: %lx\n", res); + ok(!res, "Unable to delete atom from table, retval: %x\n", res); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom); - ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Able to find previously deleted atom in table, retval: %lx\n", res); + ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Able to find previously deleted atom in table, retval: %x\n", res); res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom1); - ok(!res, "Unable to add atom to atom table, retval: %lx\n", res); + ok(!res, "Unable to add atom to atom table, retval: %x\n", res); Len = 0; res = pRtlQueryAtomInAtomTable(AtomTable, Atom1, NULL, NULL, Name, &Len); - ok(res == STATUS_BUFFER_TOO_SMALL, "Got wrong retval, retval: %lx\n", res); - ok((lstrlenW(testAtom1) * sizeof(WCHAR)) == Len, "Got wrong length %lx\n", Len); + ok(res == STATUS_BUFFER_TOO_SMALL, "Got wrong retval, retval: %x\n", res); + ok((lstrlenW(testAtom1) * sizeof(WCHAR)) == Len, "Got wrong length %x\n", Len); res = pRtlPinAtomInAtomTable(AtomTable, Atom1); - ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res); + ok(!res, "Unable to pin atom in atom table, retval: %x\n", res); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom); - ok(!res, "Unable to find atom in atom table, retval: %lx\n", res); + ok(!res, "Unable to find atom in atom table, retval: %x\n", res); ok(testAtom == Atom1, "Wrong atom found\n"); res = pRtlDeleteAtomFromAtomTable(AtomTable, Atom1); - ok(res == STATUS_WAS_LOCKED, "Unable to delete atom from table, retval: %lx\n", res); + ok(res == STATUS_WAS_LOCKED, "Unable to delete atom from table, retval: %x\n", res); res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom); ok(!res, "Able to find deleted atom in table\n"); @@ -299,82 +299,82 @@ static void test_NtIntAtom(void) AtomTable = NULL; res = pRtlCreateAtomTable(37, &AtomTable); - ok(!res, "Unable to create atom table, %lx\n", res); + ok(!res, "Unable to create atom table, %x\n", res); if (!res) { - /* According to the kernel32 functions, integer atoms are only allowd from + /* According to the kernel32 functions, integer atoms are only allowed from * 0x0001 to 0xbfff and not 0xc000 to 0xffff, which is correct */ res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)0, &testAtom); - ok(res == STATUS_INVALID_PARAMETER, "Didn't get expected result from adding 0 int atom, retval: %lx\n", res); + ok(res == STATUS_INVALID_PARAMETER, "Didn't get expected result from adding 0 int atom, retval: %x\n", res); for (i = 1; i <= 0xbfff; i++) { res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)i, &testAtom); - ok(!res, "Unable to add valid integer atom %i, retval: %lx\n", i, res); + ok(!res, "Unable to add valid integer atom %i, retval: %x\n", i, res); } for (i = 1; i <= 0xbfff; i++) { res = pRtlLookupAtomInAtomTable(AtomTable, (PWSTR)i, &testAtom); - ok(!res, "Unable to find int atom %i, retval: %lx\n", i, res); + ok(!res, "Unable to find int atom %i, retval: %x\n", i, res); if (!res) { res = pRtlPinAtomInAtomTable(AtomTable, testAtom); - ok(!res, "Unable to pin int atom %i, retval: %lx\n", i, res); + ok(!res, "Unable to pin int atom %i, retval: %x\n", i, res); } } for (i = 0xc000; i <= 0xffff; i++) { res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)i, &testAtom); - ok(res, "Able to illeageal integer atom %i, retval: %lx\n", i, res); + ok(res, "Able to illeageal integer atom %i, retval: %x\n", i, res); } res = pRtlDestroyAtomTable(AtomTable); - ok(!res, "Unable to destroy atom table, retval: %lx\n", res); + ok(!res, "Unable to destroy atom table, retval: %x\n", res); } AtomTable = NULL; res = pRtlCreateAtomTable(37, &AtomTable); - ok(!res, "Unable to create atom table, %lx\n", res); + ok(!res, "Unable to create atom table, %x\n", res); if (!res) { res = pRtlLookupAtomInAtomTable(AtomTable, (PWSTR)123, &testAtom); - ok(!res, "Unable to query atom in atom table, retval: %lx\n", res); + ok(!res, "Unable to query atom in atom table, retval: %x\n", res); res = pRtlAddAtomToAtomTable(AtomTable, testAtomInt, &testAtom); - ok(!res, "Unable to add int atom to table, retval: %lx\n", res); + ok(!res, "Unable to add int atom to table, retval: %x\n", res); res = pRtlAddAtomToAtomTable(AtomTable, testAtomIntInv, &testAtom); - ok(!res, "Unable to add int atom to table, retval: %lx\n", res); + ok(!res, "Unable to add int atom to table, retval: %x\n", res); res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)123, &testAtom); - ok(!res, "Unable to add int atom to table, retval: %lx\n", res); + ok(!res, "Unable to add int atom to table, retval: %x\n", res); res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)123, &testAtom); - ok(!res, "Unable to re-add int atom to table, retval: %lx\n", res); + ok(!res, "Unable to re-add int atom to table, retval: %x\n", res); Len = 64; res = pRtlQueryAtomInAtomTable(AtomTable, testAtom, &RefCount, &PinCount, Name, &Len); - ok(!res, "Unable to query atom in atom table, retval: %lx\n", res); - ok(PinCount == 1, "Expected pincount 1 but got %lx\n", PinCount); - ok(RefCount == 1, "Expected refcount 1 but got %lx\n", RefCount); + ok(!res, "Unable to query atom in atom table, retval: %x\n", res); + ok(PinCount == 1, "Expected pincount 1 but got %x\n", PinCount); + ok(RefCount == 1, "Expected refcount 1 but got %x\n", RefCount); ok(!lstrcmpW(testAtomOTT, Name), "Got wrong atom name\n"); - ok((lstrlenW(testAtomOTT) * sizeof(WCHAR)) == Len, "Got wrong len %ld\n", Len); + ok((lstrlenW(testAtomOTT) * sizeof(WCHAR)) == Len, "Got wrong len %d\n", Len); res = pRtlPinAtomInAtomTable(AtomTable, testAtom); - ok(!res, "Unable to pin int atom, retval: %lx\n", res); + ok(!res, "Unable to pin int atom, retval: %x\n", res); res = pRtlPinAtomInAtomTable(AtomTable, testAtom); - ok(!res, "Unable to pin int atom, retval: %lx\n", res); + ok(!res, "Unable to pin int atom, retval: %x\n", res); res = pRtlQueryAtomInAtomTable(AtomTable, testAtom, &RefCount, &PinCount, NULL, NULL); - ok(!res, "Unable to query atom in atom table, retval: %lx\n", res); - ok(PinCount == 1, "Expected pincount 1 but got %lx\n", PinCount); - ok(RefCount == 1, "Expected refcount 1 but got %lx\n", RefCount); + ok(!res, "Unable to query atom in atom table, retval: %x\n", res); + ok(PinCount == 1, "Expected pincount 1 but got %x\n", PinCount); + ok(RefCount == 1, "Expected refcount 1 but got %x\n", RefCount); res = pRtlDestroyAtomTable(AtomTable); - ok(!res, "Unable to destroy atom table, retval: %lx\n", res); + ok(!res, "Unable to destroy atom table, retval: %x\n", res); } } @@ -388,40 +388,40 @@ static void test_NtRefPinAtom(void) AtomTable = NULL; res = pRtlCreateAtomTable(37, &AtomTable); - ok(!res, "Unable to create atom table, %lx\n", res); + ok(!res, "Unable to create atom table, %x\n", res); if (!res) { res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom); - ok(!res, "Unable to add our atom to the atom table, retval: %lx\n", res); + ok(!res, "Unable to add our atom to the atom table, retval: %x\n", res); res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom); - ok(!res, "Unable to add our atom to the atom table, retval: %lx\n", res); + ok(!res, "Unable to add our atom to the atom table, retval: %x\n", res); res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom); - ok(!res, "Unable to add our atom to the atom table, retval: %lx\n", res); + ok(!res, "Unable to add our atom to the atom table, retval: %x\n", res); res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, NULL, NULL); - ok(!res, "Unable to query atom in atom table, retval: %lx\n", res); - ok(PinCount == 0, "Expected pincount 0 but got %lx\n", PinCount); - ok(RefCount == 3, "Expected refcount 3 but got %lx\n", RefCount); + ok(!res, "Unable to query atom in atom table, retval: %x\n", res); + ok(PinCount == 0, "Expected pincount 0 but got %x\n", PinCount); + ok(RefCount == 3, "Expected refcount 3 but got %x\n", RefCount); res = pRtlPinAtomInAtomTable(AtomTable, Atom); - ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res); + ok(!res, "Unable to pin atom in atom table, retval: %x\n", res); res = pRtlPinAtomInAtomTable(AtomTable, Atom); - ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res); + ok(!res, "Unable to pin atom in atom table, retval: %x\n", res); res = pRtlPinAtomInAtomTable(AtomTable, Atom); - ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res); + ok(!res, "Unable to pin atom in atom table, retval: %x\n", res); res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, NULL, NULL); - ok(!res, "Unable to query atom in atom table, retval: %lx\n", res); - ok(PinCount == 1, "Expected pincount 1 but got %lx\n", PinCount); - ok(RefCount == 3, "Expected refcount 3 but got %lx\n", RefCount); + ok(!res, "Unable to query atom in atom table, retval: %x\n", res); + ok(PinCount == 1, "Expected pincount 1 but got %x\n", PinCount); + ok(RefCount == 3, "Expected refcount 3 but got %x\n", RefCount); res = pRtlDestroyAtomTable(AtomTable); - ok(!res, "Unable to destroy atom table, retval: %lx\n", res); + ok(!res, "Unable to destroy atom table, retval: %x\n", res); } } @@ -434,29 +434,29 @@ static void test_Global(void) ULONG ptr_size = sizeof(ATOM_BASIC_INFORMATION) + 255 * sizeof(WCHAR); res = pNtAddAtom(testAtom1, lstrlenW(testAtom1) * sizeof(WCHAR), &atom); - ok(!res, "Added atom (%lx)\n", res); + ok(!res, "Added atom (%x)\n", res); - memset(abi->Name, 0x55, 255 * sizeof(WCHAR)); + memset(abi->Name, 0xcc, 255 * sizeof(WCHAR)); res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL ); ok(!res, "atom lookup\n"); ok(!lstrcmpW(abi->Name, testAtom1), "ok strings\n"); ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR), "wrong string length\n"); ok(abi->Name[lstrlenW(testAtom1)] == 0, "wrong string termination %x\n", abi->Name[lstrlenW(testAtom1)]); - ok(abi->Name[lstrlenW(testAtom1) + 1] == 0x5555, "buffer overwrite %x\n", abi->Name[lstrlenW(testAtom1) + 1]); + ok(abi->Name[lstrlenW(testAtom1) + 1] == 0xcccc, "buffer overwrite %x\n", abi->Name[lstrlenW(testAtom1) + 1]); ptr_size = sizeof(ATOM_BASIC_INFORMATION); res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL ); - ok(res == STATUS_BUFFER_TOO_SMALL, "wrong return status (%lx)\n", res); + ok(res == STATUS_BUFFER_TOO_SMALL, "wrong return status (%x)\n", res); ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR), "ok string length\n"); - memset(abi->Name, 0x55, lstrlenW(testAtom1) * sizeof(WCHAR)); + memset(abi->Name, 0xcc, lstrlenW(testAtom1) * sizeof(WCHAR)); ptr_size = sizeof(ATOM_BASIC_INFORMATION) + lstrlenW(testAtom1) * sizeof(WCHAR); res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL ); - ok(!res, "atom lookup %lx\n", res); + ok(!res, "atom lookup %x\n", res); ok(!lstrcmpW(abi->Name, testAtom1), "strings don't match\n"); ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR), "wrong string length\n"); ok(abi->Name[lstrlenW(testAtom1)] == 0, "buffer overwrite %x\n", abi->Name[lstrlenW(testAtom1)]); - ok(abi->Name[lstrlenW(testAtom1) + 1] == 0x5555, "buffer overwrite %x\n", abi->Name[lstrlenW(testAtom1) + 1]); + ok(abi->Name[lstrlenW(testAtom1) + 1] == 0xcccc, "buffer overwrite %x\n", abi->Name[lstrlenW(testAtom1) + 1]); ptr_size = sizeof(ATOM_BASIC_INFORMATION) + 4 * sizeof(WCHAR); abi->Name[0] = abi->Name[1] = abi->Name[2] = abi->Name[3] = '\0'; diff --git a/rostests/winetests/ntdll/change.c b/rostests/winetests/ntdll/change.c index 1155df998cb..d3ba58fc1c1 100644 --- a/rostests/winetests/ntdll/change.c +++ b/rostests/winetests/ntdll/change.c @@ -59,7 +59,7 @@ static void test_ntncdf(void) RemoveDirectoryW( subdir ); RemoveDirectoryW( path ); - + r = CreateDirectoryW(path, NULL); ok( r == TRUE, "failed to create directory\n"); @@ -67,7 +67,7 @@ static void test_ntncdf(void) ok(r==STATUS_ACCESS_VIOLATION, "should return access violation\n"); fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED; - hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE, FILE_SHARE_READ, NULL, + hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE, FILE_SHARE_READ, NULL, OPEN_EXISTING, fflags, NULL); ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n"); @@ -187,7 +187,7 @@ static void test_ntncdf_async(void) RemoveDirectoryW( subdir ); RemoveDirectoryW( path ); - + r = CreateDirectoryW(path, NULL); ok( r == TRUE, "failed to create directory\n"); @@ -195,7 +195,7 @@ static void test_ntncdf_async(void) ok(r==STATUS_ACCESS_VIOLATION, "should return access violation\n"); fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED; - hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE, FILE_SHARE_READ, NULL, + hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE, FILE_SHARE_READ, NULL, OPEN_EXISTING, fflags, NULL); ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n"); @@ -316,16 +316,22 @@ static void test_ntncdf_async(void) START_TEST(change) { HMODULE hntdll = GetModuleHandle("ntdll"); + if (!hntdll) + { + skip("not running on NT, skipping test\n"); + return; + } - pNtNotifyChangeDirectoryFile = (fnNtNotifyChangeDirectoryFile) + pNtNotifyChangeDirectoryFile = (fnNtNotifyChangeDirectoryFile) GetProcAddress(hntdll, "NtNotifyChangeDirectoryFile"); pNtCancelIoFile = (fnNtCancelIoFile) GetProcAddress(hntdll, "NtCancelIoFile"); - if (!pNtNotifyChangeDirectoryFile) - return; - if (!pNtCancelIoFile) + if (!pNtNotifyChangeDirectoryFile || !pNtCancelIoFile) + { + skip("missing functions, skipping test\n"); return; + } test_ntncdf(); test_ntncdf_async(); diff --git a/rostests/winetests/ntdll/env.c b/rostests/winetests/ntdll/env.c index 230398b9f35..3363e73484e 100755 --- a/rostests/winetests/ntdll/env.c +++ b/rostests/winetests/ntdll/env.c @@ -99,23 +99,22 @@ static void testQuery(void) pRtlMultiByteToUnicodeN( bn, sizeof(bn), NULL, test->var, strlen(test->var)+1 ); nts = pRtlQueryEnvironmentVariable_U(small_env, &name, &value); - ok( nts == test->status, "[%d]: Wrong status for '%s', expecting %lx got %lx\n", + ok( nts == test->status, "[%d]: Wrong status for '%s', expecting %x got %x\n", test - tests, test->var, test->status, nts ); if (nts == test->status) switch (nts) { case STATUS_SUCCESS: pRtlMultiByteToUnicodeN( bn, sizeof(bn), NULL, test->val, strlen(test->val)+1 ); - ok( value.Length == strlen(test->val) * sizeof(WCHAR), "Wrong length %d/%d for %s\n", - value.Length, strlen(test->val) * sizeof(WCHAR), test->var ); + ok( value.Length == strlen(test->val) * sizeof(WCHAR), "Wrong length %d for %s\n", + value.Length, test->var ); ok((value.Length == strlen(test->val) * sizeof(WCHAR) && memcmp(bv, bn, test->len*sizeof(WCHAR)) == 0) || - lstrcmpW(bv, bn) == 0, + lstrcmpW(bv, bn) == 0, "Wrong result for %s/%d\n", test->var, test->len); ok(bv[test->len] == '@', "Writing too far away in the buffer for %s/%d\n", test->var, test->len); break; case STATUS_BUFFER_TOO_SMALL: - ok( value.Length == strlen(test->val) * sizeof(WCHAR), - "Wrong returned length %d/%d (too small buffer) for %s\n", - value.Length, strlen(test->val) * sizeof(WCHAR), test->var ); + ok( value.Length == strlen(test->val) * sizeof(WCHAR), + "Wrong returned length %d (too small buffer) for %s\n", value.Length, test->var ); break; } } @@ -140,7 +139,7 @@ static void testSetHelper(LPWSTR* env, const char* var, const char* val, NTSTATU pRtlMultiByteToUnicodeN( bval1, sizeof(bval1), NULL, val, strlen(val)+1 ); } nts = pRtlSetEnvironmentVariable(env, &uvar, val ? &uval : NULL); - ok(nts == ret, "Setting var %s=%s (%lx/%lx)\n", var, val, nts, ret); + ok(nts == ret, "Setting var %s=%s (%x/%x)\n", var, val, nts, ret); if (nts == STATUS_SUCCESS) { uval.Length = 0; @@ -156,7 +155,7 @@ static void testSetHelper(LPWSTR* env, const char* var, const char* val, NTSTATU ok(val == NULL, "Couldn't find variable, but didn't delete it. val = %s\n", val); break; default: - ok(0, "Wrong ret %lu for %s\n", nts, var); + ok(0, "Wrong ret %u for %s\n", nts, var); break; } } @@ -214,8 +213,8 @@ static void testExpand(void) * {"hello%foo%world%=oOH%eeck", "hellototoworldIIIeeck"}, * Interestingly enough, with a 8 WCHAR buffers, we get on 2k: * helloIII - * so it seems like strings overflowing the buffer are written - * (troncated) but the write cursor is not advanced :-/ + * so it seems like strings overflowing the buffer are written + * (truncated) but the write cursor is not advanced :-/ */ {NULL, NULL} }; @@ -240,22 +239,19 @@ static void testExpand(void) us_dst.Buffer = NULL; nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul); - ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), - "Wrong returned length for %s: %lu <> %u\n", - test->src, ul, strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR)); + ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), + "Wrong returned length for %s: %u\n", test->src, ul ); us_dst.Length = 0; us_dst.MaximumLength = sizeof(dst); us_dst.Buffer = dst; nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul); - ok(nts == STATUS_SUCCESS, "Call failed (%lu)\n", nts); - ok(ul == us_dst.Length + sizeof(WCHAR), - "Wrong returned length for %s: %lu <> %u\n", - test->src, ul, us_dst.Length + sizeof(WCHAR)); - ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), - "Wrong returned length for %s: %lu <> %u\n", - test->src, ul, strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR)); + ok(nts == STATUS_SUCCESS, "Call failed (%u)\n", nts); + ok(ul == us_dst.Length + sizeof(WCHAR), + "Wrong returned length for %s: %u\n", test->src, ul); + ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), + "Wrong returned length for %s: %u\n", test->src, ul); ok(lstrcmpW(dst, rst) == 0, "Wrong result for %s: expecting %s\n", test->src, test->dst); @@ -264,10 +260,9 @@ static void testExpand(void) us_dst.Buffer = dst; dst[8] = '-'; nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul); - ok(nts == STATUS_BUFFER_TOO_SMALL, "Call failed (%lu)\n", nts); - ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), - "Wrong returned length for %s (with buffer too small): %lu <> %u\n", - test->src, ul, strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR)); + ok(nts == STATUS_BUFFER_TOO_SMALL, "Call failed (%u)\n", nts); + ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), + "Wrong returned length for %s (with buffer too small): %u\n", test->src, ul); ok(memcmp(dst, rst, 8*sizeof(WCHAR)) == 0, "Wrong result for %s (with buffer too small): expecting %s\n", test->src, test->dst); diff --git a/rostests/winetests/ntdll/error.c b/rostests/winetests/ntdll/error.c index 9679c8f3423..b00b83bd661 100755 --- a/rostests/winetests/ntdll/error.c +++ b/rostests/winetests/ntdll/error.c @@ -32,8 +32,7 @@ #include "winreg.h" #include "winternl.h" -/* FIXME!!! this test checks only mappings, defined by MSDN: - * http://support.microsoft.com/default.aspx?scid=KB;EN-US;q113996& +/* FIXME!!! this test checks only mappings, defined by MSDN * It is necessary to add other mappings and to test them up to Windows XP. * * Some Windows platforms don't know about all the mappings, and in such @@ -46,7 +45,7 @@ * (of course older Windows platforms will fail to pass the strict mode) */ -static ULONG (WINAPI *statustodoserror)(NTSTATUS Status); +static ULONG (WINAPI *pRtlNtStatusToDosError)(NTSTATUS Status); static int strict; static int prepare_test(void) @@ -56,8 +55,8 @@ static int prepare_test(void) char** argv; ntdll = LoadLibraryA("ntdll.dll"); - statustodoserror = (void*)GetProcAddress(ntdll, "RtlNtStatusToDosError"); - if (!statustodoserror) + pRtlNtStatusToDosError = (void*)GetProcAddress(ntdll, "RtlNtStatusToDosError"); + if (!pRtlNtStatusToDosError) return 0; argc = winetest_get_mainargs(&argv); @@ -69,9 +68,9 @@ static void cmp_call(NTSTATUS win_nt, ULONG win32, const char* message) { ULONG err; - err = statustodoserror(win_nt); + err = pRtlNtStatusToDosError(win_nt); ok(err == win32, - "%s (%lx): got %ld, expected %ld\n", + "%s (%x): got %u, expected %u\n", message, win_nt, err, win32); } @@ -79,10 +78,10 @@ static void cmp_call2(NTSTATUS win_nt, ULONG win32, const char* message) { ULONG err; - err = statustodoserror(win_nt); + err = pRtlNtStatusToDosError(win_nt); ok(err == win32 || (!strict && err == ERROR_MR_MID_NOT_FOUND), - "%s (%lx): got %ld, expected %ld (or MID_NOT_FOUND)\n", + "%s (%x): got %u, expected %u (or MID_NOT_FOUND)\n", message, win_nt, err, win32); } @@ -90,9 +89,9 @@ static void cmp_call3(NTSTATUS win_nt, ULONG win32_1, ULONG win32_2, const char* { ULONG err; - err = statustodoserror(win_nt); + err = pRtlNtStatusToDosError(win_nt); ok(err == win32_1 || (!strict && err == win32_2), - "%s (%lx): got %ld, expected %ld or %ld\n", + "%s (%x): got %u, expected %u or %u\n", message, win_nt, err, win32_1, win32_2); } @@ -100,10 +99,10 @@ static void cmp_call4(NTSTATUS win_nt, ULONG win32_1, ULONG win32_2, const char* { ULONG err; - err = statustodoserror(win_nt); + err = pRtlNtStatusToDosError(win_nt); ok(err == win32_1 || (!strict && (err == win32_2 || err == ERROR_MR_MID_NOT_FOUND)), - "%s (%lx): got %ld, expected %ld or %ld\n", + "%s (%x): got %u, expected %u or %u\n", message, win_nt, err, win32_1, win32_2); } @@ -245,11 +244,11 @@ static void run_error_tests(void) cmp2(STATUS_PKINIT_FAILURE, ERROR_PKINIT_FAILURE); cmp2(STATUS_SMARTCARD_SUBSYSTEM_FAILURE, ERROR_SMARTCARD_SUBSYSTEM_FAILURE); cmp2(STATUS_DOWNGRADE_DETECTED, ERROR_DOWNGRADE_DETECTED); - cmp2(STATUS_SMARTCARD_CERT_REVOKED, SEC_E_SMARTCARD_CERT_REVOKED); - cmp2(STATUS_ISSUING_CA_UNTRUSTED, SEC_E_ISSUING_CA_UNTRUSTED); - cmp2(STATUS_REVOCATION_OFFLINE_C, SEC_E_REVOCATION_OFFLINE_C); - cmp2(STATUS_PKINIT_CLIENT_FAILURE, SEC_E_PKINIT_CLIENT_FAILURE); - cmp2(STATUS_SMARTCARD_CERT_EXPIRED, SEC_E_SMARTCARD_CERT_EXPIRED); + cmp4(STATUS_SMARTCARD_CERT_REVOKED, SEC_E_SMARTCARD_CERT_REVOKED, 1266); /* FIXME: real name? */ + cmp4(STATUS_ISSUING_CA_UNTRUSTED, SEC_E_ISSUING_CA_UNTRUSTED, 1267); /* FIXME: real name? */ + cmp4(STATUS_REVOCATION_OFFLINE_C, SEC_E_REVOCATION_OFFLINE_C, 1268); /* FIXME: real name? */ + cmp4(STATUS_PKINIT_CLIENT_FAILURE, SEC_E_PKINIT_CLIENT_FAILURE, 1269); /* FIXME: real name? */ + cmp4(STATUS_SMARTCARD_CERT_EXPIRED, SEC_E_SMARTCARD_CERT_EXPIRED, 1270); /* FIXME: real name? */ cmp2(STATUS_NO_KERB_KEY, SEC_E_NO_KERB_KEY); cmp2(STATUS_CURRENT_DOMAIN_NOT_ALLOWED, ERROR_CURRENT_DOMAIN_NOT_ALLOWED); cmp2(STATUS_SMARTCARD_WRONG_PIN, SCARD_W_WRONG_CHV); diff --git a/rostests/winetests/ntdll/exception.c b/rostests/winetests/ntdll/exception.c index e0aca2c97a4..e256e187066 100644 --- a/rostests/winetests/ntdll/exception.c +++ b/rostests/winetests/ntdll/exception.c @@ -19,20 +19,7 @@ */ #include - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x500 /* For NTSTATUS */ -#endif - #include -#define WIN32_NO_STATUS -#include -#define NTOS_MODE_USER -#include - -#include "wine/test.h" - -/* #include "ntstatus.h" #define WIN32_NO_STATUS @@ -41,14 +28,23 @@ #include "winnt.h" #include "winreg.h" #include "winternl.h" -#include "excpt.h" +#include "wine/exception.h" #include "wine/test.h" -*/ - #ifdef __i386__ +static int my_argc; +static char** my_argv; +static int test_stage; static struct _TEB * (WINAPI *pNtCurrentTeb)(void); +static NTSTATUS (WINAPI *pNtGetContextThread)(HANDLE,CONTEXT*); +static NTSTATUS (WINAPI *pNtSetContextThread)(HANDLE,CONTEXT*); +static NTSTATUS (WINAPI *pRtlRaiseException)(EXCEPTION_RECORD *rec); +static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func); +static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID handler); +static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*); +static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code); +static void *code_mem; /* Test various instruction combinations that cause a protection fault on the i386, * and check what the resulting exception looks like. @@ -105,7 +101,7 @@ static const struct exception /* test loading an invalid selector */ { { 0xb8, 0xef, 0xbe, 0x00, 0x00, 0x8e, 0xe8, 0xc3 }, /* mov $beef,%ax; mov %ax,%gs; ret */ - 5, 2, STATUS_ACCESS_VIOLATION, 2, { 0, 0xbee8 } }, + 5, 2, STATUS_ACCESS_VIOLATION, 2, { 0, 0xbee8 } }, /* 0xbee8 or 0xffffffff */ /* test accessing a zero selector */ { { 0x06, 0x31, 0xc0, 0x8e, 0xc0, 0x26, 0xa1, 0, 0, 0, 0, 0x07, 0xc3 }, @@ -118,7 +114,7 @@ static const struct exception /* test overlong instruction (limit is 16 bytes) */ { { 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0xfa,0xc3 }, - 0, 16, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, + 0, 16, STATUS_ILLEGAL_INSTRUCTION, 0 }, { { 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0xfa,0xc3 }, 0, 15, STATUS_PRIVILEGED_INSTRUCTION, 0 }, @@ -154,9 +150,9 @@ static const struct exception { { 0xa1, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffc,%eax; ret */ 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffc } }, { { 0xa1, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffd,%eax; ret */ - 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, + 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffd } }, { { 0xa1, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffe,%eax; ret */ - 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, + 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffe } }, { { 0xa1, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xffffffff,%eax; ret */ 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, @@ -164,14 +160,172 @@ static const struct exception { { 0xa3, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffc; ret */ 0, 5, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffc } }, { { 0xa3, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffd; ret */ - 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, + 0, 5, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffd } }, { { 0xa3, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffe; ret */ - 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, + 0, 5, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffe } }, { { 0xa3, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xffffffff; ret */ - 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, + 0, 5, STATUS_ACCESS_VIOLATION, 2, { 1, 0xffffffff } }, }; static int got_exception; +static BOOL have_vectored_api; + +static void run_exception_test(void *handler, const void* context, + const void *code, unsigned int code_size) +{ + struct { + EXCEPTION_REGISTRATION_RECORD frame; + const void *context; + } exc_frame; + void (*func)(void) = code_mem; + + exc_frame.frame.Handler = handler; + exc_frame.frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; + exc_frame.context = context; + + memcpy(code_mem, code, code_size); + + pNtCurrentTeb()->Tib.ExceptionList = &exc_frame.frame; + func(); + pNtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev; +} + +LONG CALLBACK rtlraiseexception_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) +{ + PCONTEXT context = ExceptionInfo->ContextRecord; + PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord; + trace("vect. handler %08x addr:%p context.Eip:%x\n", rec->ExceptionCode, + rec->ExceptionAddress, context->Eip); + + todo_wine { + ok(rec->ExceptionAddress == (char *)code_mem + 0xb, "ExceptionAddress at %p instead of %p\n", + rec->ExceptionAddress, (char *)code_mem + 0xb); + + if (pNtCurrentTeb()->Peb->BeingDebugged) + ok((void *)context->Eax == pRtlRaiseException, "debugger managed to modify Eax to %x should be %p\n", + context->Eax, pRtlRaiseException); + } + + /* check that context.Eip is fixed up only for EXCEPTION_BREAKPOINT + * even if raised by RtlRaiseException + */ + if(rec->ExceptionCode == EXCEPTION_BREAKPOINT) + { + ok(context->Eip == (DWORD)code_mem + 0xa, "Eip at %x instead of %x\n", + context->Eip, (DWORD)code_mem + 0xa); + } + else + { + ok(context->Eip == (DWORD)code_mem + 0xb, "Eip at %x instead of %x\n", + context->Eip, (DWORD)code_mem + 0xb); + } + + /* test if context change is preserved from vectored handler to stack handlers */ + context->Eax = 0xf00f00f0; + return EXCEPTION_CONTINUE_SEARCH; +} + +static DWORD rtlraiseexception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ + trace( "exception: %08x flags:%x addr:%p context: Eip:%x\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, context->Eip ); + + todo_wine { + ok(rec->ExceptionAddress == (char *)code_mem + 0xb, "ExceptionAddress at %p instead of %p\n", + rec->ExceptionAddress, (char *)code_mem + 0xb); + } + + /* check that context.Eip is fixed up only for EXCEPTION_BREAKPOINT + * even if raised by RtlRaiseException + */ + if(rec->ExceptionCode == EXCEPTION_BREAKPOINT) + { + ok(context->Eip == (DWORD)code_mem + 0xa, "Eip at %x instead of %x\n", + context->Eip, (DWORD)code_mem + 0xa); + } + else + { + ok(context->Eip == (DWORD)code_mem + 0xb, "Eip at %x instead of %x\n", + context->Eip, (DWORD)code_mem + 0xb); + } + + if(have_vectored_api) + ok(context->Eax == 0xf00f00f0, "Eax is %x, should have been set to 0xf00f00f0 in vectored handler\n", + context->Eax); + + /* give the debugger a chance to examine the state a second time */ + /* without the exception handler changing Eip */ + if (test_stage == 2) + return ExceptionContinueSearch; + + /* Eip in context is decreased by 1 + * Increase it again, else execution will continue in the middle of a instruction */ + if(rec->ExceptionCode == EXCEPTION_BREAKPOINT && (context->Eip == (DWORD)code_mem + 0xa)) + context->Eip += 1; + return ExceptionContinueExecution; +} + + +static const BYTE call_one_arg_code[] = { + 0x8b, 0x44, 0x24, 0x08, /* mov 0x8(%esp),%eax */ + 0x50, /* push %eax */ + 0x8b, 0x44, 0x24, 0x08, /* mov 0x8(%esp),%eax */ + 0xff, 0xd0, /* call *%eax */ + 0x90, /* nop */ + 0x90, /* nop */ + 0x90, /* nop */ + 0x90, /* nop */ + 0xc3, /* ret */ +}; + + +static void run_rtlraiseexception_test(DWORD exceptioncode) +{ + EXCEPTION_REGISTRATION_RECORD frame; + EXCEPTION_RECORD record; + PVOID vectored_handler = NULL; + + void (*func)(void* function, EXCEPTION_RECORD* record) = code_mem; + + record.ExceptionCode = exceptioncode; + record.ExceptionFlags = 0; + record.ExceptionRecord = NULL; + record.ExceptionAddress = NULL; /* does not matter, copied return address */ + record.NumberParameters = 0; + + frame.Handler = rtlraiseexception_handler; + frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; + + memcpy(code_mem, call_one_arg_code, sizeof(call_one_arg_code)); + + pNtCurrentTeb()->Tib.ExceptionList = &frame; + if (have_vectored_api) + { + vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &rtlraiseexception_vectored_handler); + ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n"); + } + + func(pRtlRaiseException, &record); + + if (have_vectored_api) + pRtlRemoveVectoredExceptionHandler(vectored_handler); + pNtCurrentTeb()->Tib.ExceptionList = frame.Prev; +} + +static void test_rtlraiseexception(void) +{ + if (!pRtlRaiseException) + { + skip("RtlRaiseException not found\n"); + return; + } + + /* test without debugger */ + run_rtlraiseexception_test(0x12345); + run_rtlraiseexception_test(EXCEPTION_BREAKPOINT); + run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); +} static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) @@ -180,24 +334,42 @@ static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *fram unsigned int i, entry = except - exceptions; got_exception++; - trace( "exception: %lx flags:%lx addr:%p\n", + trace( "exception: %x flags:%x addr:%p\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); ok( rec->ExceptionCode == except->status, - "%u: Wrong exception code %lx/%lx\n", entry, rec->ExceptionCode, except->status ); - ok( rec->ExceptionAddress == except->code + except->offset, + "%u: Wrong exception code %x/%x\n", entry, rec->ExceptionCode, except->status ); + ok( rec->ExceptionAddress == (char*)code_mem + except->offset, "%u: Wrong exception address %p/%p\n", entry, - rec->ExceptionAddress, except->code + except->offset ); + rec->ExceptionAddress, (char*)code_mem + except->offset ); ok( rec->NumberParameters == except->nb_params, - "%u: Wrong number of parameters %lu/%lu\n", entry, rec->NumberParameters, except->nb_params ); + "%u: Wrong number of parameters %u/%u\n", entry, rec->NumberParameters, except->nb_params ); + + /* Most CPUs (except Intel Core apparently) report a segment limit violation */ + /* instead of page faults for accesses beyond 0xffffffff */ + if (except->nb_params == 2 && except->params[1] >= 0xfffffffd) + { + if (rec->ExceptionInformation[0] == 0 && rec->ExceptionInformation[1] == 0xffffffff) + goto skip_params; + } + + /* Seems that both 0xbee8 and 0xfffffffff can be returned in windows */ + if (except->nb_params == 2 && rec->NumberParameters == 2 + && except->params[1] == 0xbee8 && rec->ExceptionInformation[1] == 0xffffffff + && except->params[0] == rec->ExceptionInformation[0]) + { + goto skip_params; + } + for (i = 0; i < rec->NumberParameters; i++) ok( rec->ExceptionInformation[i] == except->params[i], - "%u: Wrong parameter %d: %lx/%lx\n", + "%u: Wrong parameter %d: %lx/%x\n", entry, i, rec->ExceptionInformation[i], except->params[i] ); +skip_params: /* don't handle exception if it's not the address we expected */ - if (rec->ExceptionAddress != except->code + except->offset) return ExceptionContinueSearch; + if (rec->ExceptionAddress != (char*)code_mem + except->offset) return ExceptionContinueSearch; context->Eip += except->length; return ExceptionContinueExecution; @@ -206,28 +378,12 @@ static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *fram static void test_prot_fault(void) { unsigned int i; - struct - { - EXCEPTION_REGISTRATION_RECORD frame; - const struct exception *except; - } exc_frame; - pNtCurrentTeb = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtCurrentTeb" ); - if (!pNtCurrentTeb) - { - trace( "NtCurrentTeb not found, skipping tests\n" ); - return; - } - - exc_frame.frame.Handler = handler; - exc_frame.frame.Next = pNtCurrentTeb()->Tib.ExceptionList; - pNtCurrentTeb()->Tib.ExceptionList = &exc_frame.frame; for (i = 0; i < sizeof(exceptions)/sizeof(exceptions[0]); i++) { - void (*func)(void) = (void *)exceptions[i].code; - exc_frame.except = &exceptions[i]; got_exception = 0; - func(); + run_exception_test(handler, &exceptions[i], &exceptions[i].code, + sizeof(exceptions[i].code)); if (!i && !got_exception) { trace( "No exception, assuming win9x, no point in testing further\n" ); @@ -236,7 +392,439 @@ static void test_prot_fault(void) ok( got_exception == (exceptions[i].status != 0), "%u: bad exception count %d\n", i, got_exception ); } - pNtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Next; +} + +/* test handling of debug registers */ +static DWORD dreg_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ + context->Eip += 2; /* Skips the popl (%eax) */ + context->Dr0 = 0x42424242; + context->Dr1 = 0; + context->Dr2 = 0; + context->Dr3 = 0; + context->Dr6 = 0; + context->Dr7 = 0x155; + return ExceptionContinueExecution; +} + +static const BYTE segfault_code[5] = { + 0x31, 0xc0, /* xor %eax,%eax */ + 0x8f, 0x00, /* popl (%eax) - cause exception */ + 0xc3 /* ret */ +}; + +/* test the single step exception behaviour */ +static DWORD single_step_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ + got_exception++; + ok (!(context->EFlags & 0x100), "eflags has single stepping bit set\n"); + + if( got_exception < 3) + context->EFlags |= 0x100; /* single step until popf instruction */ + else { + /* show that the last single step exception on the popf instruction + * (which removed the TF bit), still is a EXCEPTION_SINGLE_STEP exception */ + ok( rec->ExceptionCode == EXCEPTION_SINGLE_STEP, + "exception is not EXCEPTION_SINGLE_STEP: %x\n", rec->ExceptionCode); + } + + return ExceptionContinueExecution; +} + +static const BYTE single_stepcode[] = { + 0x9c, /* pushf */ + 0x58, /* pop %eax */ + 0x0d,0,1,0,0, /* or $0x100,%eax */ + 0x50, /* push %eax */ + 0x9d, /* popf */ + 0x35,0,1,0,0, /* xor $0x100,%eax */ + 0x50, /* push %eax */ + 0x9d, /* popf */ + 0xc3 +}; + +/* Test the alignment check (AC) flag handling. */ +static const BYTE align_check_code[] = { + 0x55, /* push %ebp */ + 0x89,0xe5, /* mov %esp,%ebp */ + 0x9c, /* pushf */ + 0x58, /* pop %eax */ + 0x0d,0,0,4,0, /* or $0x40000,%eax */ + 0x50, /* push %eax */ + 0x9d, /* popf */ + 0x89,0xe0, /* mov %esp, %eax */ + 0x8b,0x40,0x1, /* mov 0x1(%eax), %eax - cause exception */ + 0x9c, /* pushf */ + 0x58, /* pop %eax */ + 0x35,0,0,4,0, /* xor $0x40000,%eax */ + 0x50, /* push %eax */ + 0x9d, /* popf */ + 0x5d, /* pop %ebp */ + 0xc3, /* ret */ +}; + +static DWORD align_check_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ + ok (!(context->EFlags & 0x40000), "eflags has AC bit set\n"); + got_exception++; + return ExceptionContinueExecution; +} + +/* Test the direction flag handling. */ +static const BYTE direction_flag_code[] = { + 0x55, /* push %ebp */ + 0x89,0xe5, /* mov %esp,%ebp */ + 0xfd, /* std */ + 0xfa, /* cli - cause exception */ + 0x5d, /* pop %ebp */ + 0xc3, /* ret */ +}; + +static DWORD direction_flag_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ +#ifdef __GNUC__ + unsigned int flags; + __asm__("pushfl; popl %0" : "=r" (flags) ); + /* older windows versions don't clear DF properly so don't test */ + if (flags & 0x400) trace( "eflags has DF bit set\n" ); +#endif + ok( context->EFlags & 0x400, "context eflags has DF bit cleared\n" ); + got_exception++; + context->Eip++; /* skip cli */ + return ExceptionContinueExecution; +} + +/* test single stepping over hardware breakpoint */ +static DWORD bpx_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ + got_exception++; + ok( rec->ExceptionCode == EXCEPTION_SINGLE_STEP, + "wrong exception code: %x\n", rec->ExceptionCode); + + if(got_exception == 1) { + /* hw bp exception on first nop */ + ok( context->Eip == (DWORD)code_mem, "eip is wrong: %x instead of %x\n", + context->Eip, (DWORD)code_mem); + ok( (context->Dr6 & 0xf) == 1, "B0 flag is not set in Dr6\n"); + ok( !(context->Dr6 & 0x4000), "BS flag is set in Dr6\n"); + context->Dr0 = context->Dr0 + 1; /* set hw bp again on next instruction */ + context->EFlags |= 0x100; /* enable single stepping */ + } else if( got_exception == 2) { + /* single step exception on second nop */ + ok( context->Eip == (DWORD)code_mem + 1, "eip is wrong: %x instead of %x\n", + context->Eip, (DWORD)code_mem + 1); + ok( (context->Dr6 & 0x4000), "BS flag is not set in Dr6\n"); + /* depending on the win version the B0 bit is already set here as well + ok( (context->Dr6 & 0xf) == 0, "B0...3 flags in Dr6 shouldn't be set\n"); */ + context->EFlags |= 0x100; + } else if( got_exception == 3) { + /* hw bp exception on second nop */ + ok( context->Eip == (DWORD)code_mem + 1, "eip is wrong: %x instead of %x\n", + context->Eip, (DWORD)code_mem + 1); + ok( (context->Dr6 & 0xf) == 1, "B0 flag is not set in Dr6\n"); + ok( !(context->Dr6 & 0x4000), "BS flag is set in Dr6\n"); + context->Dr0 = 0; /* clear breakpoint */ + context->EFlags |= 0x100; + } else { + /* single step exception on ret */ + ok( context->Eip == (DWORD)code_mem + 2, "eip is wrong: %x instead of %x\n", + context->Eip, (DWORD)code_mem + 2); + ok( (context->Dr6 & 0xf) == 0, "B0...3 flags in Dr6 shouldn't be set\n"); + ok( (context->Dr6 & 0x4000), "BS flag is not set in Dr6\n"); + } + + context->Dr6 = 0; /* clear status register */ + return ExceptionContinueExecution; +} + +static const BYTE dummy_code[] = { 0x90, 0x90, 0xc3 }; /* nop, nop, ret */ + +/* test int3 handling */ +static DWORD int3_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ + ok( rec->ExceptionAddress == code_mem, "exception address not at: %p, but at %p\n", + code_mem, rec->ExceptionAddress); + ok( context->Eip == (DWORD)code_mem, "eip not at: %p, but at %#x\n", code_mem, context->Eip); + if(context->Eip == (DWORD)code_mem) context->Eip++; /* skip breakpoint */ + + return ExceptionContinueExecution; +} + +static const BYTE int3_code[] = { 0xCC, 0xc3 }; /* int 3, ret */ + + +static void test_exceptions(void) +{ + CONTEXT ctx; + NTSTATUS res; + + if (!pNtGetContextThread || !pNtSetContextThread) + { + skip( "NtGetContextThread/NtSetContextThread not found\n" ); + return; + } + + /* test handling of debug registers */ + run_exception_test(dreg_handler, NULL, &segfault_code, sizeof(segfault_code)); + + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + res = pNtGetContextThread(GetCurrentThread(), &ctx); + ok (res == STATUS_SUCCESS,"NtGetContextThread failed with %x\n", res); + ok(ctx.Dr0 == 0x42424242,"failed to set debugregister 0 to 0x42424242, got %x\n", ctx.Dr0); + ok((ctx.Dr7 & ~0xdc00) == 0x155,"failed to set debugregister 7 to 0x155, got %x\n", ctx.Dr7); + + /* test single stepping behavior */ + got_exception = 0; + run_exception_test(single_step_handler, NULL, &single_stepcode, sizeof(single_stepcode)); + ok(got_exception == 3, "expected 3 single step exceptions, got %d\n", got_exception); + + /* test alignment exceptions */ + got_exception = 0; + run_exception_test(align_check_handler, NULL, align_check_code, sizeof(align_check_code)); + ok(got_exception == 0, "got %d alignment faults, expected 0\n", got_exception); + + /* test direction flag */ + got_exception = 0; + run_exception_test(direction_flag_handler, NULL, direction_flag_code, sizeof(direction_flag_code)); + ok(got_exception == 1, "got %d exceptions, expected 1\n", got_exception); + + /* test single stepping over hardware breakpoint */ + memset(&ctx, 0, sizeof(ctx)); + ctx.Dr0 = (DWORD) code_mem; /* set hw bp on first nop */ + ctx.Dr7 = 3; + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + res = pNtSetContextThread( GetCurrentThread(), &ctx); + ok( res == STATUS_SUCCESS, "NtSetContextThread faild with %x\n", res); + + got_exception = 0; + run_exception_test(bpx_handler, NULL, dummy_code, sizeof(dummy_code)); + ok( got_exception == 4,"expected 4 exceptions, got %d\n", got_exception); + + /* test int3 handling */ + run_exception_test(int3_handler, NULL, int3_code, sizeof(int3_code)); +} + +static void test_debugger(void) +{ + char cmdline[MAX_PATH]; + PROCESS_INFORMATION pi; + STARTUPINFO si = { 0 }; + DEBUG_EVENT de; + DWORD continuestatus; + PVOID code_mem_address = NULL; + NTSTATUS status; + SIZE_T size_read; + BOOL ret; + int counter = 0; + si.cb = sizeof(si); + + if(!pNtGetContextThread || !pNtSetContextThread || !pNtReadVirtualMemory || !pNtTerminateProcess) + { + skip("NtGetContextThread, NtSetContextThread, NtReadVirtualMemory or NtTerminateProcess not found\n)"); + return; + } + + sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage); + ret = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); + ok(ret, "could not create child process error: %u\n", GetLastError()); + if (!ret) + return; + + do + { + continuestatus = DBG_CONTINUE; + ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); + + if (de.dwThreadId != pi.dwThreadId) + { + trace("event %d not coming from main thread, ignoring\n", de.dwDebugEventCode); + ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE); + continue; + } + + if (de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) + { + if(de.u.CreateProcessInfo.lpBaseOfImage != pNtCurrentTeb()->Peb->ImageBaseAddress) + { + skip("child process loaded at different address, terminating it\n"); + pNtTerminateProcess(pi.hProcess, 0); + } + } + else if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) + { + CONTEXT ctx; + int stage; + + counter++; + status = pNtReadVirtualMemory(pi.hProcess, &code_mem, &code_mem_address, + sizeof(code_mem_address), &size_read); + ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status); + status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, + sizeof(stage), &size_read); + ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status); + + ctx.ContextFlags = CONTEXT_FULL; + status = pNtGetContextThread(pi.hThread, &ctx); + ok(!status, "NtGetContextThread failed with 0x%x\n", status); + + trace("exception 0x%x at %p firstchance=%d Eip=0x%x, Eax=0x%x\n", + de.u.Exception.ExceptionRecord.ExceptionCode, + de.u.Exception.ExceptionRecord.ExceptionAddress, de.u.Exception.dwFirstChance, ctx.Eip, ctx.Eax); + + if (counter > 100) + { + ok(FALSE, "got way too many exceptions, probaby caught in a infinite loop, terminating child\n"); + pNtTerminateProcess(pi.hProcess, 1); + } + else if (counter >= 2) /* skip startup breakpoint */ + { + if (stage == 1) + { + ok((char *)ctx.Eip == (char *)code_mem_address + 0xb, "Eip at %x instead of %p\n", + ctx.Eip, (char *)code_mem_address + 0xb); + /* setting the context from debugger does not affect the context, the exception handlers gets */ + /* uncomment once wine is fixed */ + /* ctx.Eip = 0x12345; */ + ctx.Eax = 0xf00f00f1; + + /* let the debuggee handle the exception */ + continuestatus = DBG_EXCEPTION_NOT_HANDLED; + } + else if (stage == 2) + { + if (de.u.Exception.dwFirstChance) + { + /* debugger gets first chance exception with unmodified ctx.Eip */ + ok((char *)ctx.Eip == (char *)code_mem_address + 0xb, "Eip at 0x%x instead of %p\n", + ctx.Eip, (char *)code_mem_address + 0xb); + + /* setting the context from debugger does not affect the context, the exception handlers gets */ + /* uncomment once wine is fixed */ + /* ctx.Eip = 0x12345; */ + ctx.Eax = 0xf00f00f1; + + /* pass exception to debuggee + * exception will not be handled and + * a second chance exception will be raised */ + continuestatus = DBG_EXCEPTION_NOT_HANDLED; + } + else + { + /* debugger gets context after exception handler has played with it */ + /* ctx.Eip is the same value the exception handler got */ + if (de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) + { + ok((char *)ctx.Eip == (char *)code_mem_address + 0xa, "Eip at 0x%x instead of %p\n", + ctx.Eip, (char *)code_mem_address + 0xa); + /* need to fixup Eip for debuggee */ + if ((char *)ctx.Eip == (char *)code_mem_address + 0xa) + ctx.Eip += 1; + } + else + ok((char *)ctx.Eip == (char *)code_mem_address + 0xb, "Eip at 0x%x instead of %p\n", + ctx.Eip, (char *)code_mem_address + 0xb); + /* here we handle exception */ + } + } + else + ok(FALSE, "unexpected stage %x\n", stage); + + status = pNtSetContextThread(pi.hThread, &ctx); + ok(!status, "NtSetContextThread failed with 0x%x\n", status); + } + } + + ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus); + + } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT); + + winetest_wait_child_process( pi.hProcess ); + ok(CloseHandle(pi.hThread) != 0, "error %u\n", GetLastError()); + ok(CloseHandle(pi.hProcess) != 0, "error %u\n", GetLastError()); + + return; +} + +static DWORD simd_fault_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ + int *stage = *(int **)(frame + 1); + + got_exception++; + + if( *stage == 1) { + /* fault while executing sse instruction */ + context->Eip += 3; /* skip addps */ + return ExceptionContinueExecution; + } + + /* stage 2 - divide by zero fault */ + if( rec->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) + skip("system doesn't support SIMD exceptions\n"); + else { + ok( rec->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS, + "exception code: %#x, should be %#x\n", + rec->ExceptionCode, STATUS_FLOAT_MULTIPLE_TRAPS); + ok( rec->NumberParameters == 1, "# of params: %i, should be 1\n", + rec->NumberParameters); + if( rec->NumberParameters == 1 ) + ok( rec->ExceptionInformation[0] == 0, "param #1: %lx, should be 0\n", rec->ExceptionInformation[0]); + } + + context->Eip += 3; /* skip divps */ + + return ExceptionContinueExecution; +} + +static const BYTE simd_exception_test[] = { + 0x83, 0xec, 0x4, /* sub $0x4, %esp */ + 0x0f, 0xae, 0x1c, 0x24, /* stmxcsr (%esp) */ + 0x66, 0x81, 0x24, 0x24, 0xff, 0xfd, /* andw $0xfdff,(%esp) * enable divide by */ + 0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) * zero exceptions */ + 0x6a, 0x01, /* push $0x1 */ + 0x6a, 0x01, /* push $0x1 */ + 0x6a, 0x01, /* push $0x1 */ + 0x6a, 0x01, /* push $0x1 */ + 0x0f, 0x10, 0x0c, 0x24, /* movups (%esp),%xmm1 * fill dividend */ + 0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 * clear divisor */ + 0x0f, 0x5e, 0xc8, /* divps %xmm0,%xmm1 * generate fault */ + 0x83, 0xc4, 0x10, /* add $0x10,%esp */ + 0x66, 0x81, 0x0c, 0x24, 0x00, 0x02, /* orw $0x200,(%esp) * disable exceptions */ + 0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) */ + 0x83, 0xc4, 0x04, /* add $0x4,%esp */ + 0xc3, /* ret */ +}; + +static const BYTE sse_check[] = { + 0x0f, 0x58, 0xc8, /* addps %xmm0,%xmm1 */ + 0xc3, /* ret */ +}; + +static void test_simd_exceptions(void) +{ + int stage; + + /* test if CPU & OS can do sse */ + stage = 1; + got_exception = 0; + run_exception_test(simd_fault_handler, &stage, sse_check, sizeof(sse_check)); + if(got_exception) { + skip("system doesn't support SSE\n"); + return; + } + + /* generate a SIMD exception */ + stage = 2; + got_exception = 0; + run_exception_test(simd_fault_handler, &stage, simd_exception_test, + sizeof(simd_exception_test)); + ok( got_exception == 1, "got exception: %i, should be 1\n", got_exception); } #endif /* __i386__ */ @@ -244,6 +832,79 @@ static void test_prot_fault(void) START_TEST(exception) { #ifdef __i386__ + HMODULE hntdll = GetModuleHandleA("ntdll.dll"); + + pNtCurrentTeb = (void *)GetProcAddress( hntdll, "NtCurrentTeb" ); + pNtGetContextThread = (void *)GetProcAddress( hntdll, "NtGetContextThread" ); + pNtSetContextThread = (void *)GetProcAddress( hntdll, "NtSetContextThread" ); + pNtReadVirtualMemory = (void *)GetProcAddress( hntdll, "NtReadVirtualMemory" ); + pRtlRaiseException = (void *)GetProcAddress( hntdll, "RtlRaiseException" ); + pNtTerminateProcess = (void *)GetProcAddress( hntdll, "NtTerminateProcess" ); + pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll, + "RtlAddVectoredExceptionHandler" ); + pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll, + "RtlRemoveVectoredExceptionHandler" ); + if (!pNtCurrentTeb) + { + skip( "NtCurrentTeb not found\n" ); + return; + } + + if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler) + have_vectored_api = TRUE; + else + skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n"); + + /* 1024 byte should be sufficient */ + code_mem = VirtualAlloc(NULL, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(!code_mem) { + trace("VirtualAlloc failed\n"); + return; + } + + my_argc = winetest_get_mainargs( &my_argv ); + if (my_argc >= 4) + { + void *addr; + sscanf( my_argv[3], "%p", &addr ); + + if (addr != &test_stage) + { + skip( "child process not mapped at same address (%p/%p)\n", &test_stage, addr); + return; + } + + /* child must be run under a debugger */ + if (!pNtCurrentTeb()->Peb->BeingDebugged) + { + ok(FALSE, "child process not being debugged?\n"); + return; + } + + if (pRtlRaiseException) + { + test_stage = 1; + run_rtlraiseexception_test(0x12345); + run_rtlraiseexception_test(EXCEPTION_BREAKPOINT); + run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); + test_stage = 2; + run_rtlraiseexception_test(0x12345); + run_rtlraiseexception_test(EXCEPTION_BREAKPOINT); + run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); + } + else + skip( "RtlRaiseException not found\n" ); + + /* rest of tests only run in parent */ + return; + } + test_prot_fault(); + test_exceptions(); + test_rtlraiseexception(); + test_debugger(); + test_simd_exceptions(); + + VirtualFree(code_mem, 1024, MEM_RELEASE); #endif } diff --git a/rostests/winetests/ntdll/file.c b/rostests/winetests/ntdll/file.c new file mode 100644 index 00000000000..6d37390f0b9 --- /dev/null +++ b/rostests/winetests/ntdll/file.c @@ -0,0 +1,627 @@ +/* Unit test suite for Ntdll file functions + * + * Copyright 2007 Jeff Latimer + * Copyright 2007 Andrey Turkin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * NOTES + * We use function pointers here as there is no import library for NTDLL on + * windows. + */ + +#include +#include + +#include "ntstatus.h" + +/* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro + * definition errors when we get to winnt.h + */ +#define WIN32_NO_STATUS + +#include "wine/test.h" +#include "winternl.h" + +#ifndef IO_COMPLETION_ALL_ACCESS +#define IO_COMPLETION_ALL_ACCESS 0x001F0003 +#endif + +static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR ); +static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, + ULONG, ULONG, ULONG, PLARGE_INTEGER ); +static NTSTATUS (WINAPI *pNtReadFile)(HANDLE hFile, HANDLE hEvent, + PIO_APC_ROUTINE apc, void* apc_user, + PIO_STATUS_BLOCK io_status, void* buffer, ULONG length, + PLARGE_INTEGER offset, PULONG key); +static NTSTATUS (WINAPI *pNtWriteFile)(HANDLE hFile, HANDLE hEvent, + PIO_APC_ROUTINE apc, void* apc_user, + PIO_STATUS_BLOCK io_status, + const void* buffer, ULONG length, + PLARGE_INTEGER offset, PULONG key); +static NTSTATUS (WINAPI *pNtClose)( PHANDLE ); + +static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG); +static NTSTATUS (WINAPI *pNtOpenIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); +static NTSTATUS (WINAPI *pNtQueryIoCompletion)(HANDLE, IO_COMPLETION_INFORMATION_CLASS, PVOID, ULONG, PULONG); +static NTSTATUS (WINAPI *pNtRemoveIoCompletion)(HANDLE, PULONG_PTR, PULONG_PTR, PIO_STATUS_BLOCK, PLARGE_INTEGER); +static NTSTATUS (WINAPI *pNtSetIoCompletion)(HANDLE, ULONG_PTR, ULONG_PTR, NTSTATUS, ULONG); +static NTSTATUS (WINAPI *pNtSetInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS); + +static inline BOOL is_signaled( HANDLE obj ) +{ + return WaitForSingleObject( obj, 0 ) == 0; +} + +#define PIPENAME "\\\\.\\pipe\\ntdll_tests_file.c" + +static BOOL create_pipe( HANDLE *read, HANDLE *write, ULONG flags, ULONG size ) +{ + *read = CreateNamedPipe(PIPENAME, PIPE_ACCESS_INBOUND | flags, PIPE_TYPE_BYTE | PIPE_WAIT, + 1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(*read != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + + *write = CreateFileA(PIPENAME, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(*write != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); + + return TRUE; +} + +static HANDLE create_temp_file( ULONG flags ) +{ + char buffer[MAX_PATH]; + HANDLE handle; + + GetTempFileNameA( ".", "foo", 0, buffer ); + handle = CreateFileA(buffer, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + flags | FILE_FLAG_DELETE_ON_CLOSE, 0); + ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + return (handle == INVALID_HANDLE_VALUE) ? 0 : handle; +} + +#define CVALUE_FIRST 0xfffabbcc +#define CKEY_FIRST 0x1030341 +#define CKEY_SECOND 0x132E46 + +ULONG_PTR completionKey; +IO_STATUS_BLOCK ioSb; +ULONG_PTR completionValue; + +static long get_pending_msgs(HANDLE h) +{ + NTSTATUS res; + ULONG a, req; + + res = pNtQueryIoCompletion( h, IoCompletionBasicInformation, (PVOID)&a, sizeof(a), &req ); + ok( res == STATUS_SUCCESS, "NtQueryIoCompletion failed: %x\n", res ); + if (res != STATUS_SUCCESS) return -1; + ok( req == sizeof(a), "Unexpected response size: %x\n", req ); + return a; +} + +static BOOL get_msg(HANDLE h) +{ + LARGE_INTEGER timeout = {{-10000000*3}}; + DWORD res = pNtRemoveIoCompletion( h, &completionKey, &completionValue, &ioSb, &timeout); + ok( res == STATUS_SUCCESS, "NtRemoveIoCompletion failed: %x\n", res ); + if (res != STATUS_SUCCESS) + { + completionKey = completionValue = 0; + memset(&ioSb, 0, sizeof(ioSb)); + return FALSE; + } + return TRUE; +} + + +static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved ) +{ + int *count = arg; + + trace( "apc called block %p iosb.status %x iosb.info %lu\n", + iosb, U(*iosb).Status, iosb->Information ); + (*count)++; + ok( !reserved, "reserved is not 0: %x\n", reserved ); +} + +static void read_file_test(void) +{ + const char text[] = "foobar"; + HANDLE handle, read, write; + NTSTATUS status; + IO_STATUS_BLOCK iosb; + DWORD written; + int apc_count = 0; + char buffer[128]; + LARGE_INTEGER offset; + HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL ); + + buffer[0] = 1; + + if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; + + /* try read with no data */ + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + ok( is_signaled( read ), "read handle is not signaled\n" ); + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( read ), "read handle is signaled\n" ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + WriteFile( write, buffer, 1, &written, NULL ); + /* iosb updated here by async i/o */ + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); + ok( !is_signaled( read ), "read handle is signaled\n" ); + ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + apc_count = 0; + SleepEx( 1, FALSE ); /* non-alertable sleep */ + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc not called\n" ); + + /* with no event, the pipe handle itself gets signaled */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + ok( !is_signaled( read ), "read handle is not signaled\n" ); + status = pNtReadFile( read, 0, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( read ), "read handle is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + WriteFile( write, buffer, 1, &written, NULL ); + /* iosb updated here by async i/o */ + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( read ), "read handle is signaled\n" ); + ok( !apc_count, "apc was called\n" ); + apc_count = 0; + SleepEx( 1, FALSE ); /* non-alertable sleep */ + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc not called\n" ); + + /* now read with data ready */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + ResetEvent( event ); + WriteFile( write, buffer, 1, &written, NULL ); + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); + ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, FALSE ); /* non-alertable sleep */ + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc not called\n" ); + + /* try read with no data */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + ok( is_signaled( event ), "event is not signaled\n" ); /* check that read resets the event */ + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + WriteFile( write, buffer, 1, &written, NULL ); + /* partial read is good enough */ + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + + /* read from disconnected pipe */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + CloseHandle( write ); + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + ok( status == STATUS_PIPE_BROKEN, "wrong status %x\n", status ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( !apc_count, "apc was called\n" ); + CloseHandle( read ); + + /* read from closed handle */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + SetEvent( event ); + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is signaled\n" ); /* not reset on invalid handle */ + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( !apc_count, "apc was called\n" ); + + /* disconnect while async read is in progress */ + if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + CloseHandle( write ); + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == STATUS_PIPE_BROKEN, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + CloseHandle( read ); + + /* now try a real file */ + if (!(handle = create_temp_file( FILE_FLAG_OVERLAPPED ))) return; + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + offset.QuadPart = 0; + ResetEvent( event ); + pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + offset.QuadPart = 0; + ResetEvent( event ); + status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, strlen(text) + 10, &offset, NULL ); + ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); + ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + + /* read beyond eof */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + offset.QuadPart = strlen(text) + 2; + status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL ); + ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( !apc_count, "apc was called\n" ); + CloseHandle( handle ); + + /* now a non-overlapped file */ + if (!(handle = create_temp_file(0))) return; + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + offset.QuadPart = 0; + pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL ); + ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status ); + ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + offset.QuadPart = 0; + ResetEvent( event ); + status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, strlen(text) + 10, &offset, NULL ); + ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); + ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + todo_wine ok( !apc_count, "apc was called\n" ); + + /* read beyond eof */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + offset.QuadPart = strlen(text) + 2; + ResetEvent( event ); + status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL ); + ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status ); + todo_wine ok( U(iosb).Status == STATUS_END_OF_FILE, "wrong status %x\n", U(iosb).Status ); + todo_wine ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + todo_wine ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( !apc_count, "apc was called\n" ); + + CloseHandle( handle ); + + CloseHandle( event ); +} + +static void nt_mailslot_test(void) +{ + HANDLE hslot; + ACCESS_MASK DesiredAccess; + OBJECT_ATTRIBUTES attr; + + ULONG CreateOptions; + ULONG MailslotQuota; + ULONG MaxMessageSize; + LARGE_INTEGER TimeOut; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS rc; + UNICODE_STRING str; + WCHAR buffer1[] = { '\\','?','?','\\','M','A','I','L','S','L','O','T','\\', + 'R',':','\\','F','R','E','D','\0' }; + + TimeOut.QuadPart = -1; + + pRtlInitUnicodeString(&str, buffer1); + InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL); + DesiredAccess = CreateOptions = MailslotQuota = MaxMessageSize = 0; + + /* + * Check for NULL pointer handling + */ + rc = pNtCreateMailslotFile(NULL, DesiredAccess, + &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize, + &TimeOut); + ok( rc == STATUS_ACCESS_VIOLATION, "rc = %x not c0000005 STATUS_ACCESS_VIOLATION\n", rc); + + /* + * Test to see if the Timeout can be NULL + */ + rc = pNtCreateMailslotFile(&hslot, DesiredAccess, + &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize, + NULL); + ok( rc == STATUS_SUCCESS, "rc = %x not STATUS_SUCCESS\n", rc); + ok( hslot != 0, "Handle is invalid\n"); + + if ( rc == STATUS_SUCCESS ) rc = pNtClose(hslot); + + /* + * Test that the length field is checked properly + */ + attr.Length = 0; + rc = pNtCreateMailslotFile(&hslot, DesiredAccess, + &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize, + &TimeOut); + todo_wine ok( rc == STATUS_INVALID_PARAMETER, "rc = %x not c000000d STATUS_INVALID_PARAMETER\n", rc); + + if (rc == STATUS_SUCCESS) pNtClose(hslot); + + attr.Length = sizeof(OBJECT_ATTRIBUTES)+1; + rc = pNtCreateMailslotFile(&hslot, DesiredAccess, + &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize, + &TimeOut); + todo_wine ok( rc == STATUS_INVALID_PARAMETER, "rc = %x not c000000d STATUS_INVALID_PARAMETER\n", rc); + + if (rc == STATUS_SUCCESS) pNtClose(hslot); + + /* + * Test handling of a NULL unicode string in ObjectName + */ + InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL); + attr.ObjectName = NULL; + rc = pNtCreateMailslotFile(&hslot, DesiredAccess, + &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize, + &TimeOut); + ok( rc == STATUS_OBJECT_PATH_SYNTAX_BAD, "rc = %x not c000003b STATUS_OBJECT_PATH_SYNTAX_BAD\n", rc); + + if (rc == STATUS_SUCCESS) pNtClose(hslot); + + /* + * Test a valid call + */ + InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL); + rc = pNtCreateMailslotFile(&hslot, DesiredAccess, + &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize, + &TimeOut); + ok( rc == STATUS_SUCCESS, "Create MailslotFile failed rc = %x %u\n", rc, GetLastError()); + ok( hslot != 0, "Handle is invalid\n"); + + rc = pNtClose(hslot); + ok( rc == STATUS_SUCCESS, "NtClose failed\n"); +} + +static void test_iocp_setcompletion(HANDLE h) +{ + NTSTATUS res; + long count; + + res = pNtSetIoCompletion( h, CKEY_FIRST, CVALUE_FIRST, STATUS_INVALID_DEVICE_REQUEST, 3 ); + ok( res == STATUS_SUCCESS, "NtSetIoCompletion failed: %x\n", res ); + + count = get_pending_msgs(h); + ok( count == 1, "Unexpected msg count: %ld\n", count ); + + if (get_msg(h)) + { + ok( completionKey == CKEY_FIRST, "Invalid completion key: %lx\n", completionKey ); + ok( ioSb.Information == 3, "Invalid ioSb.Information: %ld\n", ioSb.Information ); + ok( U(ioSb).Status == STATUS_INVALID_DEVICE_REQUEST, "Invalid ioSb.Status: %x\n", U(ioSb).Status); + ok( completionValue == CVALUE_FIRST, "Invalid completion value: %lx\n", completionValue ); + } + + count = get_pending_msgs(h); + ok( !count, "Unexpected msg count: %ld\n", count ); +} + +static void test_iocp_fileio(HANDLE h) +{ + static const char pipe_name[] = "\\\\.\\pipe\\iocompletiontestnamedpipe"; + + IO_STATUS_BLOCK iosb; + FILE_COMPLETION_INFORMATION fci = {h, CKEY_SECOND}; + HANDLE hPipeSrv, hPipeClt; + NTSTATUS res; + + hPipeSrv = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, 1000, NULL ); + ok( hPipeSrv != INVALID_HANDLE_VALUE, "Cannot create named pipe\n" ); + if (hPipeSrv != INVALID_HANDLE_VALUE ) + { + hPipeClt = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL ); + ok( hPipeClt != INVALID_HANDLE_VALUE, "Cannot connect to pipe\n" ); + if (hPipeClt != INVALID_HANDLE_VALUE) + { + res = pNtSetInformationFile( hPipeSrv, &iosb, &fci, sizeof(fci), FileCompletionInformation ); + ok( res == STATUS_INVALID_PARAMETER, "Unexpected NtSetInformationFile on non-overlapped handle: %x\n", res ); + CloseHandle(hPipeClt); + } + CloseHandle( hPipeSrv ); + } + + hPipeSrv = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, 1000, NULL ); + ok( hPipeSrv != INVALID_HANDLE_VALUE, "Cannot create named pipe\n" ); + if (hPipeSrv == INVALID_HANDLE_VALUE ) + return; + + hPipeClt = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL ); + ok( hPipeClt != INVALID_HANDLE_VALUE, "Cannot connect to pipe\n" ); + if (hPipeClt != INVALID_HANDLE_VALUE) + { + OVERLAPPED o = {0,}; + BYTE buf[3]; + DWORD read; + long count; + + NTSTATUS res = pNtSetInformationFile( hPipeSrv, &iosb, &fci, sizeof(fci), FileCompletionInformation ); + ok( res == STATUS_SUCCESS, "NtSetInformationFile failed: %x\n", res ); + ok( U(iosb).Status == STATUS_SUCCESS, "iosb.Status invalid: %x\n", U(iosb).Status ); + + count = get_pending_msgs(h); + ok( !count, "Unexpected msg count: %ld\n", count ); + ReadFile( hPipeSrv, buf, 3, &read, &o); + count = get_pending_msgs(h); + ok( !count, "Unexpected msg count: %ld\n", count ); + WriteFile( hPipeClt, buf, 3, &read, NULL ); + + if (get_msg(h)) + { + ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey ); + ok( ioSb.Information == 3, "Invalid ioSb.Information: %ld\n", ioSb.Information ); + ok( U(ioSb).Status == STATUS_SUCCESS, "Invalid ioSb.Status: %x\n", U(ioSb).Status); + ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue ); + } + count = get_pending_msgs(h); + ok( !count, "Unexpected msg count: %ld\n", count ); + + WriteFile( hPipeClt, buf, 2, &read, NULL ); + count = get_pending_msgs(h); + ok( !count, "Unexpected msg count: %ld\n", count ); + ReadFile( hPipeSrv, buf, 2, &read, &o); + count = get_pending_msgs(h); + ok( count == 1, "Unexpected msg count: %ld\n", count ); + if (get_msg(h)) + { + ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey ); + ok( ioSb.Information == 2, "Invalid ioSb.Information: %ld\n", ioSb.Information ); + ok( U(ioSb).Status == STATUS_SUCCESS, "Invalid ioSb.Status: %x\n", U(ioSb).Status); + ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue ); + } + + ReadFile( hPipeSrv, buf, sizeof(buf), &read, &o); + CloseHandle( hPipeSrv ); + count = get_pending_msgs(h); + ok( count == 1, "Unexpected msg count: %ld\n", count ); + if (get_msg(h)) + { + ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey ); + ok( ioSb.Information == 0, "Invalid ioSb.Information: %ld\n", ioSb.Information ); + /* wine sends wrong status here */ + todo_wine ok( U(ioSb).Status == STATUS_PIPE_BROKEN, "Invalid ioSb.Status: %x\n", U(ioSb).Status); + ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue ); + } + } + + CloseHandle( hPipeClt ); +} + +static void test_iocompletion(void) +{ + HANDLE h = INVALID_HANDLE_VALUE; + NTSTATUS res; + + res = pNtCreateIoCompletion( &h, IO_COMPLETION_ALL_ACCESS, NULL, 0); + + ok( res == 0, "NtCreateIoCompletion anonymous failed: %x\n", res ); + ok( h && h != INVALID_HANDLE_VALUE, "Invalid handle returned\n" ); + + if ( h && h != INVALID_HANDLE_VALUE) + { + test_iocp_setcompletion(h); + test_iocp_fileio(h); + pNtClose(h); + } +} + +START_TEST(file) +{ + HMODULE hntdll = GetModuleHandleA("ntdll.dll"); + if (!hntdll) + { + skip("not running on NT, skipping test\n"); + return; + } + + pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); + pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile"); + pNtReadFile = (void *)GetProcAddress(hntdll, "NtReadFile"); + pNtWriteFile = (void *)GetProcAddress(hntdll, "NtWriteFile"); + pNtClose = (void *)GetProcAddress(hntdll, "NtClose"); + pNtCreateIoCompletion = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion"); + pNtOpenIoCompletion = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion"); + pNtQueryIoCompletion = (void *)GetProcAddress(hntdll, "NtQueryIoCompletion"); + pNtRemoveIoCompletion = (void *)GetProcAddress(hntdll, "NtRemoveIoCompletion"); + pNtSetIoCompletion = (void *)GetProcAddress(hntdll, "NtSetIoCompletion"); + pNtSetInformationFile = (void *)GetProcAddress(hntdll, "NtSetInformationFile"); + + read_file_test(); + nt_mailslot_test(); + test_iocompletion(); +} diff --git a/rostests/winetests/ntdll/generated.c b/rostests/winetests/ntdll/generated.c index 6ac1749d301..4818c9e50eb 100755 --- a/rostests/winetests/ntdll/generated.c +++ b/rostests/winetests/ntdll/generated.c @@ -16,7 +16,7 @@ #include "wine/test.h" /*********************************************************************** - * Compability macros + * Compatibility macros */ #define DWORD_PTR UINT_PTR @@ -635,48 +635,8 @@ static void test_pack_IMAGE_LOAD_CONFIG_DIRECTORY(void) static void test_pack_IMAGE_NT_HEADERS(void) { - /* IMAGE_NT_HEADERS (pack 4) */ + /* IMAGE_NT_HEADERS */ TEST_TYPE(IMAGE_NT_HEADERS, 248, 4); - TEST_FIELD(IMAGE_NT_HEADERS, DWORD, Signature, 0, 4, 4); - TEST_FIELD(IMAGE_NT_HEADERS, IMAGE_FILE_HEADER, FileHeader, 4, 20, 4); - TEST_FIELD(IMAGE_NT_HEADERS, IMAGE_OPTIONAL_HEADER, OptionalHeader, 24, 224, 4); -} - -static void test_pack_IMAGE_OPTIONAL_HEADER(void) -{ - /* IMAGE_OPTIONAL_HEADER (pack 4) */ - TEST_TYPE(IMAGE_OPTIONAL_HEADER, 224, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, WORD, Magic, 0, 2, 2); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, BYTE, MajorLinkerVersion, 2, 1, 1); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, BYTE, MinorLinkerVersion, 3, 1, 1); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, SizeOfCode, 4, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, SizeOfInitializedData, 8, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, SizeOfUninitializedData, 12, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, AddressOfEntryPoint, 16, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, BaseOfCode, 20, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, BaseOfData, 24, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, ImageBase, 28, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, SectionAlignment, 32, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, FileAlignment, 36, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, WORD, MajorOperatingSystemVersion, 40, 2, 2); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, WORD, MinorOperatingSystemVersion, 42, 2, 2); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, WORD, MajorImageVersion, 44, 2, 2); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, WORD, MinorImageVersion, 46, 2, 2); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, WORD, MajorSubsystemVersion, 48, 2, 2); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, WORD, MinorSubsystemVersion, 50, 2, 2); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, Win32VersionValue, 52, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, SizeOfImage, 56, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, SizeOfHeaders, 60, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, CheckSum, 64, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, WORD, Subsystem, 68, 2, 2); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, WORD, DllCharacteristics, 70, 2, 2); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, SizeOfStackReserve, 72, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, SizeOfStackCommit, 76, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, SizeOfHeapReserve, 80, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, SizeOfHeapCommit, 84, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, LoaderFlags, 88, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, DWORD, NumberOfRvaAndSizes, 92, 4, 4); - TEST_FIELD(IMAGE_OPTIONAL_HEADER, IMAGE_DATA_DIRECTORY[IMAGE_NUMBEROF_DIRECTORY_ENTRIES], DataDirectory, 96, 128, 4); } static void test_pack_IMAGE_OS2_HEADER(void) @@ -795,19 +755,13 @@ static void test_pack_IMAGE_SYMBOL(void) static void test_pack_IMAGE_THUNK_DATA(void) { - /* IMAGE_THUNK_DATA (pack 4) */ + /* IMAGE_THUNK_DATA */ } static void test_pack_IMAGE_TLS_DIRECTORY(void) { - /* IMAGE_TLS_DIRECTORY (pack 4) */ + /* IMAGE_TLS_DIRECTORY */ TEST_TYPE(IMAGE_TLS_DIRECTORY, 24, 4); - TEST_FIELD(IMAGE_TLS_DIRECTORY, DWORD, StartAddressOfRawData, 0, 4, 4); - TEST_FIELD(IMAGE_TLS_DIRECTORY, DWORD, EndAddressOfRawData, 4, 4, 4); - TEST_FIELD(IMAGE_TLS_DIRECTORY, LPDWORD, AddressOfIndex, 8, 4, 4); - TEST_FIELD(IMAGE_TLS_DIRECTORY, PIMAGE_TLS_CALLBACK *, AddressOfCallBacks, 12, 4, 4); - TEST_FIELD(IMAGE_TLS_DIRECTORY, DWORD, SizeOfZeroFill, 16, 4, 4); - TEST_FIELD(IMAGE_TLS_DIRECTORY, DWORD, Characteristics, 20, 4, 4); } static void test_pack_IMAGE_VXD_HEADER(void) @@ -920,12 +874,6 @@ static void test_pack_LONGLONG(void) TEST_TYPE_SIGNED(LONGLONG); } -static void test_pack_LPTOP_LEVEL_EXCEPTION_FILTER(void) -{ - /* LPTOP_LEVEL_EXCEPTION_FILTER */ - TEST_TYPE(LPTOP_LEVEL_EXCEPTION_FILTER, 4, 4); -} - static void test_pack_LUID(void) { /* LUID (pack 4) */ @@ -949,7 +897,7 @@ static void test_pack_MEMORY_BASIC_INFORMATION(void) TEST_FIELD(MEMORY_BASIC_INFORMATION, LPVOID, BaseAddress, 0, 4, 4); TEST_FIELD(MEMORY_BASIC_INFORMATION, LPVOID, AllocationBase, 4, 4, 4); TEST_FIELD(MEMORY_BASIC_INFORMATION, DWORD, AllocationProtect, 8, 4, 4); - TEST_FIELD(MEMORY_BASIC_INFORMATION, DWORD, RegionSize, 12, 4, 4); + TEST_FIELD(MEMORY_BASIC_INFORMATION, SIZE_T, RegionSize, 12, 4, 4); TEST_FIELD(MEMORY_BASIC_INFORMATION, DWORD, State, 16, 4, 4); TEST_FIELD(MEMORY_BASIC_INFORMATION, DWORD, Protect, 20, 4, 4); TEST_FIELD(MEMORY_BASIC_INFORMATION, DWORD, Type, 24, 4, 4); @@ -1250,14 +1198,12 @@ static void test_pack_PIMAGE_NT_HEADERS(void) { /* PIMAGE_NT_HEADERS */ TEST_TYPE(PIMAGE_NT_HEADERS, 4, 4); - TEST_TYPE_POINTER(PIMAGE_NT_HEADERS, 248, 4); } static void test_pack_PIMAGE_OPTIONAL_HEADER(void) { /* PIMAGE_OPTIONAL_HEADER */ TEST_TYPE(PIMAGE_OPTIONAL_HEADER, 4, 4); - TEST_TYPE_POINTER(PIMAGE_OPTIONAL_HEADER, 224, 4); } static void test_pack_PIMAGE_OS2_HEADER(void) @@ -1342,7 +1288,6 @@ static void test_pack_PIMAGE_TLS_DIRECTORY(void) { /* PIMAGE_TLS_DIRECTORY */ TEST_TYPE(PIMAGE_TLS_DIRECTORY, 4, 4); - TEST_TYPE_POINTER(PIMAGE_TLS_DIRECTORY, 24, 4); } static void test_pack_PIMAGE_VXD_HEADER(void) @@ -1482,7 +1427,6 @@ static void test_pack_PRTL_CRITICAL_SECTION_DEBUG(void) { /* PRTL_CRITICAL_SECTION_DEBUG */ TEST_TYPE(PRTL_CRITICAL_SECTION_DEBUG, 4, 4); - TEST_TYPE_POINTER(PRTL_CRITICAL_SECTION_DEBUG, 32, 4); } static void test_pack_PRTL_OSVERSIONINFOEXW(void) @@ -1503,7 +1447,6 @@ static void test_pack_PRTL_RESOURCE_DEBUG(void) { /* PRTL_RESOURCE_DEBUG */ TEST_TYPE(PRTL_RESOURCE_DEBUG, 4, 4); - TEST_TYPE_POINTER(PRTL_RESOURCE_DEBUG, 32, 4); } static void test_pack_PSECURITY_DESCRIPTOR(void) @@ -1580,12 +1523,6 @@ static void test_pack_PTOKEN_USER(void) TEST_TYPE_POINTER(PTOKEN_USER, 8, 4); } -static void test_pack_PTOP_LEVEL_EXCEPTION_FILTER(void) -{ - /* PTOP_LEVEL_EXCEPTION_FILTER */ - TEST_TYPE(PTOP_LEVEL_EXCEPTION_FILTER, 4, 4); -} - static void test_pack_PTSTR(void) { /* PTSTR */ @@ -1639,14 +1576,12 @@ static void test_pack_RTL_CRITICAL_SECTION(void) static void test_pack_RTL_CRITICAL_SECTION_DEBUG(void) { /* RTL_CRITICAL_SECTION_DEBUG (pack 4) */ - TEST_TYPE(RTL_CRITICAL_SECTION_DEBUG, 32, 4); TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, WORD, Type, 0, 2, 2); TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, WORD, CreatorBackTraceIndex, 2, 2, 2); TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, struct _RTL_CRITICAL_SECTION *, CriticalSection, 4, 4, 4); TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, LIST_ENTRY, ProcessLocksList, 8, 8, 4); TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, DWORD, EntryCount, 16, 4, 4); TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, DWORD, ContentionCount, 20, 4, 4); - TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, DWORD[ 2 ], Spare, 24, 8, 4); } static void test_pack_RTL_OSVERSIONINFOEXW(void) @@ -1681,14 +1616,12 @@ static void test_pack_RTL_OSVERSIONINFOW(void) static void test_pack_RTL_RESOURCE_DEBUG(void) { /* RTL_RESOURCE_DEBUG (pack 4) */ - TEST_TYPE(RTL_RESOURCE_DEBUG, 32, 4); TEST_FIELD(RTL_RESOURCE_DEBUG, WORD, Type, 0, 2, 2); TEST_FIELD(RTL_RESOURCE_DEBUG, WORD, CreatorBackTraceIndex, 2, 2, 2); TEST_FIELD(RTL_RESOURCE_DEBUG, struct _RTL_CRITICAL_SECTION *, CriticalSection, 4, 4, 4); TEST_FIELD(RTL_RESOURCE_DEBUG, LIST_ENTRY, ProcessLocksList, 8, 8, 4); TEST_FIELD(RTL_RESOURCE_DEBUG, DWORD, EntryCount, 16, 4, 4); TEST_FIELD(RTL_RESOURCE_DEBUG, DWORD, ContentionCount, 20, 4, 4); - TEST_FIELD(RTL_RESOURCE_DEBUG, DWORD[ 2 ], Spare, 24, 8, 4); } static void test_pack_SECURITY_CONTEXT_TRACKING_MODE(void) @@ -2029,13 +1962,6 @@ static void test_pack_LPPOINT(void) TEST_TYPE_POINTER(LPPOINT, 8, 4); } -static void test_pack_LPPOINTS(void) -{ - /* LPPOINTS */ - TEST_TYPE(LPPOINTS, 4, 4); - TEST_TYPE_POINTER(LPPOINTS, 4, 2); -} - static void test_pack_LPRECT(void) { /* LPRECT */ @@ -2079,14 +2005,6 @@ static void test_pack_POINTL(void) TEST_FIELD(POINTL, LONG, y, 4, 4, 4); } -static void test_pack_POINTS(void) -{ - /* POINTS (pack 4) */ - TEST_TYPE(POINTS, 4, 2); - TEST_FIELD(POINTS, SHORT, x, 0, 2, 2); - TEST_FIELD(POINTS, SHORT, y, 2, 2, 2); -} - static void test_pack_PPOINT(void) { /* PPOINT */ @@ -2101,13 +2019,6 @@ static void test_pack_PPOINTL(void) TEST_TYPE_POINTER(PPOINTL, 8, 4); } -static void test_pack_PPOINTS(void) -{ - /* PPOINTS */ - TEST_TYPE(PPOINTS, 4, 4); - TEST_TYPE_POINTER(PPOINTS, 4, 2); -} - static void test_pack_PRECT(void) { /* PRECT */ @@ -2273,7 +2184,6 @@ static void test_pack(void) test_pack_IMAGE_LINENUMBER(); test_pack_IMAGE_LOAD_CONFIG_DIRECTORY(); test_pack_IMAGE_NT_HEADERS(); - test_pack_IMAGE_OPTIONAL_HEADER(); test_pack_IMAGE_OS2_HEADER(); test_pack_IMAGE_RELOCATION(); test_pack_IMAGE_RESOURCE_DATA_ENTRY(); @@ -2309,11 +2219,9 @@ static void test_pack(void) test_pack_LPCRECTL(); test_pack_LPCVOID(); test_pack_LPPOINT(); - test_pack_LPPOINTS(); test_pack_LPRECT(); test_pack_LPRECTL(); test_pack_LPSIZE(); - test_pack_LPTOP_LEVEL_EXCEPTION_FILTER(); test_pack_LRESULT(); test_pack_LUID(); test_pack_LUID_AND_ATTRIBUTES(); @@ -2391,10 +2299,8 @@ static void test_pack(void) test_pack_POBJECT_TYPE_LIST(); test_pack_POINT(); test_pack_POINTL(); - test_pack_POINTS(); test_pack_PPOINT(); test_pack_PPOINTL(); - test_pack_PPOINTS(); test_pack_PPRIVILEGE_SET(); test_pack_PRECT(); test_pack_PRECTL(); @@ -2419,7 +2325,6 @@ static void test_pack(void) test_pack_PTOKEN_GROUPS(); test_pack_PTOKEN_PRIVILEGES(); test_pack_PTOKEN_USER(); - test_pack_PTOP_LEVEL_EXCEPTION_FILTER(); test_pack_PTSTR(); test_pack_PULARGE_INTEGER(); test_pack_PVECTORED_EXCEPTION_HANDLER(); diff --git a/rostests/winetests/ntdll/info.c b/rostests/winetests/ntdll/info.c index b134af57980..9fab8065969 100755 --- a/rostests/winetests/ntdll/info.c +++ b/rostests/winetests/ntdll/info.c @@ -19,37 +19,39 @@ */ #include "ntdll_test.h" +#include static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); - -static HMODULE hntdll = 0; +static NTSTATUS (WINAPI * pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*); /* one_before_last_pid is used to be able to compare values of a still running process with the output of the test_query_process_times and test_query_process_handlecount tests. */ static DWORD one_before_last_pid = 0; -#define NTDLL_GET_PROC(func) \ +#define NTDLL_GET_PROC(func) do { \ p ## func = (void*)GetProcAddress(hntdll, #func); \ if(!p ## func) { \ trace("GetProcAddress(%s) failed\n", #func); \ - FreeLibrary(hntdll); \ return FALSE; \ - } + } \ + } while(0) static BOOL InitFunctionPtrs(void) { - hntdll = LoadLibraryA("ntdll.dll"); - if(!hntdll) { - trace("Could not load ntdll.dll\n"); - return FALSE; - } - if (hntdll) + /* All needed functions are NT based, so using GetModuleHandle is a good check */ + HMODULE hntdll = GetModuleHandle("ntdll"); + if (!hntdll) { - NTDLL_GET_PROC(NtQuerySystemInformation) - NTDLL_GET_PROC(NtQueryInformationProcess) + skip("Not running on NT\n"); + return FALSE; } + + NTDLL_GET_PROC(NtQuerySystemInformation); + NTDLL_GET_PROC(NtQueryInformationProcess); + NTDLL_GET_PROC(NtReadVirtualMemory); + return TRUE; } @@ -59,40 +61,40 @@ static void test_query_basic(void) ULONG ReturnLength; SYSTEM_BASIC_INFORMATION sbi; - /* This test also covers some basic parameter testing that should be the same for + /* This test also covers some basic parameter testing that should be the same for * every information class */ /* Use a nonexistent info class */ trace("Check nonexistent info class\n"); status = pNtQuerySystemInformation(-1, NULL, 0, NULL); - ok( status == STATUS_INVALID_INFO_CLASS, "Expected STATUS_INVALID_INFO_CLASS, got %08lx\n", status); + ok( status == STATUS_INVALID_INFO_CLASS, "Expected STATUS_INVALID_INFO_CLASS, got %08x\n", status); /* Use an existing class but with a zero-length buffer */ trace("Check zero-length buffer\n"); status = pNtQuerySystemInformation(SystemBasicInformation, NULL, 0, NULL); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); /* Use an existing class, correct length but no SystemInformation buffer */ trace("Check no SystemInformation buffer\n"); status = pNtQuerySystemInformation(SystemBasicInformation, NULL, sizeof(sbi), NULL); - ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", status); + ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status); /* Use a existing class, correct length, a pointer to a buffer but no ReturnLength pointer */ trace("Check no ReturnLength pointer\n"); status = pNtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); /* Check a too large buffer size */ trace("Check a too large buffer size\n"); status = pNtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi) * 2, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); /* Finally some correct calls */ trace("Check with correct parameters\n"); status = pNtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(sbi) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(sbi), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(sbi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); /* Check if we have some return values */ trace("Number of Processors : %d\n", sbi.NumberOfProcessors); @@ -106,12 +108,12 @@ static void test_query_cpu(void) SYSTEM_CPU_INFORMATION sci; status = pNtQuerySystemInformation(SystemCpuInformation, &sci, sizeof(sci), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(sci) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(sci), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(sci) == ReturnLength, "Inconsistent length %d\n", ReturnLength); /* Check if we have some return values */ - trace("Processor FeatureSet : %08lx\n", sci.FeatureSet); - ok( sci.FeatureSet != 0, "Expected some features for this processor, got %08lx\n", sci.FeatureSet); + trace("Processor FeatureSet : %08x\n", sci.FeatureSet); + ok( sci.FeatureSet != 0, "Expected some features for this processor, got %08x\n", sci.FeatureSet); } static void test_query_performance(void) @@ -121,15 +123,15 @@ static void test_query_performance(void) SYSTEM_PERFORMANCE_INFORMATION spi; status = pNtQuerySystemInformation(SystemPerformanceInformation, &spi, 0, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); status = pNtQuerySystemInformation(SystemPerformanceInformation, &spi, sizeof(spi), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(spi) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(spi), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(spi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); status = pNtQuerySystemInformation(SystemPerformanceInformation, &spi, sizeof(spi) + 2, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(spi) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(spi), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(spi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); /* Not return values yet, as struct members are unknown */ } @@ -149,7 +151,7 @@ static void test_query_timeofday(void) } SYSTEM_TIMEOFDAY_INFORMATION_PRIVATE, *PSYSTEM_TIMEOFDAY_INFORMATION_PRIVATE; SYSTEM_TIMEOFDAY_INFORMATION_PRIVATE sti; - + /* The struct size for NT (32 bytes) and Win2K/XP (48 bytes) differ. * * Windows 2000 and XP return STATUS_INFO_LENGTH_MISMATCH if the given buffer size is greater @@ -167,48 +169,48 @@ static void test_query_timeofday(void) if (status == STATUS_INFO_LENGTH_MISMATCH) { trace("Windows version is NT, we have to cater for differences with W2K/WinXP\n"); - + status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 0, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); - ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%ld)\n", ReturnLength); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength); sti.uCurrentTimeZoneId = 0xdeadbeef; status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 28, &ReturnLength); ok( 0xdeadbeef == sti.uCurrentTimeZoneId, "This part of the buffer should not have been filled\n"); status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 32, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( 32 == ReturnLength, "ReturnLength should be 0, it is (%ld)\n", ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( 32 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength); } else { status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 0, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%ld)\n", ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength); sti.uCurrentTimeZoneId = 0xdeadbeef; status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 24, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( 24 == ReturnLength, "ReturnLength should be 24, it is (%ld)\n", ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( 24 == ReturnLength, "ReturnLength should be 24, it is (%d)\n", ReturnLength); ok( 0xdeadbeef == sti.uCurrentTimeZoneId, "This part of the buffer should not have been filled\n"); - + sti.uCurrentTimeZoneId = 0xdeadbeef; status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 32, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( 32 == ReturnLength, "ReturnLength should be 32, it is (%ld)\n", ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( 32 == ReturnLength, "ReturnLength should be 32, it is (%d)\n", ReturnLength); ok( 0xdeadbeef != sti.uCurrentTimeZoneId, "Buffer should have been partially filled\n"); - + status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 49, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); - ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%ld)\n", ReturnLength); - + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength); + status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, sizeof(sti), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(sti) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(sti), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(sti) == ReturnLength, "Inconsistent length %d\n", ReturnLength); } /* Check if we have some return values */ - trace("uCurrentTimeZoneId : (%ld)\n", sti.uCurrentTimeZoneId); + trace("uCurrentTimeZoneId : (%d)\n", sti.uCurrentTimeZoneId); } static void test_query_process(void) @@ -250,11 +252,11 @@ static void test_query_process(void) status = pNtQuerySystemInformation(SystemProcessInformation, spi, SystemInformationLength, &ReturnLength); if (status != STATUS_INFO_LENGTH_MISMATCH) break; - + spi = HeapReAlloc(GetProcessHeap(), 0, spi , SystemInformationLength *= 2); } - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); /* Get the first dwOffset, from this we can deduce the OS version we're running * @@ -275,14 +277,14 @@ static void test_query_process(void) is_nt = ( spi->dwOffset - (sbi.NumberOfProcessors * sizeof(SYSTEM_THREAD_INFORMATION)) == 136); - if (is_nt) trace("Windows version is NT, we will skip thread tests\n"); + if (is_nt) skip("Windows version is NT, we will skip thread tests\n"); /* Check if we have some return values - * + * * On windows there will be several processes running (Including the always present Idle and System) * On wine we only have one (if this test is the only wine process running) */ - + /* Loop through the processes */ for (;;) @@ -294,15 +296,15 @@ static void test_query_process(void) ok( spi->dwThreadCount > 0, "Expected some threads for this process, got 0\n"); /* Loop through the threads, skip NT4 for now */ - + if (!is_nt) { DWORD j; - for ( j = 0; j < spi->dwThreadCount; j++) + for ( j = 0; j < spi->dwThreadCount; j++) { k++; - ok ( spi->ti[j].dwOwningPID == spi->dwProcessID, - "The owning pid of the thread (%ld) doesn't equal the pid (%ld) of the process\n", + ok ( spi->ti[j].dwOwningPID == spi->dwProcessID, + "The owning pid of the thread (%d) doesn't equal the pid (%d) of the process\n", spi->ti[j].dwOwningPID, spi->dwProcessID); } } @@ -336,25 +338,25 @@ static void test_query_procperf(void) sppi = HeapAlloc(GetProcessHeap(), 0, NeededLength); status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, 0, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); /* Try it for 1 processor */ status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); ok( sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) == ReturnLength, - "Inconsistent length (%d) <-> (%ld)\n", sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), ReturnLength); - + "Inconsistent length %d\n", ReturnLength); + /* Try it for all processors */ status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, NeededLength, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( NeededLength == ReturnLength, "Inconsistent length (%ld) <-> (%ld)\n", NeededLength, ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( NeededLength == ReturnLength, "Inconsistent length (%d) <-> (%d)\n", NeededLength, ReturnLength); /* A too large given buffer size */ sppi = HeapReAlloc(GetProcessHeap(), 0, sppi , NeededLength + 2); status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, NeededLength + 2, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( NeededLength == ReturnLength, "Inconsistent length (%ld) <-> (%ld)\n", NeededLength, ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( NeededLength == ReturnLength, "Inconsistent length (%d) <-> (%d)\n", NeededLength, ReturnLength); HeapFree( GetProcessHeap(), 0, sppi); } @@ -366,30 +368,28 @@ static void test_query_module(void) ULONG ModuleCount, i; ULONG SystemInformationLength = sizeof(SYSTEM_MODULE_INFORMATION); - SYSTEM_MODULE_INFORMATION* smi = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength); + SYSTEM_MODULE_INFORMATION* smi = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength); SYSTEM_MODULE* sm; /* Request the needed length */ status = pNtQuerySystemInformation(SystemModuleInformation, smi, 0, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); ok( ReturnLength > 0, "Expected a ReturnLength to show the needed length\n"); SystemInformationLength = ReturnLength; smi = HeapReAlloc(GetProcessHeap(), 0, smi , SystemInformationLength); status = pNtQuerySystemInformation(SystemModuleInformation, smi, SystemInformationLength, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); ModuleCount = smi->ModulesCount; sm = &smi->Modules[0]; - todo_wine{ - /* our implementation is a stub for now */ - ok( ModuleCount > 0, "Expected some modules to be loaded\n"); - } + /* our implementation is a stub for now */ + ok( ModuleCount > 0, "Expected some modules to be loaded\n"); /* Loop through all the modules/drivers, Wine doesn't get here (yet) */ for (i = 0; i < ModuleCount ; i++) { - ok( i == sm->Id, "Id (%d) should have matched %lu\n", sm->Id, i); + ok( i == sm->Id, "Id (%d) should have matched %u\n", sm->Id, i); sm++; } @@ -409,21 +409,21 @@ static void test_query_handle(void) /* The following check assumes more than one handle on any given system */ todo_wine { - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); } - ok( ReturnLength > 0, "Expected ReturnLength to be > 0, it was %ld\n", ReturnLength); + ok( ReturnLength > 0, "Expected ReturnLength to be > 0, it was %d\n", ReturnLength); SystemInformationLength = ReturnLength; shi = HeapReAlloc(GetProcessHeap(), 0, shi , SystemInformationLength); status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); /* Check if we have some return values */ - trace("Number of Handles : %ld\n", shi->Count); + trace("Number of Handles : %d\n", shi->Count); todo_wine { /* our implementation is a stub for now */ - ok( shi->Count > 1, "Expected more than 1 handles, got (%ld)\n", shi->Count); + ok( shi->Count > 1, "Expected more than 1 handles, got (%d)\n", shi->Count); } HeapFree( GetProcessHeap(), 0, shi); @@ -436,15 +436,15 @@ static void test_query_cache(void) SYSTEM_CACHE_INFORMATION sci; status = pNtQuerySystemInformation(SystemCacheInformation, &sci, 0, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); status = pNtQuerySystemInformation(SystemCacheInformation, &sci, sizeof(sci), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(sci) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(sci), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(sci) == ReturnLength, "Inconsistent length %d\n", ReturnLength); status = pNtQuerySystemInformation(SystemCacheInformation, &sci, sizeof(sci) + 2, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(sci) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(sci), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(sci) == ReturnLength, "Inconsistent length %d\n", ReturnLength); } static void test_query_interrupt(void) @@ -462,11 +462,11 @@ static void test_query_interrupt(void) sii = HeapAlloc(GetProcessHeap(), 0, NeededLength); status = pNtQuerySystemInformation(SystemInterruptInformation, sii, 0, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); /* Try it for all processors */ status = pNtQuerySystemInformation(SystemInterruptInformation, sii, NeededLength, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); /* Windows XP and W2K3 (and others?) always return 0 for the ReturnLength * No test added for this as it's highly unlikely that an app depends on this @@ -482,15 +482,15 @@ static void test_query_kerndebug(void) SYSTEM_KERNEL_DEBUGGER_INFORMATION skdi; status = pNtQuerySystemInformation(SystemKernelDebuggerInformation, &skdi, 0, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); status = pNtQuerySystemInformation(SystemKernelDebuggerInformation, &skdi, sizeof(skdi), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(skdi) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(skdi), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(skdi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); status = pNtQuerySystemInformation(SystemKernelDebuggerInformation, &skdi, sizeof(skdi) + 2, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(skdi) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(skdi), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(skdi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); } static void test_query_regquota(void) @@ -500,15 +500,15 @@ static void test_query_regquota(void) SYSTEM_REGISTRY_QUOTA_INFORMATION srqi; status = pNtQuerySystemInformation(SystemRegistryQuotaInformation, &srqi, 0, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); status = pNtQuerySystemInformation(SystemRegistryQuotaInformation, &srqi, sizeof(srqi), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(srqi) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(srqi), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(srqi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); status = pNtQuerySystemInformation(SystemRegistryQuotaInformation, &srqi, sizeof(srqi) + 2, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(srqi) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(srqi), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(srqi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); } static void test_query_process_basic(void) @@ -534,48 +534,48 @@ static void test_query_process_basic(void) /* Use a nonexistent info class */ trace("Check nonexistent info class\n"); status = pNtQueryInformationProcess(NULL, -1, NULL, 0, NULL); - ok( status == STATUS_INVALID_INFO_CLASS, "Expected STATUS_INVALID_INFO_CLASS, got %08lx\n", status); + ok( status == STATUS_INVALID_INFO_CLASS, "Expected STATUS_INVALID_INFO_CLASS, got %08x\n", status); /* Do not give a handle and buffer */ trace("Check NULL handle and buffer and zero-length buffersize\n"); status = pNtQueryInformationProcess(NULL, ProcessBasicInformation, NULL, 0, NULL); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); /* Use a correct info class and buffer size, but still no handle and buffer */ trace("Check NULL handle and buffer\n"); status = pNtQueryInformationProcess(NULL, ProcessBasicInformation, NULL, sizeof(pbi), NULL); ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE, - "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08lx\n", status); + "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08x\n", status); /* Use a correct info class and buffer size, but still no handle */ trace("Check NULL handle\n"); status = pNtQueryInformationProcess(NULL, ProcessBasicInformation, &pbi, sizeof(pbi), NULL); - ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08lx\n", status); + ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status); /* Use a greater buffer size */ trace("Check NULL handle and too large buffersize\n"); status = pNtQueryInformationProcess(NULL, ProcessBasicInformation, &pbi, sizeof(pbi) * 2, NULL); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); /* Use no ReturnLength */ trace("Check NULL ReturnLength\n"); status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), NULL); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); /* Finally some correct calls */ trace("Check with correct parameters\n"); status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(pbi) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(pbi), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(pbi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); /* Everything is correct except a too large buffersize */ trace("Too large buffersize\n"); status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi) * 2, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); - ok( sizeof(pbi) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(pbi), ReturnLength); - + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( sizeof(pbi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); + /* Check if we have some return values */ - trace("ProcessID : %ld\n", pbi.UniqueProcessId); + trace("ProcessID : %d\n", pbi.UniqueProcessId); ok( pbi.UniqueProcessId > 0, "Expected a ProcessID > 0, got 0\n"); } @@ -587,10 +587,10 @@ static void test_query_process_vm(void) status = pNtQueryInformationProcess(NULL, ProcessVmCounters, NULL, sizeof(pvi), NULL); ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE, - "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08lx\n", status); + "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08x\n", status); status = pNtQueryInformationProcess(NULL, ProcessVmCounters, &pvi, sizeof(pvi), NULL); - ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08lx\n", status); + ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status); /* Windows XP and W2K3 will report success for a size of 44 AND 48 ! Windows W2K will only report success for 44. @@ -599,15 +599,15 @@ static void test_query_process_vm(void) */ status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &pvi, 24, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(pvi) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(pvi), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(pvi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &pvi, 46, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); - ok( sizeof(pvi) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(pvi), ReturnLength); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( sizeof(pvi) == ReturnLength, "Inconsistent length %d\n", ReturnLength); /* Check if we have some return values */ trace("WorkingSetSize : %ld\n", pvi.WorkingSetSize); @@ -627,30 +627,30 @@ static void test_query_process_io(void) status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessIoCounters, &pii, sizeof(pii), &ReturnLength); if (status == STATUS_NOT_SUPPORTED) { - trace("ProcessIoCounters information class not supported, skipping tests\n"); + skip("ProcessIoCounters information class is not supported\n"); return; } - + status = pNtQueryInformationProcess(NULL, ProcessIoCounters, NULL, sizeof(pii), NULL); ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE, - "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08lx\n", status); + "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08x\n", status); status = pNtQueryInformationProcess(NULL, ProcessIoCounters, &pii, sizeof(pii), NULL); - ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08lx\n", status); + ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessIoCounters, &pii, 24, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessIoCounters, &pii, sizeof(pii), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(pii) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(pii), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(pii) == ReturnLength, "Inconsistent length %d\n", ReturnLength); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessIoCounters, &pii, sizeof(pii) * 2, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); - ok( sizeof(pii) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(pii), ReturnLength); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( sizeof(pii) == ReturnLength, "Inconsistent length %d\n", ReturnLength); /* Check if we have some return values */ - trace("OtherOperationCount : %lld\n", pii.OtherOperationCount); + trace("OtherOperationCount : 0x%x%08x\n", (DWORD)(pii.OtherOperationCount >> 32), (DWORD)pii.OtherOperationCount); todo_wine { ok( pii.OtherOperationCount > 0, "Expected an OtherOperationCount > 0\n"); @@ -667,27 +667,27 @@ static void test_query_process_times(void) status = pNtQueryInformationProcess(NULL, ProcessTimes, NULL, sizeof(spti), NULL); ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE, - "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08lx\n", status); + "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08x\n", status); status = pNtQueryInformationProcess(NULL, ProcessTimes, &spti, sizeof(spti), NULL); - ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08lx\n", status); + ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessTimes, &spti, 24, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, one_before_last_pid); if (!process) { - trace("Could not open process with ID : %ld, error : %08lx. Going to use current one.\n", one_before_last_pid, GetLastError()); + trace("Could not open process with ID : %d, error : %u. Going to use current one.\n", one_before_last_pid, GetLastError()); process = GetCurrentProcess(); trace("ProcessTimes for current process\n"); } else - trace("ProcessTimes for process with ID : %ld\n", one_before_last_pid); + trace("ProcessTimes for process with ID : %d\n", one_before_last_pid); status = pNtQueryInformationProcess( process, ProcessTimes, &spti, sizeof(spti), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(spti) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(spti), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(spti) == ReturnLength, "Inconsistent length %d\n", ReturnLength); CloseHandle(process); FileTimeToSystemTime((const FILETIME *)&spti.CreateTime, &UTC); @@ -707,8 +707,8 @@ static void test_query_process_times(void) trace("UserTime : %02d:%02d:%02d.%03d\n", Local.wHour, Local.wMinute, Local.wSecond, Local.wMilliseconds); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessTimes, &spti, sizeof(spti) * 2, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); - ok( sizeof(spti) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(spti), ReturnLength); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( sizeof(spti) == ReturnLength, "Inconsistent length %d\n", ReturnLength); } static void test_query_process_handlecount(void) @@ -720,41 +720,132 @@ static void test_query_process_handlecount(void) status = pNtQueryInformationProcess(NULL, ProcessHandleCount, NULL, sizeof(handlecount), NULL); ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE, - "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08lx\n", status); + "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE(W2K3), got %08x\n", status); status = pNtQueryInformationProcess(NULL, ProcessHandleCount, &handlecount, sizeof(handlecount), NULL); - ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08lx\n", status); + ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessHandleCount, &handlecount, 2, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, one_before_last_pid); if (!process) { - trace("Could not open process with ID : %ld, error : %08lx. Going to use current one.\n", one_before_last_pid, GetLastError()); + trace("Could not open process with ID : %d, error : %u. Going to use current one.\n", one_before_last_pid, GetLastError()); process = GetCurrentProcess(); trace("ProcessHandleCount for current process\n"); } else - trace("ProcessHandleCount for process with ID : %ld\n", one_before_last_pid); + trace("ProcessHandleCount for process with ID : %d\n", one_before_last_pid); status = pNtQueryInformationProcess( process, ProcessHandleCount, &handlecount, sizeof(handlecount), &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); - ok( sizeof(handlecount) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(handlecount), ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( sizeof(handlecount) == ReturnLength, "Inconsistent length %d\n", ReturnLength); CloseHandle(process); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessHandleCount, &handlecount, sizeof(handlecount) * 2, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08lx\n", status); - ok( sizeof(handlecount) == ReturnLength, "Inconsistent length (%d) <-> (%ld)\n", sizeof(handlecount), ReturnLength); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( sizeof(handlecount) == ReturnLength, "Inconsistent length %d\n", ReturnLength); /* Check if we have some return values */ - trace("HandleCount : %ld\n", handlecount); + trace("HandleCount : %d\n", handlecount); todo_wine { ok( handlecount > 0, "Expected some handles, got 0\n"); } } +static void test_query_process_image_file_name(void) +{ + DWORD status; + ULONG ReturnLength; + UNICODE_STRING image_file_name; + void *buffer; + char *file_nameA; + INT len; + + status = pNtQueryInformationProcess(NULL, ProcessImageFileName, &image_file_name, sizeof(image_file_name), NULL); + if (status == STATUS_INVALID_INFO_CLASS) + { + skip("ProcessImageFileName is not supported\n"); + return; + } + ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status); + + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessImageFileName, &image_file_name, 2, &ReturnLength); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessImageFileName, &image_file_name, sizeof(image_file_name), &ReturnLength); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + + buffer = HeapAlloc(GetProcessHeap(), 0, ReturnLength); + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessImageFileName, buffer, ReturnLength, &ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + memcpy(&image_file_name, buffer, sizeof(image_file_name)); + len = WideCharToMultiByte(CP_ACP, 0, image_file_name.Buffer, image_file_name.Length/sizeof(WCHAR), NULL, 0, NULL, NULL); + file_nameA = HeapAlloc(GetProcessHeap(), 0, len + 1); + WideCharToMultiByte(CP_ACP, 0, image_file_name.Buffer, image_file_name.Length/sizeof(WCHAR), file_nameA, len, NULL, NULL); + file_nameA[len] = '\0'; + HeapFree(GetProcessHeap(), 0, buffer); + trace("process image file name: %s\n", file_nameA); + HeapFree(GetProcessHeap(), 0, file_nameA); +} + + +static void test_readvirtualmemory(void) +{ + HANDLE process; + DWORD status; + SIZE_T readcount; + static const char teststring[] = "test string"; + char buffer[12]; + + process = OpenProcess(PROCESS_VM_READ, FALSE, GetCurrentProcessId()); + ok(process != 0, "Expected to be able to open own process for reading memory\n"); + + /* normal operation */ + status = pNtReadVirtualMemory(process, teststring, buffer, 12, &readcount); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( readcount == 12, "Expected to read 12 bytes, got %ld\n",readcount); + ok( strcmp(teststring, buffer) == 0, "Expected read memory to be the same as original memory\n"); + + /* no number of bytes */ + memset(buffer, 0, 12); + status = pNtReadVirtualMemory(process, teststring, buffer, 12, NULL); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( strcmp(teststring, buffer) == 0, "Expected read memory to be the same as original memory\n"); + + /* illegal remote address */ + todo_wine{ + status = pNtReadVirtualMemory(process, (void *) 0x1234, buffer, 12, &readcount); + ok( status == STATUS_PARTIAL_COPY, "Expected STATUS_PARTIAL_COPY, got %08x\n", status); + ok( readcount == 0, "Expected to read 0 bytes, got %ld\n",readcount); + } + + /* 0 handle */ + status = pNtReadVirtualMemory(0, teststring, buffer, 12, &readcount); + ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status); + ok( readcount == 0, "Expected to read 0 bytes, got %ld\n",readcount); + + /* pseudo handle for current process*/ + memset(buffer, 0, 12); + status = pNtReadVirtualMemory((HANDLE)-1, teststring, buffer, 12, &readcount); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( readcount == 12, "Expected to read 12 bytes, got %ld\n",readcount); + ok( strcmp(teststring, buffer) == 0, "Expected read memory to be the same as original memory\n"); + + /* this test currently crashes wine with "wine client error:: read: Bad address" + * because the reply from wine server is directly read into the buffer and that fails with EFAULT + */ + /* illegal local address */ + /*status = pNtReadVirtualMemory(process, teststring, (void *)0x1234, 12, &readcount); + ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", status); + ok( readcount == 0, "Expected to read 0 bytes, got %ld\n",readcount); + */ + + CloseHandle(process); +} + START_TEST(info) { if(!InitFunctionPtrs()) @@ -832,5 +923,11 @@ START_TEST(info) trace("Starting test_query_process_handlecount()\n"); test_query_process_handlecount(); - FreeLibrary(hntdll); + /* 27 ProcessImageFileName */ + trace("Starting test_query_process_image_file_name()\n"); + test_query_process_image_file_name(); + + /* belongs into it's own file */ + trace("Starting test_readvirtualmemory()\n"); + test_readvirtualmemory(); } diff --git a/rostests/winetests/ntdll/large_int.c b/rostests/winetests/ntdll/large_int.c index a8fe2f563e6..bec8ad9bf8f 100755 --- a/rostests/winetests/ntdll/large_int.c +++ b/rostests/winetests/ntdll/large_int.c @@ -113,8 +113,10 @@ static void test_RtlExtendedMagicDivide(void) for (i = 0; i < NB_MAGIC_DIVIDE; i++) { result = pRtlExtendedMagicDivide(magic_divide[i].a, magic_divide[i].b, magic_divide[i].shift); ok(result == magic_divide[i].result, - "call failed: RtlExtendedMagicDivide(%lld, %llu, %d) has result %llx, expected %llx\n", - magic_divide[i].a, magic_divide[i].b, magic_divide[i].shift, result, magic_divide[i].result); + "call failed: RtlExtendedMagicDivide(0x%x%08x, 0x%x%08x, %d) has result 0x%x%08x, expected 0x%x%08x\n", + (DWORD)(magic_divide[i].a >> 32), (DWORD)magic_divide[i].a, (DWORD)(magic_divide[i].b >> 32), + (DWORD)magic_divide[i].b, magic_divide[i].shift, (DWORD)(result >> 32), (DWORD)result, + (DWORD)(magic_divide[i].result >> 32), (DWORD)magic_divide[i].result); } } @@ -322,23 +324,28 @@ static void one_RtlInt64ToUnicodeString_test(int test_num, const largeint2str_t } /* if */ } else { ok(result == largeint2str->result, - "(test %d): RtlInt64ToUnicodeString(%llu, %d, [out]) has result %lx, expected: %lx\n", - test_num, largeint2str->value, largeint2str->base, result, largeint2str->result); + "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) has result %x, expected: %x\n", + test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, + largeint2str->base, result, largeint2str->result); if (result == STATUS_SUCCESS) { ok(unicode_string.Buffer[unicode_string.Length/sizeof(WCHAR)] == '\0', - "(test %d): RtlInt64ToUnicodeString(%llu, %d, [out]) string \"%s\" is not NULL terminated\n", - test_num, largeint2str->value, largeint2str->base, ansi_str.Buffer); + "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string \"%s\" is not NULL terminated\n", + test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, + largeint2str->base, ansi_str.Buffer); } /* if */ } /* if */ ok(memcmp(unicode_string.Buffer, expected_unicode_string.Buffer, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0, - "(test %d): RtlInt64ToUnicodeString(%llu, %d, [out]) assigns string \"%s\", expected: \"%s\"\n", - test_num, largeint2str->value, largeint2str->base, ansi_str.Buffer, expected_ansi_str.Buffer); + "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) assigns string \"%s\", expected: \"%s\"\n", + test_num, (DWORD)(largeint2str->value >>32), (DWORD)largeint2str->value, largeint2str->base, + ansi_str.Buffer, expected_ansi_str.Buffer); ok(unicode_string.Length == expected_unicode_string.Length, - "(test %d): RtlInt64ToUnicodeString(%llu, %d, [out]) string has Length %d, expected: %d\n", - test_num, largeint2str->value, largeint2str->base, unicode_string.Length, expected_unicode_string.Length); + "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string has Length %d, expected: %d\n", + test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base, + unicode_string.Length, expected_unicode_string.Length); ok(unicode_string.MaximumLength == expected_unicode_string.MaximumLength, - "(test %d): RtlInt64ToUnicodeString(%llu, %d, [out]) string has MaximumLength %d, expected: %d\n", - test_num, largeint2str->value, largeint2str->base, unicode_string.MaximumLength, expected_unicode_string.MaximumLength); + "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string has MaximumLength %d, expected: %d\n", + test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base, + unicode_string.MaximumLength, expected_unicode_string.MaximumLength); pRtlFreeAnsiString(&expected_ansi_str); pRtlFreeAnsiString(&ansi_str); } @@ -369,11 +376,13 @@ static void one_RtlLargeIntegerToChar_test(int test_num, const largeint2str_t *l result = pRtlLargeIntegerToChar(&value, largeint2str->base, largeint2str->MaximumLength, dest_str); } /* if */ ok(result == largeint2str->result, - "(test %d): RtlLargeIntegerToChar(%llu, %d, %d, [out]) has result %lx, expected: %lx\n", - test_num, largeint2str->value, largeint2str->base, largeint2str->MaximumLength, result, largeint2str->result); + "(test %d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, [out]) has result %x, expected: %x\n", + test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base, + largeint2str->MaximumLength, result, largeint2str->result); ok(memcmp(dest_str, largeint2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0, - "(test %d): RtlLargeIntegerToChar(%llu, %d, %d, [out]) assigns string \"%s\", expected: \"%s\"\n", - test_num, largeint2str->value, largeint2str->base, largeint2str->MaximumLength, dest_str, largeint2str->Buffer); + "(test %d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, [out]) assigns string \"%s\", expected: \"%s\"\n", + test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base, + largeint2str->MaximumLength, dest_str, largeint2str->Buffer); } @@ -390,23 +399,27 @@ static void test_RtlLargeIntegerToChar(void) value = largeint2str[0].value; result = pRtlLargeIntegerToChar(&value, 20, largeint2str[0].MaximumLength, NULL); ok(result == STATUS_INVALID_PARAMETER, - "(test a): RtlLargeIntegerToChar(%llu, %d, %d, NULL) has result %lx, expected: %lx\n", - largeint2str[0].value, 20, largeint2str[0].MaximumLength, result, STATUS_INVALID_PARAMETER); + "(test a): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n", + (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, 20, + largeint2str[0].MaximumLength, result, STATUS_INVALID_PARAMETER); result = pRtlLargeIntegerToChar(&value, 20, 0, NULL); ok(result == STATUS_INVALID_PARAMETER, - "(test b): RtlLargeIntegerToChar(%llu, %d, %d, NULL) has result %lx, expected: %lx\n", - largeint2str[0].value, 20, largeint2str[0].MaximumLength, result, STATUS_INVALID_PARAMETER); + "(test b): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n", + (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, 20, + largeint2str[0].MaximumLength, result, STATUS_INVALID_PARAMETER); result = pRtlLargeIntegerToChar(&value, largeint2str[0].base, 0, NULL); ok(result == STATUS_BUFFER_OVERFLOW, - "(test c): RtlLargeIntegerToChar(%llu, %d, %d, NULL) has result %lx, expected: %lx\n", - largeint2str[0].value, largeint2str[0].base, 0, result, STATUS_BUFFER_OVERFLOW); + "(test c): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n", + (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, + largeint2str[0].base, 0, result, STATUS_BUFFER_OVERFLOW); result = pRtlLargeIntegerToChar(&value, largeint2str[0].base, largeint2str[0].MaximumLength, NULL); ok(result == STATUS_ACCESS_VIOLATION, - "(test d): RtlLargeIntegerToChar(%llu, %d, %d, NULL) has result %lx, expected: %lx\n", - largeint2str[0].value, largeint2str[0].base, largeint2str[0].MaximumLength, result, STATUS_ACCESS_VIOLATION); + "(test d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n", + (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, + largeint2str[0].base, largeint2str[0].MaximumLength, result, STATUS_ACCESS_VIOLATION); } diff --git a/rostests/winetests/ntdll/ntdll.rbuild b/rostests/winetests/ntdll/ntdll.rbuild index 886ac2af625..7af6b4450c7 100644 --- a/rostests/winetests/ntdll/ntdll.rbuild +++ b/rostests/winetests/ntdll/ntdll.rbuild @@ -1,6 +1,11 @@ + + + . + 0x0600 + 0x609 kernel32 ntdll atom.c @@ -8,6 +13,7 @@ env.c error.c exception.c + file.c info.c large_int.c om.c @@ -21,3 +27,4 @@ time.c testlist.c + diff --git a/rostests/winetests/ntdll/ntdll_test.h b/rostests/winetests/ntdll/ntdll_test.h index d083729c03f..167e5ca708c 100755 --- a/rostests/winetests/ntdll/ntdll_test.h +++ b/rostests/winetests/ntdll/ntdll_test.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include diff --git a/rostests/winetests/ntdll/om.c b/rostests/winetests/ntdll/om.c index acd947c17a4..d211ea00432 100644 --- a/rostests/winetests/ntdll/om.c +++ b/rostests/winetests/ntdll/om.c @@ -25,6 +25,7 @@ #include "winnt.h" #include "stdlib.h" +static HANDLE (WINAPI *pCreateWaitableTimerA)(SECURITY_ATTRIBUTES*, BOOL, LPCSTR); static NTSTATUS (WINAPI *pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR); static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR ); static VOID (WINAPI *pRtlFreeUnicodeString)(PUNICODE_STRING); @@ -45,7 +46,7 @@ static NTSTATUS (WINAPI *pNtOpenSymbolicLinkObject)(PHANDLE, ACCESS_MASK, POBJEC static NTSTATUS (WINAPI *pNtCreateSymbolicLinkObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PUNICODE_STRING); -void test_case_sensitive (void) +static void test_case_sensitive (void) { static const WCHAR buffer1[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s','\\','t','e','s','t',0}; static const WCHAR buffer2[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s','\\','T','e','s','t',0}; @@ -59,22 +60,22 @@ void test_case_sensitive (void) pRtlInitUnicodeString(&str, buffer1); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); status = pNtCreateMutant(&Mutant, GENERIC_ALL, &attr, FALSE); - ok(status == STATUS_SUCCESS, "Failed to create Mutant(%08lx)\n", status); + ok(status == STATUS_SUCCESS, "Failed to create Mutant(%08x)\n", status); status = pNtCreateEvent(&Event, GENERIC_ALL, &attr, FALSE, FALSE); ok(status == STATUS_OBJECT_NAME_COLLISION, - "NtCreateEvent should have failed with STATUS_OBJECT_NAME_COLLISION got(%08lx)\n", status); + "NtCreateEvent should have failed with STATUS_OBJECT_NAME_COLLISION got(%08x)\n", status); pRtlInitUnicodeString(&str, buffer2); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); status = pNtCreateEvent(&Event, GENERIC_ALL, &attr, FALSE, FALSE); - ok(status == STATUS_SUCCESS, "Failed to create Event(%08lx)\n", status); + ok(status == STATUS_SUCCESS, "Failed to create Event(%08x)\n", status); pRtlInitUnicodeString(&str, buffer3); InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL); status = pNtOpenMutant(&h, GENERIC_ALL, &attr); ok(status == STATUS_OBJECT_TYPE_MISMATCH, - "NtOpenMutant should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08lx)\n", status); + "NtOpenMutant should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08x)\n", status); pNtClose(Mutant); @@ -82,21 +83,21 @@ void test_case_sensitive (void) InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL); status = pNtCreateMutant(&Mutant, GENERIC_ALL, &attr, FALSE); ok(status == STATUS_OBJECT_NAME_COLLISION, - "NtCreateMutant should have failed with STATUS_OBJECT_NAME_COLLISION got(%08lx)\n", status); + "NtCreateMutant should have failed with STATUS_OBJECT_NAME_COLLISION got(%08x)\n", status); status = pNtCreateEvent(&h, GENERIC_ALL, &attr, FALSE, FALSE); ok(status == STATUS_OBJECT_NAME_COLLISION, - "NtCreateEvent should have failed with STATUS_OBJECT_NAME_COLLISION got(%08lx)\n", status); + "NtCreateEvent should have failed with STATUS_OBJECT_NAME_COLLISION got(%08x)\n", status); attr.Attributes = 0; status = pNtCreateMutant(&Mutant, GENERIC_ALL, &attr, FALSE); ok(status == STATUS_OBJECT_PATH_NOT_FOUND, - "NtCreateMutant should have failed with STATUS_OBJECT_PATH_NOT_FOUND got(%08lx)\n", status); + "NtCreateMutant should have failed with STATUS_OBJECT_PATH_NOT_FOUND got(%08x)\n", status); pNtClose(Event); } -void test_namespace_pipe(void) +static void test_namespace_pipe(void) { static const WCHAR buffer1[] = {'\\','?','?','\\','P','I','P','E','\\','t','e','s','t','\\','p','i','p','e',0}; static const WCHAR buffer2[] = {'\\','?','?','\\','P','I','P','E','\\','T','E','S','T','\\','P','I','P','E',0}; @@ -115,36 +116,36 @@ void test_namespace_pipe(void) InitializeObjectAttributes(&attr, &str, 0, 0, NULL); status = pNtCreateNamedPipeFile(&pipe, GENERIC_READ|GENERIC_WRITE, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_CREATE, FILE_PIPE_FULL_DUPLEX, FALSE, FALSE, FALSE, 1, 256, 256, &timeout); - ok(status == STATUS_SUCCESS, "Failed to create NamedPipe(%08lx)\n", status); + ok(status == STATUS_SUCCESS, "Failed to create NamedPipe(%08x)\n", status); status = pNtCreateNamedPipeFile(&pipe, GENERIC_READ|GENERIC_WRITE, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_CREATE, FILE_PIPE_FULL_DUPLEX, FALSE, FALSE, FALSE, 1, 256, 256, &timeout); ok(status == STATUS_INSTANCE_NOT_AVAILABLE, - "NtCreateNamedPipeFile should have failed with STATUS_INSTANCE_NOT_AVAILABLE got(%08lx)\n", status); + "NtCreateNamedPipeFile should have failed with STATUS_INSTANCE_NOT_AVAILABLE got(%08x)\n", status); pRtlInitUnicodeString(&str, buffer2); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); status = pNtCreateNamedPipeFile(&pipe, GENERIC_READ|GENERIC_WRITE, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_CREATE, FILE_PIPE_FULL_DUPLEX, FALSE, FALSE, FALSE, 1, 256, 256, &timeout); ok(status == STATUS_INSTANCE_NOT_AVAILABLE, - "NtCreateNamedPipeFile should have failed with STATUS_INSTANCE_NOT_AVAILABLE got(%08lx)\n", status); + "NtCreateNamedPipeFile should have failed with STATUS_INSTANCE_NOT_AVAILABLE got(%08x)\n", status); attr.Attributes = OBJ_CASE_INSENSITIVE; status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); - ok(status == STATUS_SUCCESS, "Failed to open NamedPipe(%08lx)\n", status); + ok(status == STATUS_SUCCESS, "Failed to open NamedPipe(%08x)\n", status); pNtClose(h); pRtlInitUnicodeString(&str, buffer3); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); ok(status == STATUS_OBJECT_PATH_NOT_FOUND || status == STATUS_PIPE_NOT_AVAILABLE, - "pNtOpenFile should have failed with STATUS_OBJECT_PATH_NOT_FOUND got(%08lx)\n", status); + "NtOpenFile should have failed with STATUS_OBJECT_PATH_NOT_FOUND got(%08x)\n", status); pRtlInitUnicodeString(&str, buffer4); InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL); status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); ok(status == STATUS_OBJECT_NAME_NOT_FOUND, - "pNtOpenFile should have failed with STATUS_OBJECT_NAME_NOT_FOUND got(%08lx)\n", status); + "NtOpenFile should have failed with STATUS_OBJECT_NAME_NOT_FOUND got(%08x)\n", status); pNtClose(pipe); } @@ -154,10 +155,10 @@ void test_namespace_pipe(void) #define DIR_TEST_CREATE_FAILURE(h,e) \ status = pNtCreateDirectoryObject(h, DIRECTORY_QUERY, &attr);\ - ok(status == e,"NtCreateDirectoryObject should have failed with %s got(%08lx)\n", #e, status); + ok(status == e,"NtCreateDirectoryObject should have failed with %s got(%08x)\n", #e, status); #define DIR_TEST_OPEN_FAILURE(h,e) \ status = pNtOpenDirectoryObject(h, DIRECTORY_QUERY, &attr);\ - ok(status == e,"NtOpenDirectoryObject should have failed with %s got(%08lx)\n", #e, status); + ok(status == e,"NtOpenDirectoryObject should have failed with %s got(%08x)\n", #e, status); #define DIR_TEST_CREATE_OPEN_FAILURE(h,n,e) \ pRtlCreateUnicodeStringFromAsciiz(&str, n);\ DIR_TEST_CREATE_FAILURE(h,e) DIR_TEST_OPEN_FAILURE(h,e)\ @@ -165,13 +166,13 @@ void test_namespace_pipe(void) #define DIR_TEST_CREATE_SUCCESS(h) \ status = pNtCreateDirectoryObject(h, DIRECTORY_QUERY, &attr); \ - ok(status == STATUS_SUCCESS, "Failed to create Directory(%08lx)\n", status); + ok(status == STATUS_SUCCESS, "Failed to create Directory(%08x)\n", status); #define DIR_TEST_OPEN_SUCCESS(h) \ status = pNtOpenDirectoryObject(h, DIRECTORY_QUERY, &attr); \ - ok(status == STATUS_SUCCESS, "Failed to open Directory(%08lx)\n", status); + ok(status == STATUS_SUCCESS, "Failed to open Directory(%08x)\n", status); #define DIR_TEST_CREATE_OPEN_SUCCESS(h,n) \ pRtlCreateUnicodeStringFromAsciiz(&str, n);\ - DIR_TEST_CREATE_SUCCESS(h) pNtClose(h); DIR_TEST_OPEN_SUCCESS(h) pNtClose(h); \ + DIR_TEST_CREATE_SUCCESS(&h) pNtClose(h); DIR_TEST_OPEN_SUCCESS(&h) pNtClose(h); \ pRtlFreeUnicodeString(&str); static void test_name_collisions(void) @@ -192,13 +193,13 @@ static void test_name_collisions(void) pNtClose(h); status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE); ok(status == STATUS_OBJECT_TYPE_MISMATCH, - "NtCreateMutant should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08lx)\n", status); + "NtCreateMutant should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08x)\n", status); pRtlFreeUnicodeString(&str); pRtlCreateUnicodeStringFromAsciiz(&str, "\\??\\PIPE\\om.c-mutant"); status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE); ok(status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_OBJECT_PATH_NOT_FOUND, - "NtCreateMutant should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08lx)\n", status); + "NtCreateMutant should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08x)\n", status); pRtlFreeUnicodeString(&str); @@ -206,70 +207,70 @@ static void test_name_collisions(void) DIR_TEST_OPEN_SUCCESS(&dir) pRtlCreateUnicodeStringFromAsciiz(&str, "om.c-test"); InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, dir, NULL); - + h = CreateMutexA(NULL, FALSE, "om.c-test"); - ok(h != 0, "CreateMutexA failed got ret=%p (%ld)\n", h, GetLastError()); + ok(h != 0, "CreateMutexA failed got ret=%p (%d)\n", h, GetLastError()); status = pNtCreateMutant(&h1, GENERIC_ALL, &attr, FALSE); ok(status == STATUS_OBJECT_NAME_EXISTS && h1 != NULL, - "NtCreateMutant should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08lx)\n", status); + "NtCreateMutant should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08x)\n", status); h2 = CreateMutexA(NULL, FALSE, "om.c-test"); winerr = GetLastError(); ok(h2 != 0 && winerr == ERROR_ALREADY_EXISTS, - "CreateMutexA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%ld)\n", h2, winerr); + "CreateMutexA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%d)\n", h2, winerr); pNtClose(h); pNtClose(h1); pNtClose(h2); h = CreateEventA(NULL, FALSE, FALSE, "om.c-test"); - ok(h != 0, "CreateEventA failed got ret=%p (%ld)\n", h, GetLastError()); + ok(h != 0, "CreateEventA failed got ret=%p (%d)\n", h, GetLastError()); status = pNtCreateEvent(&h1, GENERIC_ALL, &attr, FALSE, FALSE); ok(status == STATUS_OBJECT_NAME_EXISTS && h1 != NULL, - "NtCreateEvent should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08lx)\n", status); + "NtCreateEvent should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08x)\n", status); h2 = CreateEventA(NULL, FALSE, FALSE, "om.c-test"); winerr = GetLastError(); ok(h2 != 0 && winerr == ERROR_ALREADY_EXISTS, - "CreateEventA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%ld)\n", h2, winerr); + "CreateEventA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%d)\n", h2, winerr); pNtClose(h); pNtClose(h1); pNtClose(h2); h = CreateSemaphoreA(NULL, 1, 2, "om.c-test"); - ok(h != 0, "CreateSemaphoreA failed got ret=%p (%ld)\n", h, GetLastError()); + ok(h != 0, "CreateSemaphoreA failed got ret=%p (%d)\n", h, GetLastError()); status = pNtCreateSemaphore(&h1, GENERIC_ALL, &attr, 1, 2); ok(status == STATUS_OBJECT_NAME_EXISTS && h1 != NULL, - "NtCreateSemaphore should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08lx)\n", status); + "NtCreateSemaphore should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08x)\n", status); h2 = CreateSemaphoreA(NULL, 1, 2, "om.c-test"); winerr = GetLastError(); ok(h2 != 0 && winerr == ERROR_ALREADY_EXISTS, - "CreateSemaphoreA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%ld)\n", h2, winerr); + "CreateSemaphoreA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%d)\n", h2, winerr); pNtClose(h); pNtClose(h1); pNtClose(h2); - - h = CreateWaitableTimerA(NULL, TRUE, "om.c-test"); - ok(h != 0, "CreateWaitableTimerA failed got ret=%p (%ld)\n", h, GetLastError()); + + h = pCreateWaitableTimerA(NULL, TRUE, "om.c-test"); + ok(h != 0, "CreateWaitableTimerA failed got ret=%p (%d)\n", h, GetLastError()); status = pNtCreateTimer(&h1, GENERIC_ALL, &attr, NotificationTimer); ok(status == STATUS_OBJECT_NAME_EXISTS && h1 != NULL, - "NtCreateTimer should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08lx)\n", status); - h2 = CreateWaitableTimerA(NULL, TRUE, "om.c-test"); + "NtCreateTimer should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08x)\n", status); + h2 = pCreateWaitableTimerA(NULL, TRUE, "om.c-test"); winerr = GetLastError(); ok(h2 != 0 && winerr == ERROR_ALREADY_EXISTS, - "CreateWaitableTimerA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%ld)\n", h2, winerr); + "CreateWaitableTimerA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%d)\n", h2, winerr); pNtClose(h); pNtClose(h1); pNtClose(h2); h = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 256, "om.c-test"); - ok(h != 0, "CreateFileMappingA failed got ret=%p (%ld)\n", h, GetLastError()); + ok(h != 0, "CreateFileMappingA failed got ret=%p (%d)\n", h, GetLastError()); size.u.LowPart = 256; size.u.HighPart = 0; status = pNtCreateSection(&h1, SECTION_MAP_WRITE, &attr, &size, PAGE_READWRITE, SEC_COMMIT, 0); ok(status == STATUS_OBJECT_NAME_EXISTS && h1 != NULL, - "NtCreateSection should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08lx)\n", status); + "NtCreateSection should have succeeded with STATUS_OBJECT_NAME_EXISTS got(%08x)\n", status); h2 = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 256, "om.c-test"); winerr = GetLastError(); ok(h2 != 0 && winerr == ERROR_ALREADY_EXISTS, - "CreateFileMappingA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%ld)\n", h2, winerr); + "CreateFileMappingA should have succeeded with ERROR_ALREADY_EXISTS got ret=%p (%d)\n", h2, winerr); pNtClose(h); pNtClose(h1); pNtClose(h2); @@ -278,7 +279,7 @@ static void test_name_collisions(void) pNtClose(dir); } -void test_directory(void) +static void test_directory(void) { NTSTATUS status; UNICODE_STRING str; @@ -288,17 +289,17 @@ void test_directory(void) /* No name and/or no attributes */ status = pNtCreateDirectoryObject(NULL, DIRECTORY_QUERY, &attr); ok(status == STATUS_ACCESS_VIOLATION, - "NtCreateDirectoryObject should have failed with STATUS_ACCESS_VIOLATION got(%08lx)\n", status); + "NtCreateDirectoryObject should have failed with STATUS_ACCESS_VIOLATION got(%08x)\n", status); status = pNtOpenDirectoryObject(NULL, DIRECTORY_QUERY, &attr); ok(status == STATUS_ACCESS_VIOLATION, - "NtOpenDirectoryObject should have failed with STATUS_ACCESS_VIOLATION got(%08lx)\n", status); + "NtOpenDirectoryObject should have failed with STATUS_ACCESS_VIOLATION got(%08x)\n", status); status = pNtCreateDirectoryObject(&h, DIRECTORY_QUERY, NULL); - ok(status == STATUS_SUCCESS, "Failed to create Directory without attributes(%08lx)\n", status); + ok(status == STATUS_SUCCESS, "Failed to create Directory without attributes(%08x)\n", status); pNtClose(h); status = pNtOpenDirectoryObject(&h, DIRECTORY_QUERY, NULL); ok(status == STATUS_INVALID_PARAMETER, - "NtOpenDirectoryObject should have failed with STATUS_INVALID_PARAMETER got(%08lx)\n", status); + "NtOpenDirectoryObject should have failed with STATUS_INVALID_PARAMETER got(%08x)\n", status); InitializeObjectAttributes(&attr, NULL, 0, 0, NULL); DIR_TEST_CREATE_SUCCESS(&dir) @@ -333,8 +334,8 @@ void test_directory(void) /* Can't use symlinks as a directory */ pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Local"); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); - status = pNtOpenSymbolicLinkObject(&dir, SYMBOLIC_LINK_QUERY, &attr);\ - ok(status == STATUS_SUCCESS, "Failed to open SymbolicLink(%08lx)\n", status); + status = pNtOpenSymbolicLinkObject(&dir, SYMBOLIC_LINK_QUERY, &attr); + ok(status == STATUS_SUCCESS, "Failed to open SymbolicLink(%08x)\n", status); pRtlFreeUnicodeString(&str); InitializeObjectAttributes(&attr, &str, 0, dir, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "one more level"); @@ -352,7 +353,7 @@ void test_directory(void) DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_NAME_INVALID) InitializeObjectAttributes(&attr, &str, 0, dir, NULL); - DIR_TEST_CREATE_OPEN_SUCCESS(&h, "") + DIR_TEST_CREATE_OPEN_SUCCESS(h, "") DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\", STATUS_OBJECT_PATH_SYNTAX_BAD) DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\om.c-test", STATUS_OBJECT_PATH_SYNTAX_BAD) DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\om.c-test\\", STATUS_OBJECT_PATH_SYNTAX_BAD) @@ -417,27 +418,27 @@ void test_directory(void) pRtlFreeUnicodeString(&str); InitializeObjectAttributes(&attr, &str, 0, dir, NULL); - /* Test inavalid paths */ + /* Test invalid paths */ pRtlCreateUnicodeStringFromAsciiz(&str, "\\om.c-mutant"); status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE); ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, - "NtCreateMutant should have failed with STATUS_OBJECT_PATH_SYNTAX_BAD got(%08lx)\n", status); + "NtCreateMutant should have failed with STATUS_OBJECT_PATH_SYNTAX_BAD got(%08x)\n", status); pRtlFreeUnicodeString(&str); pRtlCreateUnicodeStringFromAsciiz(&str, "\\om.c-mutant\\"); status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE); ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, - "NtCreateMutant should have failed with STATUS_OBJECT_PATH_SYNTAX_BAD got(%08lx)\n", status); + "NtCreateMutant should have failed with STATUS_OBJECT_PATH_SYNTAX_BAD got(%08x)\n", status); pRtlFreeUnicodeString(&str); pRtlCreateUnicodeStringFromAsciiz(&str, "om.c\\-mutant"); status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE); ok(status == STATUS_OBJECT_PATH_NOT_FOUND, - "NtCreateMutant should have failed with STATUS_OBJECT_PATH_NOT_FOUND got(%08lx)\n", status); + "NtCreateMutant should have failed with STATUS_OBJECT_PATH_NOT_FOUND got(%08x)\n", status); pRtlFreeUnicodeString(&str); pRtlCreateUnicodeStringFromAsciiz(&str, "om.c-mutant"); status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE); - ok(status == STATUS_SUCCESS, "Failed to create Mutant(%08lx)\n", status); + ok(status == STATUS_SUCCESS, "Failed to create Mutant(%08x)\n", status); pRtlFreeUnicodeString(&str); pNtClose(h); @@ -446,10 +447,10 @@ void test_directory(void) #define SYMLNK_TEST_CREATE_FAILURE(h,e) \ status = pNtCreateSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr, &target);\ - ok(status == e,"NtCreateSymbolicLinkObject should have failed with %s got(%08lx)\n", #e, status); + ok(status == e,"NtCreateSymbolicLinkObject should have failed with %s got(%08x)\n", #e, status); #define SYMLNK_TEST_OPEN_FAILURE(h,e) \ status = pNtOpenSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr);\ - ok(status == e,"NtOpenSymbolicLinkObject should have failed with %s got(%08lx)\n", #e, status); + ok(status == e,"NtOpenSymbolicLinkObject should have failed with %s got(%08x)\n", #e, status); #define SYMLNK_TEST_CREATE_OPEN_FAILURE(h,n,t,e) \ pRtlCreateUnicodeStringFromAsciiz(&str, n);\ pRtlCreateUnicodeStringFromAsciiz(&target, t);\ @@ -460,12 +461,12 @@ void test_directory(void) #define SYMLNK_TEST_CREATE_SUCCESS(h) \ status = pNtCreateSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr, &target); \ - ok(status == STATUS_SUCCESS, "Failed to create SymbolicLink(%08lx)\n", status); + ok(status == STATUS_SUCCESS, "Failed to create SymbolicLink(%08x)\n", status); #define SYMLNK_TEST_OPEN_SUCCESS(h) \ status = pNtOpenSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr); \ - ok(status == STATUS_SUCCESS, "Failed to open SymbolicLink(%08lx)\n", status); + ok(status == STATUS_SUCCESS, "Failed to open SymbolicLink(%08x)\n", status); -void test_symboliclink(void) +static void test_symboliclink(void) { NTSTATUS status; UNICODE_STRING str, target; @@ -478,10 +479,17 @@ void test_symboliclink(void) status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL, NULL); ok(status == STATUS_ACCESS_VIOLATION, - "NtCreateSymbolicLinkObject should have failed with STATUS_ACCESS_VIOLATION got(%08lx)\n", status); + "NtCreateSymbolicLinkObject should have failed with STATUS_ACCESS_VIOLATION got(%08x)\n", status); status = pNtOpenSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL); ok(status == STATUS_INVALID_PARAMETER, - "NtOpenSymbolicLinkObject should have failed with STATUS_INVALID_PARAMETER got(%08lx)\n", status); + "NtOpenSymbolicLinkObject should have failed with STATUS_INVALID_PARAMETER got(%08x)\n", status); + + /* No attributes */ + pRtlCreateUnicodeStringFromAsciiz(&target, "\\DosDevices"); + status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL, &target); + ok(status == STATUS_SUCCESS, "NtCreateSymbolicLinkObject failed(%08x)\n", status); + pRtlFreeUnicodeString(&target); + pNtClose(h); InitializeObjectAttributes(&attr, NULL, 0, 0, NULL); SYMLNK_TEST_CREATE_FAILURE(&link, STATUS_INVALID_PARAMETER) @@ -523,7 +531,7 @@ void test_symboliclink(void) pRtlCreateUnicodeStringFromAsciiz(&str, "Local\\test-link\\PIPE"); status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); - todo_wine ok(status == STATUS_SUCCESS, "Failed to open NamedPipe(%08lx)\n", status); + todo_wine ok(status == STATUS_SUCCESS, "Failed to open NamedPipe(%08x)\n", status); pRtlFreeUnicodeString(&str); pNtClose(h); @@ -534,29 +542,36 @@ void test_symboliclink(void) START_TEST(om) { HMODULE hntdll = GetModuleHandleA("ntdll.dll"); - if (hntdll) - { - pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz"); - pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); - pNtCreateEvent = (void *)GetProcAddress(hntdll, "NtCreateEvent"); - pNtCreateMutant = (void *)GetProcAddress(hntdll, "NtCreateMutant"); - pNtOpenMutant = (void *)GetProcAddress(hntdll, "NtOpenMutant"); - pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile"); - pNtClose = (void *)GetProcAddress(hntdll, "NtClose"); - pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); - pNtCreateNamedPipeFile = (void *)GetProcAddress(hntdll, "NtCreateNamedPipeFile"); - pNtOpenDirectoryObject = (void *)GetProcAddress(hntdll, "NtOpenDirectoryObject"); - pNtCreateDirectoryObject= (void *)GetProcAddress(hntdll, "NtCreateDirectoryObject"); - pNtOpenSymbolicLinkObject = (void *)GetProcAddress(hntdll, "NtOpenSymbolicLinkObject"); - pNtCreateSymbolicLinkObject = (void *)GetProcAddress(hntdll, "NtCreateSymbolicLinkObject"); - pNtCreateSemaphore = (void *)GetProcAddress(hntdll, "NtCreateSemaphore"); - pNtCreateTimer = (void *)GetProcAddress(hntdll, "NtCreateTimer"); - pNtCreateSection = (void *)GetProcAddress(hntdll, "NtCreateSection"); + HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); - test_case_sensitive(); - test_namespace_pipe(); - test_name_collisions(); - test_directory(); - test_symboliclink(); + if (!hntdll) + { + skip("not running on NT, skipping test\n"); + return; } + + pCreateWaitableTimerA = (void *)GetProcAddress(hkernel32, "CreateWaitableTimerA"); + + pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz"); + pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); + pNtCreateEvent = (void *)GetProcAddress(hntdll, "NtCreateEvent"); + pNtCreateMutant = (void *)GetProcAddress(hntdll, "NtCreateMutant"); + pNtOpenMutant = (void *)GetProcAddress(hntdll, "NtOpenMutant"); + pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile"); + pNtClose = (void *)GetProcAddress(hntdll, "NtClose"); + pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); + pNtCreateNamedPipeFile = (void *)GetProcAddress(hntdll, "NtCreateNamedPipeFile"); + pNtOpenDirectoryObject = (void *)GetProcAddress(hntdll, "NtOpenDirectoryObject"); + pNtCreateDirectoryObject= (void *)GetProcAddress(hntdll, "NtCreateDirectoryObject"); + pNtOpenSymbolicLinkObject = (void *)GetProcAddress(hntdll, "NtOpenSymbolicLinkObject"); + pNtCreateSymbolicLinkObject = (void *)GetProcAddress(hntdll, "NtCreateSymbolicLinkObject"); + pNtCreateSemaphore = (void *)GetProcAddress(hntdll, "NtCreateSemaphore"); + pNtCreateTimer = (void *)GetProcAddress(hntdll, "NtCreateTimer"); + pNtCreateSection = (void *)GetProcAddress(hntdll, "NtCreateSection"); + + test_case_sensitive(); + test_namespace_pipe(); + test_name_collisions(); + test_directory(); + test_symboliclink(); } diff --git a/rostests/winetests/ntdll/path.c b/rostests/winetests/ntdll/path.c index 8423c09a1cd..99d94829bcb 100755 --- a/rostests/winetests/ntdll/path.c +++ b/rostests/winetests/ntdll/path.c @@ -101,23 +101,22 @@ static void test_RtlIsDosDeviceName(void) { "", 0, 0 }, { "\\\\foo\\nul", 0, 0 }, { "c:\\nul:", 6, 6 }, - { "c:\\nul::", 0, 0 }, + { "c:\\nul::", 6, 6 }, + { "c:\\nul::::::", 6, 6 }, { "c:prn ", 4, 6 }, { "c:prn.......", 4, 6 }, { "c:prn... ...", 4, 6 }, - { "c:NUL .... ", 0, 0 }, + { "c:NUL .... ", 4, 6 }, { "c: . . .", 0, 0 }, { "c:", 0, 0 }, { " . . . :", 0, 0 }, { ":", 0, 0 }, { "c:nul. . . :", 4, 6 }, - { "c:nul . . :", 0, 0 }, + { "c:nul . . :", 4, 6 }, { "c:nul0", 0, 0 }, - { "c:prn:aaa", 0, 0 }, { "c:PRN:.txt", 4, 6 }, { "c:aux:.txt...", 4, 6 }, { "c:prn:.txt:", 4, 6 }, - { "c:nul:aaa", 0, 0 }, { "con:", 0, 6 }, { "lpt1:", 0, 8 }, { "c:com5:", 4, 8 }, @@ -146,6 +145,18 @@ static void test_RtlIsDosDeviceName(void) "Wrong result (%d,%d)/(%d,%d) for %s\n", HIWORD(ret), LOWORD(ret), test->pos, test->len, test->path ); } + + pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, "c:prn:aaa", strlen("c:prn:aaa")+1 ); + ret = pRtlIsDosDeviceName_U( buffer ); + ok( ret == MAKELONG( 6, 4 ) || /* NT */ + ret == MAKELONG( 0, 0), /* win9x */ + "Wrong result (%d,%d)/(4,6) or (0,0) for c:prn:aaa\n", HIWORD(ret), LOWORD(ret) ); + + pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, "c:nul:aaa", strlen("c:nul:aaa")+1 ); + ret = pRtlIsDosDeviceName_U( buffer ); + ok( ret == MAKELONG( 6, 4 ) || /* NT */ + ret == MAKELONG( 0, 0), /* win9x */ + "Wrong result (%d,%d)/(4,6) or (0,0) for c:nul:aaa\n", HIWORD(ret), LOWORD(ret) ); } static void test_RtlIsNameLegalDOS8Dot3(void) @@ -213,7 +224,7 @@ static void test_RtlIsNameLegalDOS8Dot3(void) strcpy( str, test->path ); for (i = 0; str[i]; i++) str[i] = toupper(str[i]); ok( oem_ret.Length == strlen(test->path), "Wrong length %d/%d for '%s'\n", - oem_ret.Length, strlen(test->path), test->path ); + oem_ret.Length, lstrlenA(test->path), test->path ); ok( !memcmp( oem_ret.Buffer, str, oem_ret.Length ), "Wrong string '%.*s'/'%s'\n", oem_ret.Length, oem_ret.Buffer, str ); } @@ -265,7 +276,7 @@ static void test_RtlGetFullPathName_U(void) len= strlen(test->rname) * sizeof(WCHAR); pRtlMultiByteToUnicodeN(pathbufW , sizeof(pathbufW), NULL, test->path, strlen(test->path)+1 ); ret = pRtlGetFullPathName_U( pathbufW,MAX_PATH, rbufferW, &file_part); - ok( ret == len, "Wrong result %ld/%d for \"%s\"\n", ret, len, test->path ); + ok( ret == len, "Wrong result %d/%d for \"%s\"\n", ret, len, test->path ); ok(pRtlUnicodeToMultiByteN(rbufferA,MAX_PATH,&reslen,rbufferW,(lstrlenW(rbufferW) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS, "RtlUnicodeToMultiByteN failed\n"); ok(lstrcmpiA(rbufferA,test->rname) == 0, "Got \"%s\" expected \"%s\"\n",rbufferA,test->rname); diff --git a/rostests/winetests/ntdll/port.c b/rostests/winetests/ntdll/port.c index 6c79970a9ba..971591737a7 100644 --- a/rostests/winetests/ntdll/port.c +++ b/rostests/winetests/ntdll/port.c @@ -20,8 +20,15 @@ #include #include -#include "ntdll_test.h" -#include "windows.h" +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "winnls.h" +#include "wine/test.h" +#include "winternl.h" #ifndef __WINE_WINTERNL_H @@ -146,10 +153,10 @@ static void ProcessConnectionRequest(PLPC_MESSAGE LpcMessage, PHANDLE pAcceptPor ok(!*LpcMessage->Data, "Expected empty string!\n"); status = pNtAcceptConnectPort(pAcceptPortHandle, 0, LpcMessage, 1, 0, NULL); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld\n", status); - + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); + status = pNtCompleteConnectPort(*pAcceptPortHandle); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); } static void ProcessLpcRequest(HANDLE PortHandle, PLPC_MESSAGE LpcMessage) @@ -164,7 +171,7 @@ static void ProcessLpcRequest(HANDLE PortHandle, PLPC_MESSAGE LpcMessage) lstrcpy((LPSTR)LpcMessage->Data, REPLY); status = pNtReplyPort(PortHandle, LpcMessage); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); ok(LpcMessage->MessageType == LPC_REQUEST, "Expected LPC_REQUEST, got %d\n", LpcMessage->MessageType); ok(!lstrcmp((LPSTR)LpcMessage->Data, REPLY), @@ -185,22 +192,22 @@ static DWORD WINAPI test_ports_client(LPVOID arg) sqos.EffectiveOnly = TRUE; status = pNtConnectPort(&PortHandle, &port, &sqos, 0, 0, &len, NULL, NULL); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld\n", status); + todo_wine ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); + if (status != STATUS_SUCCESS) return 1; status = pNtRegisterThreadTerminatePort(PortHandle); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); size = FIELD_OFFSET(LPC_MESSAGE, Data) + MAX_MESSAGE_LEN; - LpcMessage = HeapAlloc(GetProcessHeap(), 0, size); + LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); out = HeapAlloc(GetProcessHeap(), 0, size); - memset(LpcMessage, 0, size); LpcMessage->DataSize = lstrlen(REQUEST1) + 1; LpcMessage->MessageSize = FIELD_OFFSET(LPC_MESSAGE, Data) + LpcMessage->DataSize; lstrcpy((LPSTR)LpcMessage->Data, REQUEST1); status = pNtRequestPort(PortHandle, LpcMessage); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); ok(LpcMessage->MessageType == 0, "Expected 0, got %d\n", LpcMessage->MessageType); ok(!lstrcmp((LPSTR)LpcMessage->Data, REQUEST1), "Expected %s, got %s\n", REQUEST1, LpcMessage->Data); @@ -213,7 +220,7 @@ static DWORD WINAPI test_ports_client(LPVOID arg) /* Send the message and wait for the reply */ status = pNtRequestWaitReplyPort(PortHandle, LpcMessage, out); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); ok(!lstrcmp((LPSTR)out->Data, REPLY), "Expected %s, got %s\n", REPLY, out->Data); ok(out->MessageType == LPC_REPLY, "Expected LPC_REPLY, got %d\n", out->MessageType); @@ -239,19 +246,19 @@ static void test_ports_server(void) status = pNtCreatePort(&PortHandle, &obj, 100, 100, 0); todo_wine { - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); } + if (status != STATUS_SUCCESS) return; size = FIELD_OFFSET(LPC_MESSAGE, Data) + MAX_MESSAGE_LEN; - LpcMessage = HeapAlloc(GetProcessHeap(), 0, size); - memset(LpcMessage, 0, size); + LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); while (TRUE) { status = pNtReplyWaitReceivePort(PortHandle, NULL, NULL, LpcMessage); todo_wine { - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld(%lx)\n", status, status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d(%x)\n", status, status); } /* STATUS_INVALID_HANDLE: win2k without admin rights will perform an * endless loop here diff --git a/rostests/winetests/ntdll/reg.c b/rostests/winetests/ntdll/reg.c index a2ee8d3c382..3efdfabaf45 100755 --- a/rostests/winetests/ntdll/reg.c +++ b/rostests/winetests/ntdll/reg.c @@ -2,7 +2,6 @@ * * Copyright 2003 Thomas Mertes * Copyright 2005 Brad DeMorrow - * Copyright 2006 Dmitry Philippov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -68,6 +67,37 @@ typedef struct _RTL_QUERY_REGISTRY_TABLE { ULONG DefaultLength; } RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE; +typedef struct _KEY_VALUE_BASIC_INFORMATION { + ULONG TitleIndex; + ULONG Type; + ULONG NameLength; + WCHAR Name[1]; +} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION; + +typedef struct _KEY_VALUE_PARTIAL_INFORMATION { + ULONG TitleIndex; + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; +} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; + +typedef struct _KEY_VALUE_FULL_INFORMATION { + ULONG TitleIndex; + ULONG Type; + ULONG DataOffset; + ULONG DataLength; + ULONG NameLength; + WCHAR Name[1]; +} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION; + +typedef enum _KEY_VALUE_INFORMATION_CLASS { + KeyValueBasicInformation, + KeyValueFullInformation, + KeyValuePartialInformation, + KeyValueFullInformationAlign64, + KeyValuePartialInformationAlign64 +} KEY_VALUE_INFORMATION_CLASS; + #define InitializeObjectAttributes(p,n,a,r,s) \ do { \ (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ @@ -85,18 +115,18 @@ static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING); static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING); static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID); static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR); -static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, OUT PHANDLE); +static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, OUT PHKEY); static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES); static NTSTATUS (WINAPI * pNtClose)(IN HANDLE); static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING); -static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE); -static NTSTATUS (WINAPI * pNtCreateKey)( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, +static NTSTATUS (WINAPI * pNtFlushKey)(HKEY); +static NTSTATUS (WINAPI * pNtDeleteKey)(HKEY); +static NTSTATUS (WINAPI * pNtCreateKey)( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, ULONG TitleIndex, const UNICODE_STRING *class, ULONG options, PULONG dispos ); -static NTSTATUS (WINAPI * pNtSetValueKey)( HANDLE, const PUNICODE_STRING, ULONG, +static NTSTATUS (WINAPI * pNtQueryValueKey)(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *); +static NTSTATUS (WINAPI * pNtSetValueKey)( PHKEY, const PUNICODE_STRING, ULONG, ULONG, const PVOID, ULONG ); -static NTSTATUS (WINAPI * pNtQueryValueKey)( HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS, - void *,DWORD,DWORD * ); static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING); static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR); static NTSTATUS (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG); @@ -105,6 +135,7 @@ static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRIN static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID); static NTSTATUS (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG); static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG); +static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*); static HMODULE hntdll = 0; static int CurrentTest = 0; @@ -137,9 +168,10 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(NtClose) NTDLL_GET_PROC(NtDeleteValueKey) NTDLL_GET_PROC(NtCreateKey) + NTDLL_GET_PROC(NtFlushKey) NTDLL_GET_PROC(NtDeleteKey) - NTDLL_GET_PROC(NtSetValueKey) NTDLL_GET_PROC(NtQueryValueKey) + NTDLL_GET_PROC(NtSetValueKey) NTDLL_GET_PROC(NtOpenKey) NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath) NTDLL_GET_PROC(RtlReAllocateHeap) @@ -148,6 +180,7 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(RtlFreeHeap) NTDLL_GET_PROC(RtlAllocateHeap) NTDLL_GET_PROC(RtlZeroMemory) + NTDLL_GET_PROC(RtlpNtQueryValueKey) } return TRUE; } @@ -157,9 +190,8 @@ static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext) { NTSTATUS ret = STATUS_SUCCESS; - LPSTR ValName = 0; - LPSTR ValData = 0; int ValueNameLength = 0; + LPSTR ValName = 0; trace("**Test %d**\n", CurrentTest); if(ValueName) @@ -167,6 +199,7 @@ static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN ValueNameLength = lstrlenW(ValueName); ValName = (LPSTR)pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength); + WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0); trace("ValueName: %s\n", ValName); @@ -174,14 +207,6 @@ static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN else trace("ValueName: (null)\n"); - if( ValueType == REG_SZ || - ValueType == REG_MULTI_SZ || - ValueType == REG_EXPAND_SZ ) - { - ValData = (LPSTR)pRtlAllocateHeap(GetProcessHeap(), 0, ValueLength); - WideCharToMultiByte(0, 0, ValueData, ValueLength, ValData, ValueLength, 0, 0); - } - switch(ValueType) { case REG_NONE: @@ -196,17 +221,17 @@ static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN case REG_SZ: trace("ValueType: REG_SZ\n"); - trace("ValueData: %s\n", ValData); + trace("ValueData: %s\n", (char*)ValueData); break; case REG_MULTI_SZ: trace("ValueType: REG_MULTI_SZ\n"); - trace("ValueData: %s", (char*)ValData); + trace("ValueData: %s\n", (char*)ValueData); break; case REG_EXPAND_SZ: trace("ValueType: REG_EXPAND_SZ\n"); - trace("ValueData: %s\n", (char*)ValData); + trace("ValueData: %s\n", (char*)ValueData); break; case REG_DWORD: @@ -226,9 +251,6 @@ static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN if(ValName) pRtlFreeHeap(GetProcessHeap(), 0, ValName); - if(ValData) - pRtlFreeHeap(GetProcessHeap(), 0, ValData); - return ret; } @@ -261,7 +283,7 @@ static void test_RtlQueryRegistryValues(void) 8)DefaultLength Test Default Length with DefaultType = REG_SZ 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ - 11)DefaultData Test whether DefaultData is used while DefaltType = REG_NONE(shouldn't be) + 11)DefaultData Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be) 12)Delete Try to delete value key */ @@ -284,14 +306,14 @@ static void test_RtlQueryRegistryValues(void) QueryTable[0].DefaultLength = 100; QueryTable[1].QueryRoutine = QueryRoutine; - QueryTable[1].Flags = RTL_QUERY_REGISTRY_DELETE; - QueryTable[1].Name = L"multisztest"; + QueryTable[1].Flags = 0; + QueryTable[1].Name = NULL; QueryTable[1].EntryContext = 0; QueryTable[1].DefaultType = REG_NONE; QueryTable[1].DefaultData = NULL; QueryTable[1].DefaultLength = 0; - QueryTable[2].QueryRoutine = QueryRoutine; + QueryTable[2].QueryRoutine = NULL; QueryTable[2].Flags = 0; QueryTable[2].Name = NULL; QueryTable[2].EntryContext = 0; @@ -300,22 +322,84 @@ static void test_RtlQueryRegistryValues(void) QueryTable[2].DefaultLength = 0; status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0); - ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08lx\n", status); + ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status); pRtlFreeHeap(GetProcessHeap(), 0, QueryTable); } +static void test_NtOpenKey(void) +{ + HANDLE key; + NTSTATUS status; + OBJECT_ATTRIBUTES attr; + ACCESS_MASK am = KEY_READ; + + if (0) + { + /* Crashes Wine */ + /* All NULL */ + status = pNtOpenKey(NULL, 0, NULL); + ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); + + /* NULL attributes */ + status = pNtOpenKey(&key, 0, NULL); + ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */, + "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status); + } + + InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); + + /* NULL key */ + status = pNtOpenKey(NULL, 0, &attr); + todo_wine + ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); + + /* Length > sizeof(OBJECT_ATTRIBUTES) */ + attr.Length *= 2; + status = pNtOpenKey(&key, am, &attr); + todo_wine + ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); +} + static void test_NtCreateKey(void) { /*Create WineTest*/ OBJECT_ATTRIBUTES attr; - HANDLE key; + HKEY key; ACCESS_MASK am = GENERIC_ALL; NTSTATUS status; + /* All NULL */ + status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0); + ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); + + /* Only the key */ + status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0); + ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */, + "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status); + + /* Only accessmask */ + status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0); + ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); + + /* Key and accessmask */ + status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0); + ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */, + "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status); + InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); + + /* Only attributes */ + status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0); + ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); + status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0); - ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08lx\n", status); + ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status); + + /* Length > sizeof(OBJECT_ATTRIBUTES) */ + attr.Length *= 2; + status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0); + ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); pNtClose(key); } @@ -327,39 +411,27 @@ static void test_NtSetValueKey(void) OBJECT_ATTRIBUTES attr; ACCESS_MASK am = KEY_WRITE; UNICODE_STRING ValName; - UNICODE_STRING ValNameMultiSz; DWORD data = 711; - static const WCHAR DataMultiSz[] = {'T','e','s','t','V','a','l','u','e','1',0, - 'T','e','s','t','V','a','l','u','e','2',0, - 'T','e','s','t','V','a','l','u','e','3',0,0, - 'T','e','s','t','V','a','l','u','e','5',0,0,0}; pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest"); + InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); status = pNtOpenKey(&key, am, &attr); - ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status); + ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data)); - ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08lx\n", status); + ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status); pRtlFreeUnicodeString(&ValName); - - pRtlCreateUnicodeStringFromAsciiz(&ValNameMultiSz, "multisztest"); - - status = pNtSetValueKey(key, &ValNameMultiSz, 0, REG_MULTI_SZ, (PVOID)DataMultiSz, sizeof(DataMultiSz)); - ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08lx\n", status); - - pRtlFreeUnicodeString(&ValNameMultiSz); - pNtClose(key); } static void test_RtlOpenCurrentUser(void) { NTSTATUS status; - HANDLE handle; + HKEY handle; status=pRtlOpenCurrentUser(KEY_READ, &handle); - ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08lx\n", status); + ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status); pNtClose(handle); } @@ -368,32 +440,111 @@ static void test_RtlCheckRegistryKey(void) NTSTATUS status; status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer); - ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08lx\n", status); + ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status); status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer); - ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08lx\n", status); + ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status); } -static void test_RtlQueryRegistryDelete(void) +static void test_NtFlushKey(void) +{ + NTSTATUS status; + HANDLE hkey; + OBJECT_ATTRIBUTES attr; + ACCESS_MASK am = KEY_ALL_ACCESS; + + status = pNtFlushKey(NULL); + ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status); + + InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); + pNtOpenKey(&hkey, am, &attr); + + status = pNtFlushKey(hkey); + ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status); + + pNtClose(hkey); +} + +static void test_NtQueryValueKey(void) { HANDLE key; NTSTATUS status; OBJECT_ATTRIBUTES attr; - UNICODE_STRING ValNameMultiSz; - WCHAR sBuf[255]; - DWORD ValueSize; + UNICODE_STRING ValName; + KEY_VALUE_BASIC_INFORMATION *basic_info; + KEY_VALUE_PARTIAL_INFORMATION *partial_info; + KEY_VALUE_FULL_INFORMATION *full_info; + DWORD len; + + pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest"); InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); status = pNtOpenKey(&key, KEY_READ, &attr); - ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status); + ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); - pRtlCreateUnicodeStringFromAsciiz(&ValNameMultiSz, "multisztest"); + len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]); + basic_info = HeapAlloc(GetProcessHeap(), 0, len); + status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len); + ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status); + ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->Type); + ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type); + ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength); + ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len); - status = pNtQueryValueKey(key, &ValNameMultiSz, 0, (void*)sBuf, sizeof(sBuf), &ValueSize); - ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey returns: 0x%08lx instead of STATUS_OBJECT_NAME_NOT_FOUND\n", status); + basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len); + status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len); + ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); + ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->Type); + ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type); + ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength); + ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len); + ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n"); + HeapFree(GetProcessHeap(), 0, basic_info); - pRtlFreeUnicodeString(&ValNameMultiSz); + len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]); + partial_info = HeapAlloc(GetProcessHeap(), 0, len); + status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len); + ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status); + ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->Type); + ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type); + ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength); + ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len); + partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len); + status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len); + ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); + ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->Type); + ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type); + ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength); + ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len); + ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data); + HeapFree(GetProcessHeap(), 0, partial_info); + + len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]); + full_info = HeapAlloc(GetProcessHeap(), 0, len); + status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len); + ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status); + ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->Type); + ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type); + ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength); + ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength); + ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength, + "NtQueryValueKey returned wrong len %d\n", len); + len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength; + + full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len); + status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len); + ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); + ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->Type); + ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type); + ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength); + ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength); + ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n"); + ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n", + *(DWORD *)((char *)full_info + full_info->DataOffset)); + HeapFree(GetProcessHeap(), 0, full_info); + + pRtlFreeUnicodeString(&ValName); pNtClose(key); } @@ -404,13 +555,22 @@ static void test_NtDeleteKey(void) OBJECT_ATTRIBUTES attr; ACCESS_MASK am = KEY_ALL_ACCESS; + status = pNtDeleteKey(NULL); + ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status); + InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); status = pNtOpenKey(&hkey, am, &attr); status = pNtDeleteKey(hkey); - ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08lx\n", status); + ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status); +} - pNtClose(hkey); +static void test_RtlpNtQueryValueKey(void) +{ + NTSTATUS status; + + status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL); + ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status); } START_TEST(reg) @@ -425,12 +585,15 @@ START_TEST(reg) pRtlAppendUnicodeToString(&winetestpath, winetest); + test_NtOpenKey(); test_NtCreateKey(); test_NtSetValueKey(); test_RtlCheckRegistryKey(); test_RtlOpenCurrentUser(); test_RtlQueryRegistryValues(); - test_RtlQueryRegistryDelete(); + test_RtlpNtQueryValueKey(); + test_NtFlushKey(); + test_NtQueryValueKey(); test_NtDeleteKey(); pRtlFreeUnicodeString(&winetestpath); diff --git a/rostests/winetests/ntdll/rtl.c b/rostests/winetests/ntdll/rtl.c index 72de77349f5..443b987c1f2 100755 --- a/rostests/winetests/ntdll/rtl.c +++ b/rostests/winetests/ntdll/rtl.c @@ -130,39 +130,39 @@ static void test_RtlCompareMemoryUlong(void) a[2]= 0x89ab; a[3]= 0xcdef; result = pRtlCompareMemoryUlong(a, 0, 0x0123); - ok(result == 0, "RtlCompareMemoryUlong(%p, 0, 0x0123) returns %lu, expected 0\n", a, result); + ok(result == 0, "RtlCompareMemoryUlong(%p, 0, 0x0123) returns %u, expected 0\n", a, result); result = pRtlCompareMemoryUlong(a, 3, 0x0123); - ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %lu, expected 0\n", a, result); + ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %u, expected 0\n", a, result); result = pRtlCompareMemoryUlong(a, 4, 0x0123); - ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %lu, expected 4\n", a, result); + ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %u, expected 4\n", a, result); result = pRtlCompareMemoryUlong(a, 5, 0x0123); - ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %lu, expected 4\n", a, result); + ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %u, expected 4\n", a, result); result = pRtlCompareMemoryUlong(a, 7, 0x0123); - ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %lu, expected 4\n", a, result); + ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %u, expected 4\n", a, result); result = pRtlCompareMemoryUlong(a, 8, 0x0123); - ok(result == 4, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %lu, expected 4\n", a, result); + ok(result == 4, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %u, expected 4\n", a, result); result = pRtlCompareMemoryUlong(a, 9, 0x0123); - ok(result == 4, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %lu, expected 4\n", a, result); + ok(result == 4, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %u, expected 4\n", a, result); result = pRtlCompareMemoryUlong(a, 4, 0x0127); - ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x0127) returns %lu, expected 0\n", a, result); + ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x0127) returns %u, expected 0\n", a, result); result = pRtlCompareMemoryUlong(a, 4, 0x7123); - ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x7123) returns %lu, expected 0\n", a, result); + ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x7123) returns %u, expected 0\n", a, result); result = pRtlCompareMemoryUlong(a, 16, 0x4567); - ok(result == 0, "RtlCompareMemoryUlong(%p, 16, 0x4567) returns %lu, expected 0\n", a, result); + ok(result == 0, "RtlCompareMemoryUlong(%p, 16, 0x4567) returns %u, expected 0\n", a, result); a[1]= 0x0123; result = pRtlCompareMemoryUlong(a, 3, 0x0123); - ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %lu, expected 0\n", a, result); + ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %u, expected 0\n", a, result); result = pRtlCompareMemoryUlong(a, 4, 0x0123); - ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %lu, expected 4\n", a, result); + ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %u, expected 4\n", a, result); result = pRtlCompareMemoryUlong(a, 5, 0x0123); - ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %lu, expected 4\n", a, result); + ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %u, expected 4\n", a, result); result = pRtlCompareMemoryUlong(a, 7, 0x0123); - ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %lu, expected 4\n", a, result); + ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %u, expected 4\n", a, result); result = pRtlCompareMemoryUlong(a, 8, 0x0123); - ok(result == 8, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %lu, expected 8\n", a, result); + ok(result == 8, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %u, expected 8\n", a, result); result = pRtlCompareMemoryUlong(a, 9, 0x0123); - ok(result == 8, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %lu, expected 8\n", a, result); + ok(result == 8, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %u, expected 8\n", a, result); } #define COPY(len) memset(dest,0,sizeof(dest_aligned_block)); pRtlMoveMemory(dest, src, len) @@ -266,8 +266,8 @@ static void test_RtlUlonglongByteSwap(void) result = pRtlUlonglongByteSwap( ((ULONGLONG)0x76543210 << 32) | 0x87654321 ); ok( (((ULONGLONG)0x21436587 << 32) | 0x10325476) == result, - "RtlUlonglongByteSwap(0x7654321087654321) returns 0x%llx, expected 0x2143658710325476\n", - result); + "RtlUlonglongByteSwap(0x7654321087654321) returns 0x%x%08x, expected 0x2143658710325476\n", + (DWORD)(result >> 32), (DWORD)result); } @@ -301,7 +301,7 @@ static void test_RtlUniform(void) expected = 0x7fffffc3; result = pRtlUniform(&seed); ok(result == expected, - "RtlUniform(&seed (seed == 0)) returns %lx, expected %lx\n", + "RtlUniform(&seed (seed == 0)) returns %x, expected %x\n", result, expected); /* * The algorithm is now: @@ -322,7 +322,7 @@ static void test_RtlUniform(void) expected = seed * 0xffffffed + 0x7fffffc3 + 1; result = pRtlUniform(&seed); ok(result == expected, - "RtlUniform(&seed (seed == 1)) returns %lx, expected %lx\n", + "RtlUniform(&seed (seed == 1)) returns %x, expected %x\n", result, expected); /* * For seed = 2 the const_2 is 0x7fffffc3: @@ -330,9 +330,21 @@ static void test_RtlUniform(void) seed = 2; expected = seed * 0xffffffed + 0x7fffffc3; result = pRtlUniform(&seed); + +/* + * Windows Vista uses different algorithms, so skip the rest of the tests + * until that is figured out. Trace output for the failures is about 10.5 MB! + */ + + if (result == 0x7fffff9f) { + skip("Most likely running on Windows Vista which uses a different algorithm\n"); + return; + } + ok(result == expected, - "RtlUniform(&seed (seed == 2)) returns %lx, expected %lx\n", + "RtlUniform(&seed (seed == 2)) returns %x, expected %x\n", result, expected); + /* * More tests show that if seed is odd the result must be incremented by 1: */ @@ -340,21 +352,21 @@ static void test_RtlUniform(void) expected = seed * 0xffffffed + 0x7fffffc3 + (seed & 1); result = pRtlUniform(&seed); ok(result == expected, - "RtlUniform(&seed (seed == 2)) returns %lx, expected %lx\n", + "RtlUniform(&seed (seed == 3)) returns %x, expected %x\n", result, expected); seed = 0x6bca1aa; expected = seed * 0xffffffed + 0x7fffffc3; result = pRtlUniform(&seed); ok(result == expected, - "RtlUniform(&seed (seed == 0x6bca1aa)) returns %lx, expected %lx\n", + "RtlUniform(&seed (seed == 0x6bca1aa)) returns %x, expected %x\n", result, expected); seed = 0x6bca1ab; expected = seed * 0xffffffed + 0x7fffffc3 + 1; result = pRtlUniform(&seed); ok(result == expected, - "RtlUniform(&seed (seed == 0x6bca1ab)) returns %lx, expected %lx\n", + "RtlUniform(&seed (seed == 0x6bca1ab)) returns %x, expected %x\n", result, expected); /* * When seed is 0x6bca1ac there is an exception: @@ -363,7 +375,7 @@ static void test_RtlUniform(void) expected = seed * 0xffffffed + 0x7fffffc3 + 2; result = pRtlUniform(&seed); ok(result == expected, - "RtlUniform(&seed (seed == 0x6bca1ac)) returns %lx, expected %lx\n", + "RtlUniform(&seed (seed == 0x6bca1ac)) returns %x, expected %x\n", result, expected); /* * Note that up to here const_3 is not used @@ -375,14 +387,14 @@ static void test_RtlUniform(void) expected = (seed * 0xffffffed + 0x7fffffc3) & MAXLONG; result = pRtlUniform(&seed); ok(result == expected, - "RtlUniform(&seed (seed == 0x6bca1ad)) returns %lx, expected %lx\n", + "RtlUniform(&seed (seed == 0x6bca1ad)) returns %x, expected %x\n", result, expected); seed = 0x6bca1ae; expected = (seed * 0xffffffed + 0x7fffffc3 + 1) & MAXLONG; result = pRtlUniform(&seed); ok(result == expected, - "RtlUniform(&seed (seed == 0x6bca1ae)) returns %lx, expected %lx\n", + "RtlUniform(&seed (seed == 0x6bca1ae)) returns %x, expected %x\n", result, expected); /* * There are several ranges where for odd or even seed the result must be @@ -410,7 +422,7 @@ static void test_RtlUniform(void) expected = (expected + (~seed & 1)) & MAXLONG; } else if (seed < 0x1435e50b) { expected = expected + (seed & 1); - } else if (seed < 0x1af286ba) { + } else if (seed < 0x1af286ba) { expected = (expected + (~seed & 1)) & MAXLONG; } else if (seed < 0x21af2869) { expected = expected + (seed & 1); @@ -490,11 +502,11 @@ static void test_RtlUniform(void) seed_bak = seed; result = pRtlUniform(&seed); ok(result == expected, - "test: %llu RtlUniform(&seed (seed == %lx)) returns %lx, expected %lx\n", - num, seed_bak, result, expected); + "test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n", + (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected); ok(seed == expected, - "test: %llu RtlUniform(&seed (seed == %lx)) sets seed to %lx, expected %lx\n", - num, seed_bak, seed, expected); + "test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n", + (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected); } /* for */ /* * Further investigation shows: In the different regions the highest bit @@ -537,11 +549,11 @@ static void test_RtlUniform(void) seed_bak = seed; result = pRtlUniform(&seed); ok(result == expected, - "test: %llu RtlUniform(&seed (seed == %lx)) returns %lx, expected %lx\n", - num, seed_bak, result, expected); + "test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n", + (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected); ok(seed == expected, - "test: %llu RtlUniform(&seed (seed == %lx)) sets seed to %lx, expected %lx\n", - num, seed_bak, seed, expected); + "test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n", + (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected); } /* for */ /* * More tests show that RtlUniform does not return 0x7ffffffd for seed values @@ -616,42 +628,53 @@ static void test_RtlRandom(void) result_expected = 0x320a1743; seed_expected =0x44b; result = pRtlRandom(&seed); + +/* + * Windows Vista uses different algorithms, so skip the rest of the tests + * until that is figured out. Trace output for the failures is about 10.5 MB! + */ + + if (seed == 0x3fc) { + skip("Most likely running on Windows Vista which uses a different algorithm\n"); + return; + } + ok(result == result_expected, - "pRtlRandom(&seed (seed == 0)) returns %lx, expected %lx\n", + "pRtlRandom(&seed (seed == 0)) returns %x, expected %x\n", result, result_expected); ok(seed == seed_expected, - "pRtlRandom(&seed (seed == 0)) sets seed to %lx, expected %lx\n", + "pRtlRandom(&seed (seed == 0)) sets seed to %x, expected %x\n", seed, seed_expected); /* * Seed is not equal to result as with RtlUniform. To see more we - * call RtlRandom aggain with seed set to 0: + * call RtlRandom again with seed set to 0: */ seed = 0; result_expected = 0x7fffffc3; seed_expected =0x44b; result = pRtlRandom(&seed); ok(result == result_expected, - "RtlRandom(&seed (seed == 0)) returns %lx, expected %lx\n", + "RtlRandom(&seed (seed == 0)) returns %x, expected %x\n", result, result_expected); ok(seed == seed_expected, - "RtlRandom(&seed (seed == 0)) sets seed to %lx, expected %lx\n", + "RtlRandom(&seed (seed == 0)) sets seed to %x, expected %x\n", seed, seed_expected); /* * Seed is set to the same value as before but the result is different. - * To see more we call RtlRandom aggain with seed set to 0: + * To see more we call RtlRandom again with seed set to 0: */ seed = 0; result_expected = 0x7fffffc3; seed_expected =0x44b; result = pRtlRandom(&seed); ok(result == result_expected, - "RtlRandom(&seed (seed == 0)) returns %lx, expected %lx\n", + "RtlRandom(&seed (seed == 0)) returns %x, expected %x\n", result, result_expected); ok(seed == seed_expected, - "RtlRandom(&seed (seed == 0)) sets seed to %lx, expected %lx\n", + "RtlRandom(&seed (seed == 0)) sets seed to %x, expected %x\n", seed, seed_expected); /* - * Seed is aggain set to the same value as before. This time we also + * Seed is again set to the same value as before. This time we also * have the same result as before. Interestingly the value of the * result is 0x7fffffc3 which is the same value used in RtlUniform * as const_2. If we do @@ -678,7 +701,7 @@ static void test_RtlRandom(void) * RtlRandom(&seed); * * assigns to seed. Putting these two findings together leads to - * the concluson that RtlRandom saves the value in some variable, + * the conclusion that RtlRandom saves the value in some variable, * like in the following algorithm: * * result = saved_value; @@ -693,10 +716,10 @@ static void test_RtlRandom(void) seed_expected =0x5a1; result = pRtlRandom(&seed); ok(result == result_expected, - "RtlRandom(&seed (seed == 1)) returns %lx, expected %lx\n", + "RtlRandom(&seed (seed == 1)) returns %x, expected %x\n", result, result_expected); ok(seed == seed_expected, - "RtlRandom(&seed (seed == 1)) sets seed to %lx, expected %lx\n", + "RtlRandom(&seed (seed == 1)) sets seed to %x, expected %x\n", seed, seed_expected); /* * If there is just one saved_value the result now would be @@ -725,7 +748,7 @@ static void test_RtlRandom(void) * * What remains to be determined is: The size of the saved_value array, * the initial values of the saved_value array and the function - * position(seed). These tests are not shown here. + * position(seed). These tests are not shown here. * The result of these tests is: The size of the saved_value array * is 128, the initial values can be seen in the my_RtlRandom * function and the position(seed) function is (seed & 0x7f). @@ -754,11 +777,11 @@ static void test_RtlRandom(void) } /* if */ result = pRtlRandom(&seed); ok(result == result_expected, - "test: %llu RtlUniform(&seed (seed == %lx)) returns %lx, expected %lx\n", - num, seed_bak, result, result_expected); + "test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n", + (DWORD)(num >> 32), (DWORD)num, seed_bak, result, result_expected); ok(seed == seed_expected, - "test: %llu RtlUniform(&seed (seed == %lx)) sets seed to %lx, expected %lx\n", - num, seed_bak, seed, seed_expected); + "test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n", + (DWORD)(num >> 32), (DWORD)num, seed_bak, result, seed_expected); } /* for */ } @@ -786,14 +809,14 @@ static const all_accesses_t all_accesses[] = { static void test_RtlAreAllAccessesGranted(void) { - size_t test_num; + unsigned int test_num; BOOLEAN result; for (test_num = 0; test_num < NB_ALL_ACCESSES; test_num++) { result = pRtlAreAllAccessesGranted(all_accesses[test_num].GrantedAccess, all_accesses[test_num].DesiredAccess); ok(all_accesses[test_num].result == result, - "(test %d): RtlAreAllAccessesGranted(%08lx, %08lx) returns %d, expected %d\n", + "(test %d): RtlAreAllAccessesGranted(%08x, %08x) returns %d, expected %d\n", test_num, all_accesses[test_num].GrantedAccess, all_accesses[test_num].DesiredAccess, result, all_accesses[test_num].result); @@ -823,14 +846,14 @@ static const any_accesses_t any_accesses[] = { static void test_RtlAreAnyAccessesGranted(void) { - size_t test_num; + unsigned int test_num; BOOLEAN result; for (test_num = 0; test_num < NB_ANY_ACCESSES; test_num++) { result = pRtlAreAnyAccessesGranted(any_accesses[test_num].GrantedAccess, any_accesses[test_num].DesiredAccess); ok(any_accesses[test_num].result == result, - "(test %d): RtlAreAnyAccessesGranted(%08lx, %08lx) returns %d, expected %d\n", + "(test %d): RtlAreAnyAccessesGranted(%08x, %08x) returns %d, expected %d\n", test_num, any_accesses[test_num].GrantedAccess, any_accesses[test_num].DesiredAccess, result, any_accesses[test_num].result); @@ -844,8 +867,8 @@ static void test_RtlComputeCrc32(void) if (!pRtlComputeCrc32) return; - crc = pRtlComputeCrc32(crc, (LPBYTE)src, LEN); - ok(crc == 0x40861dc2,"Expected 0x40861dc2, got %8lx\n", crc); + crc = pRtlComputeCrc32(crc, (const BYTE *)src, LEN); + ok(crc == 0x40861dc2,"Expected 0x40861dc2, got %8x\n", crc); } @@ -879,7 +902,7 @@ static void test_HandleTables(void) result = pRtlFreeHandle(&HandleTable, &MyHandle->RtlHandle); ok(result, "Couldn't free handle %p\n", MyHandle); status = pRtlDestroyHandleTable(&HandleTable); - ok(status == STATUS_SUCCESS, "RtlDestroyHandleTable failed with error 0x%08lx\n", status); + ok(status == STATUS_SUCCESS, "RtlDestroyHandleTable failed with error 0x%08x\n", status); } static void test_RtlAllocateAndInitializeSid(void) @@ -889,16 +912,16 @@ static void test_RtlAllocateAndInitializeSid(void) PSID psid; ret = pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid); - ok(!ret, "RtlAllocateAndInitializeSid error %08lx\n", ret); + ok(!ret, "RtlAllocateAndInitializeSid error %08x\n", ret); ret = pRtlFreeSid(psid); - ok(!ret, "RtlFreeSid error %08lx\n", ret); + ok(!ret, "RtlFreeSid error %08x\n", ret); /* these tests crash on XP ret = pRtlAllocateAndInitializeSid(NULL, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid); ret = pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, NULL);*/ ret = pRtlAllocateAndInitializeSid(&sia, 9, 1, 2, 3, 4, 5, 6, 7, 8, &psid); - ok(ret == STATUS_INVALID_SID, "wrong error %08lx\n", ret); + ok(ret == STATUS_INVALID_SID, "wrong error %08x\n", ret); } START_TEST(rtl) diff --git a/rostests/winetests/ntdll/rtlbitmap.c b/rostests/winetests/ntdll/rtlbitmap.c index d45eedcaf20..fc7f6c55fc9 100755 --- a/rostests/winetests/ntdll/rtlbitmap.c +++ b/rostests/winetests/ntdll/rtlbitmap.c @@ -425,13 +425,15 @@ static void test_RtlFindMostSignificantBit(void) ulLong <<= i; cPos = pRtlFindMostSignificantBit(ulLong); - ok (cPos == i, "didn't find MSB %llx %d %d\n", ulLong, i, cPos); + ok (cPos == i, "didn't find MSB 0x%x%08x %d %d\n", + (DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos); /* Set all bits lower than bit i */ ulLong = ((ulLong - 1) << 1) | 1; cPos = pRtlFindMostSignificantBit(ulLong); - ok (cPos == i, "didn't find MSB %llx %d %d\n", ulLong, i, cPos); + ok (cPos == i, "didn't find MSB 0x%x%08x %d %d\n", + (DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos); } cPos = pRtlFindMostSignificantBit(0); ok (cPos == -1, "found bit when not set\n"); @@ -451,12 +453,14 @@ static void test_RtlFindLeastSignificantBit(void) ulLong = (ULONGLONG)1 << i; cPos = pRtlFindLeastSignificantBit(ulLong); - ok (cPos == i, "didn't find LSB %llx %d %d\n", ulLong, i, cPos); + ok (cPos == i, "didn't find LSB 0x%x%08x %d %d\n", + (DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos); ulLong = ~((ULONGLONG)0) << i; cPos = pRtlFindLeastSignificantBit(ulLong); - ok (cPos == i, "didn't find LSB %llx %d %d\n", ulLong, i, cPos); + ok (cPos == i, "didn't find LSB 0x%x%08x %d %d\n", + (DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos); } cPos = pRtlFindLeastSignificantBit(0); ok (cPos == -1, "found bit when not set\n"); @@ -528,7 +532,7 @@ static void test_RtlFindSetRuns(void) ULONG ulStart = 0; ulCount = pRtlFindLongestRunSet(&bm, &ulStart); - ok(ulCount == 33 && ulStart == 1877,"didn't find longest %ld %ld\n",ulCount,ulStart); + ok(ulCount == 33 && ulStart == 1877,"didn't find longest %d %d\n",ulCount,ulStart); memset(buff, 0, sizeof(buff)); ulCount = pRtlFindLongestRunSet(&bm, &ulStart); diff --git a/rostests/winetests/ntdll/rtlstr.c b/rostests/winetests/ntdll/rtlstr.c index b60f54fdab2..5239de07e04 100755 --- a/rostests/winetests/ntdll/rtlstr.c +++ b/rostests/winetests/ntdll/rtlstr.c @@ -62,6 +62,7 @@ static NTSTATUS (WINAPI *pRtlUpperString)(STRING *, const STRING *); static NTSTATUS (WINAPI *pRtlValidateUnicodeString)(long, UNICODE_STRING *); static NTSTATUS (WINAPI *pRtlGUIDFromString)(const UNICODE_STRING*,GUID*); static NTSTATUS (WINAPI *pRtlStringFromGUID)(const GUID*, UNICODE_STRING*); +static BOOLEAN (WINAPI *pRtlIsTextUnicode)(LPVOID, INT, INT *); /*static VOID (WINAPI *pRtlFreeOemString)(PSTRING);*/ /*static VOID (WINAPI *pRtlFreeUnicodeString)(PUNICODE_STRING);*/ @@ -82,7 +83,6 @@ static NTSTATUS (WINAPI *pRtlStringFromGUID)(const GUID*, UNICODE_STRING*); /*static NTSTATUS (WINAPI *pRtlUpcaseUnicodeToOemN)(LPSTR, DWORD, LPDWORD, LPCWSTR, DWORD);*/ /*static UINT (WINAPI *pRtlOemToUnicodeSize)(const STRING *);*/ /*static DWORD (WINAPI *pRtlAnsiStringToUnicodeSize)(const STRING *);*/ -/*static DWORD (WINAPI *pRtlIsTextUnicode)(LPVOID, DWORD, DWORD *);*/ static WCHAR* AtoW( const char* p ) @@ -130,6 +130,7 @@ static void InitFunctionPtrs(void) pRtlValidateUnicodeString = (void *)GetProcAddress(hntdll, "RtlValidateUnicodeString"); pRtlGUIDFromString = (void *)GetProcAddress(hntdll, "RtlGUIDFromString"); pRtlStringFromGUID = (void *)GetProcAddress(hntdll, "RtlStringFromGUID"); + pRtlIsTextUnicode = (void *)GetProcAddress(hntdll, "RtlIsTextUnicode"); } } @@ -199,7 +200,7 @@ static void test_RtlInitUnicodeStringEx(void) uni.Buffer = (void *) 0xdeadbeef; result = pRtlInitUnicodeStringEx(&uni, teststring); ok(result == STATUS_SUCCESS, - "pRtlInitUnicodeStringEx(&uni, 0) returns %lx, expected 0\n", + "pRtlInitUnicodeStringEx(&uni, 0) returns %x, expected 0\n", result); ok(uni.Length == 32, "pRtlInitUnicodeStringEx(&uni, 0) sets Length to %u, expected %u\n", @@ -230,7 +231,7 @@ static void test_RtlInitUnicodeStringEx(void) uni.Buffer = (void *) 0xdeadbeef; result = pRtlInitUnicodeStringEx(&uni, teststring2); ok(result == STATUS_NAME_TOO_LONG, - "pRtlInitUnicodeStringEx(&uni, 0) returns %lx, expected %lx\n", + "pRtlInitUnicodeStringEx(&uni, 0) returns %x, expected %x\n", result, STATUS_NAME_TOO_LONG); ok(uni.Length == 12345, "pRtlInitUnicodeStringEx(&uni, 0) sets Length to %u, expected %u\n", @@ -246,12 +247,12 @@ static void test_RtlInitUnicodeStringEx(void) uni.MaximumLength = 12345; uni.Buffer = (void *) 0xdeadbeef; pRtlInitUnicodeString(&uni, teststring2); - ok(uni.Length == 33920, + ok(uni.Length == 33920 /* <= Win2000 */ || uni.Length == 65532 /* >= Win XP */, "pRtlInitUnicodeString(&uni, 0) sets Length to %u, expected %u\n", - uni.Length, 33920); - ok(uni.MaximumLength == 33922, + uni.Length, 65532); + ok(uni.MaximumLength == 33922 /* <= Win2000 */ || uni.MaximumLength == 65534 /* >= Win XP */, "pRtlInitUnicodeString(&uni, 0) sets MaximumLength to %u, expected %u\n", - uni.MaximumLength, 33922); + uni.MaximumLength, 65534); ok(uni.Buffer == teststring2, "pRtlInitUnicodeString(&uni, 0) sets Buffer to %p, expected %p\n", uni.Buffer, teststring2); @@ -263,7 +264,7 @@ static void test_RtlInitUnicodeStringEx(void) uni.Buffer = (void *) 0xdeadbeef; result = pRtlInitUnicodeStringEx(&uni, 0); ok(result == STATUS_SUCCESS, - "pRtlInitUnicodeStringEx(&uni, 0) returns %lx, expected 0\n", + "pRtlInitUnicodeStringEx(&uni, 0) returns %x, expected 0\n", result); ok(uni.Length == 0, "pRtlInitUnicodeStringEx(&uni, 0) sets Length to %u, expected %u\n", @@ -288,6 +289,8 @@ static void test_RtlInitUnicodeStringEx(void) ok(uni.Buffer == NULL, "pRtlInitUnicodeString(&uni, 0) sets Buffer to %p, expected %p\n", uni.Buffer, NULL); + + free(teststring2); } @@ -397,7 +400,7 @@ static void test_RtlDuplicateUnicodeString(void) CHAR dest_ansi_buf[257]; STRING dest_ansi_str; NTSTATUS result; - size_t test_num; + unsigned int test_num; for (test_num = 0; test_num < NB_DUPL_USTR; test_num++) { source_str.Length = dupl_ustr[test_num].source_Length; @@ -439,7 +442,7 @@ static void test_RtlDuplicateUnicodeString(void) dest_ansi_buf[dest_ansi_str.Length] = '\0'; dest_ansi_str.Buffer = dest_ansi_buf; ok(result == dupl_ustr[test_num].result, - "(test %d): RtlDuplicateUnicodeString(%d, source, dest) has result %lx, expected %lx\n", + "(test %d): RtlDuplicateUnicodeString(%d, source, dest) has result %x, expected %x\n", test_num, dupl_ustr[test_num].add_nul, result, dupl_ustr[test_num].result); ok(dest_str.Length == dupl_ustr[test_num].res_Length, "(test %d): RtlDuplicateUnicodeString(%d, source, dest) destination has Length %d, expected %d\n", @@ -637,7 +640,7 @@ static void test_RtlDowncaseUnicodeString(void) UNICODE_STRING result_str; UNICODE_STRING lower_str; - for (i = 0; i <= 1024; i++) { + for (i = 0; i < 1024; i++) { ch = (WCHAR) i; if (ch >= 'A' && ch <= 'Z') { lower_ch = ch - 'A' + 'a'; @@ -678,7 +681,6 @@ static void test_RtlDowncaseUnicodeString(void) case 0x38c: lower_ch = 0x3cc; break; case 0x38e: lower_ch = 0x3cd; break; case 0x38f: lower_ch = 0x3ce; break; - case 0x400: lower_ch = 0x0; break; default: lower_ch = ch; break; } /* switch */ } @@ -754,7 +756,7 @@ static void test_RtlUnicodeStringToAnsiString(void) STRING ansi_str; UNICODE_STRING uni_str; NTSTATUS result; - size_t test_num; + unsigned int test_num; for (test_num = 0; test_num < NB_USTR2ASTR; test_num++) { ansi_str.Length = ustr2astr[test_num].ansi_Length; @@ -778,7 +780,7 @@ static void test_RtlUnicodeStringToAnsiString(void) } result = pRtlUnicodeStringToAnsiString(&ansi_str, &uni_str, ustr2astr[test_num].doalloc); ok(result == ustr2astr[test_num].result, - "(test %d): RtlUnicodeStringToAnsiString(ansi, uni, %d) has result %lx, expected %lx\n", + "(test %d): RtlUnicodeStringToAnsiString(ansi, uni, %d) has result %x, expected %x\n", test_num, ustr2astr[test_num].doalloc, result, ustr2astr[test_num].result); ok(ansi_str.Length == ustr2astr[test_num].res_Length, "(test %d): RtlUnicodeStringToAnsiString(ansi, uni, %d) ansi has Length %d, expected %d\n", @@ -825,7 +827,7 @@ static void test_RtlAppendAsciizToString(void) CHAR dest_buf[257]; STRING dest_str; NTSTATUS result; - size_t test_num; + unsigned int test_num; for (test_num = 0; test_num < NB_APP_ASC2STR; test_num++) { dest_str.Length = app_asc2str[test_num].dest_Length; @@ -839,7 +841,7 @@ static void test_RtlAppendAsciizToString(void) } result = pRtlAppendAsciizToString(&dest_str, app_asc2str[test_num].src); ok(result == app_asc2str[test_num].result, - "(test %d): RtlAppendAsciizToString(dest, src) has result %lx, expected %lx\n", + "(test %d): RtlAppendAsciizToString(dest, src) has result %x, expected %x\n", test_num, result, app_asc2str[test_num].result); ok(dest_str.Length == app_asc2str[test_num].res_Length, "(test %d): RtlAppendAsciizToString(dest, src) dest has Length %d, expected %d\n", @@ -897,7 +899,7 @@ static void test_RtlAppendStringToString(void) STRING dest_str; STRING src_str; NTSTATUS result; - size_t test_num; + unsigned int test_num; for (test_num = 0; test_num < NB_APP_STR2STR; test_num++) { dest_str.Length = app_str2str[test_num].dest_Length; @@ -920,7 +922,7 @@ static void test_RtlAppendStringToString(void) } result = pRtlAppendStringToString(&dest_str, &src_str); ok(result == app_str2str[test_num].result, - "(test %d): RtlAppendStringToString(dest, src) has result %lx, expected %lx\n", + "(test %d): RtlAppendStringToString(dest, src) has result %x, expected %x\n", test_num, result, app_str2str[test_num].result); ok(dest_str.Length == app_str2str[test_num].res_Length, "(test %d): RtlAppendStringToString(dest, src) dest has Length %d, expected %d\n", @@ -978,7 +980,7 @@ static void test_RtlAppendUnicodeToString(void) WCHAR dest_buf[257]; UNICODE_STRING dest_str; NTSTATUS result; - size_t test_num; + unsigned int test_num; for (test_num = 0; test_num < NB_APP_UNI2STR; test_num++) { dest_str.Length = app_uni2str[test_num].dest_Length; @@ -992,7 +994,7 @@ static void test_RtlAppendUnicodeToString(void) } result = pRtlAppendUnicodeToString(&dest_str, (LPCWSTR) app_uni2str[test_num].src); ok(result == app_uni2str[test_num].result, - "(test %d): RtlAppendUnicodeToString(dest, src) has result %lx, expected %lx\n", + "(test %d): RtlAppendUnicodeToString(dest, src) has result %x, expected %x\n", test_num, result, app_uni2str[test_num].result); ok(dest_str.Length == app_uni2str[test_num].res_Length, "(test %d): RtlAppendUnicodeToString(dest, src) dest has Length %d, expected %d\n", @@ -1033,7 +1035,7 @@ static const app_ustr2str_t app_ustr2str[] = { { 4, 12, 14, "Fake0123abcdef", 4, 6, 8, "UstrZYXW", 8, 12, 14, "FakeUstr\0\0cdef", STATUS_SUCCESS}, { 4, 11, 14, "Fake0123abcdef", 4, 6, 8, "UstrZYXW", 8, 11, 14, "FakeUstr\0\0cdef", STATUS_SUCCESS}, { 4, 10, 14, "Fake0123abcdef", 4, 6, 8, "UstrZYXW", 8, 10, 14, "FakeUstr\0\0cdef", STATUS_SUCCESS}, -/* In the following test the native function writes beyond MaximumLength +/* In the following test the native function writes beyond MaximumLength * { 4, 9, 14, "Fake0123abcdef", 4, 6, 8, "UstrZYXW", 8, 9, 14, "FakeUstrabcdef", STATUS_SUCCESS}, */ { 4, 8, 14, "Fake0123abcdef", 4, 6, 8, "UstrZYXW", 8, 8, 14, "FakeUstrabcdef", STATUS_SUCCESS}, @@ -1054,7 +1056,7 @@ static void test_RtlAppendUnicodeStringToString(void) UNICODE_STRING dest_str; UNICODE_STRING src_str; NTSTATUS result; - size_t test_num; + unsigned int test_num; for (test_num = 0; test_num < NB_APP_USTR2STR; test_num++) { dest_str.Length = app_ustr2str[test_num].dest_Length; @@ -1077,7 +1079,7 @@ static void test_RtlAppendUnicodeStringToString(void) } result = pRtlAppendUnicodeStringToString(&dest_str, &src_str); ok(result == app_ustr2str[test_num].result, - "(test %d): RtlAppendStringToString(dest, src) has result %lx, expected %lx\n", + "(test %d): RtlAppendStringToString(dest, src) has result %x, expected %x\n", test_num, result, app_ustr2str[test_num].result); ok(dest_str.Length == app_ustr2str[test_num].res_Length, "(test %d): RtlAppendStringToString(dest, src) dest has Length %d, expected %d\n", @@ -1165,8 +1167,8 @@ static void test_RtlFindCharInUnicodeString(void) UNICODE_STRING search_chars; USHORT pos; NTSTATUS result; - size_t idx; - size_t test_num; + unsigned int idx; + unsigned int test_num; for (test_num = 0; test_num < NB_FIND_CH_IN_USTR; test_num++) { if (find_ch_in_ustr[test_num].main_str != NULL) { @@ -1196,7 +1198,7 @@ static void test_RtlFindCharInUnicodeString(void) pos = 12345; result = pRtlFindCharInUnicodeString(find_ch_in_ustr[test_num].flags, &main_str, &search_chars, &pos); ok(result == find_ch_in_ustr[test_num].result, - "(test %d): RtlFindCharInUnicodeString(%d, %s, %s, [out]) has result %lx, expected %lx\n", + "(test %d): RtlFindCharInUnicodeString(%d, %s, %s, [out]) has result %x, expected %x\n", test_num, find_ch_in_ustr[test_num].flags, find_ch_in_ustr[test_num].main_str, find_ch_in_ustr[test_num].search_chars, result, find_ch_in_ustr[test_num].result); @@ -1280,7 +1282,7 @@ static const str2int_t str2int[] = { { 0, "0o7", 7, STATUS_SUCCESS}, /* one digit octal */ { 0, "0o8", 0, STATUS_SUCCESS}, /* empty octal */ { 0, "0o", 0, STATUS_SUCCESS}, /* empty octal */ - { 0, "0d1011101100", 0, STATUS_SUCCESS}, /* explizit decimal with 0d */ + { 0, "0d1011101100", 0, STATUS_SUCCESS}, /* explicit decimal with 0d */ { 0, "x89abcdef", 0, STATUS_SUCCESS}, /* Hex with lower case digits a-f (x-notation) */ { 0, "xFEDCBA00", 0, STATUS_SUCCESS}, /* Hex with upper case digits A-F (x-notation) */ { 0, "-xFEDCBA00", 0, STATUS_SUCCESS}, /* Negative Hexadecimal (x-notation) */ @@ -1335,7 +1337,7 @@ static const str2int_t str2int[] = { static void test_RtlUnicodeStringToInteger(void) { - size_t test_num; + unsigned int test_num; int value; NTSTATUS result; WCHAR *wstr; @@ -1347,7 +1349,7 @@ static void test_RtlUnicodeStringToInteger(void) pRtlInitUnicodeString(&uni, wstr); result = pRtlUnicodeStringToInteger(&uni, str2int[test_num].base, &value); ok(result == str2int[test_num].result, - "(test %d): RtlUnicodeStringToInteger(\"%s\", %d, [out]) has result %lx, expected: %lx\n", + "(test %d): RtlUnicodeStringToInteger(\"%s\", %d, [out]) has result %x, expected: %x\n", test_num, str2int[test_num].str, str2int[test_num].base, result, str2int[test_num].result); ok(value == str2int[test_num].value, "(test %d): RtlUnicodeStringToInteger(\"%s\", %d, [out]) assigns value %d, expected: %d\n", @@ -1359,17 +1361,17 @@ static void test_RtlUnicodeStringToInteger(void) pRtlInitUnicodeString(&uni, wstr); result = pRtlUnicodeStringToInteger(&uni, str2int[1].base, NULL); ok(result == STATUS_ACCESS_VIOLATION, - "call failed: RtlUnicodeStringToInteger(\"%s\", %d, NULL) has result %lx\n", + "call failed: RtlUnicodeStringToInteger(\"%s\", %d, NULL) has result %x\n", str2int[1].str, str2int[1].base, result); result = pRtlUnicodeStringToInteger(&uni, 20, NULL); ok(result == STATUS_INVALID_PARAMETER, - "call failed: RtlUnicodeStringToInteger(\"%s\", 20, NULL) has result %lx\n", + "call failed: RtlUnicodeStringToInteger(\"%s\", 20, NULL) has result %x\n", str2int[1].str, result); uni.Length = 10; /* Make Length shorter (5 WCHARS instead of 7) */ result = pRtlUnicodeStringToInteger(&uni, str2int[1].base, &value); ok(result == STATUS_SUCCESS, - "call failed: RtlUnicodeStringToInteger(\"12345\", %d, [out]) has result %lx\n", + "call failed: RtlUnicodeStringToInteger(\"12345\", %d, [out]) has result %x\n", str2int[1].base, result); ok(value == 12345, "didn't return expected value (test a): expected: %d, got: %d\n", @@ -1378,7 +1380,7 @@ static void test_RtlUnicodeStringToInteger(void) uni.Length = 5; /* Use odd Length (2.5 WCHARS) */ result = pRtlUnicodeStringToInteger(&uni, str2int[1].base, &value); ok(result == STATUS_SUCCESS, - "call failed: RtlUnicodeStringToInteger(\"12\", %d, [out]) has result %lx\n", + "call failed: RtlUnicodeStringToInteger(\"12\", %d, [out]) has result %x\n", str2int[1].base, result); ok(value == 12, "didn't return expected value (test b): expected: %d, got: %d\n", @@ -1387,7 +1389,7 @@ static void test_RtlUnicodeStringToInteger(void) uni.Length = 2; result = pRtlUnicodeStringToInteger(&uni, str2int[1].base, &value); ok(result == STATUS_SUCCESS, - "call failed: RtlUnicodeStringToInteger(\"1\", %d, [out]) has result %lx\n", + "call failed: RtlUnicodeStringToInteger(\"1\", %d, [out]) has result %x\n", str2int[1].base, result); ok(value == 1, "didn't return expected value (test c): expected: %d, got: %d\n", @@ -1399,7 +1401,7 @@ static void test_RtlUnicodeStringToInteger(void) static void test_RtlCharToInteger(void) { - size_t test_num; + unsigned int test_num; int value; NTSTATUS result; @@ -1409,7 +1411,7 @@ static void test_RtlCharToInteger(void) value = 0xdeadbeef; result = pRtlCharToInteger(str2int[test_num].str, str2int[test_num].base, &value); ok(result == str2int[test_num].result, - "(test %d): call failed: RtlCharToInteger(\"%s\", %d, [out]) has result %lx, expected: %lx\n", + "(test %d): call failed: RtlCharToInteger(\"%s\", %d, [out]) has result %x, expected: %x\n", test_num, str2int[test_num].str, str2int[test_num].base, result, str2int[test_num].result); ok(value == str2int[test_num].value, "(test %d): call failed: RtlCharToInteger(\"%s\", %d, [out]) assigns value %d, expected: %d\n", @@ -1419,12 +1421,12 @@ static void test_RtlCharToInteger(void) result = pRtlCharToInteger(str2int[1].str, str2int[1].base, NULL); ok(result == STATUS_ACCESS_VIOLATION, - "call failed: RtlCharToInteger(\"%s\", %d, NULL) has result %lx\n", + "call failed: RtlCharToInteger(\"%s\", %d, NULL) has result %x\n", str2int[1].str, str2int[1].base, result); result = pRtlCharToInteger(str2int[1].str, 20, NULL); ok(result == STATUS_INVALID_PARAMETER, - "call failed: RtlCharToInteger(\"%s\", 20, NULL) has result %lx\n", + "call failed: RtlCharToInteger(\"%s\", 20, NULL) has result %x\n", str2int[1].str, result); } @@ -1592,22 +1594,22 @@ static void one_RtlIntegerToUnicodeString_test(int test_num, const int2str_t *in } } else { ok(result == int2str->result, - "(test %d): RtlIntegerToUnicodeString(%lu, %d, [out]) has result %lx, expected: %lx\n", + "(test %d): RtlIntegerToUnicodeString(%u, %d, [out]) has result %x, expected: %x\n", test_num, int2str->value, int2str->base, result, int2str->result); if (result == STATUS_SUCCESS) { ok(unicode_string.Buffer[unicode_string.Length/sizeof(WCHAR)] == '\0', - "(test %d): RtlIntegerToUnicodeString(%lu, %d, [out]) string \"%s\" is not NULL terminated\n", + "(test %d): RtlIntegerToUnicodeString(%u, %d, [out]) string \"%s\" is not NULL terminated\n", test_num, int2str->value, int2str->base, ansi_str.Buffer); } } ok(memcmp(unicode_string.Buffer, expected_unicode_string.Buffer, STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0, - "(test %d): RtlIntegerToUnicodeString(%lu, %d, [out]) assigns string \"%s\", expected: \"%s\"\n", + "(test %d): RtlIntegerToUnicodeString(%u, %d, [out]) assigns string \"%s\", expected: \"%s\"\n", test_num, int2str->value, int2str->base, ansi_str.Buffer, expected_ansi_str.Buffer); ok(unicode_string.Length == expected_unicode_string.Length, - "(test %d): RtlIntegerToUnicodeString(%lu, %d, [out]) string has Length %d, expected: %d\n", + "(test %d): RtlIntegerToUnicodeString(%u, %d, [out]) string has Length %d, expected: %d\n", test_num, int2str->value, int2str->base, unicode_string.Length, expected_unicode_string.Length); ok(unicode_string.MaximumLength == expected_unicode_string.MaximumLength, - "(test %d): RtlIntegerToUnicodeString(%lu, %d, [out]) string has MaximumLength %d, expected: %d\n", + "(test %d): RtlIntegerToUnicodeString(%u, %d, [out]) string has MaximumLength %d, expected: %d\n", test_num, int2str->value, int2str->base, unicode_string.MaximumLength, expected_unicode_string.MaximumLength); pRtlFreeAnsiString(&expected_ansi_str); pRtlFreeAnsiString(&ansi_str); @@ -1632,10 +1634,10 @@ static void one_RtlIntegerToChar_test(int test_num, const int2str_t *int2str) dest_str[STRI_BUFFER_LENGTH] = '\0'; result = pRtlIntegerToChar(int2str->value, int2str->base, int2str->MaximumLength, dest_str); ok(result == int2str->result, - "(test %d): RtlIntegerToChar(%lu, %d, %d, [out]) has result %lx, expected: %lx\n", + "(test %d): RtlIntegerToChar(%u, %d, %d, [out]) has result %x, expected: %x\n", test_num, int2str->value, int2str->base, int2str->MaximumLength, result, int2str->result); ok(memcmp(dest_str, int2str->Buffer, STRI_BUFFER_LENGTH) == 0, - "(test %d): RtlIntegerToChar(%lu, %d, %d, [out]) assigns string \"%s\", expected: \"%s\"\n", + "(test %d): RtlIntegerToChar(%u, %d, %d, [out]) assigns string \"%s\", expected: \"%s\"\n", test_num, int2str->value, int2str->base, int2str->MaximumLength, dest_str, int2str->Buffer); } @@ -1650,25 +1652,75 @@ static void test_RtlIntegerToChar(void) result = pRtlIntegerToChar(int2str[0].value, 20, int2str[0].MaximumLength, NULL); ok(result == STATUS_INVALID_PARAMETER, - "(test a): RtlIntegerToChar(%lu, %d, %d, NULL) has result %lx, expected: %lx\n", + "(test a): RtlIntegerToChar(%u, %d, %d, NULL) has result %x, expected: %x\n", int2str[0].value, 20, int2str[0].MaximumLength, result, STATUS_INVALID_PARAMETER); result = pRtlIntegerToChar(int2str[0].value, 20, 0, NULL); ok(result == STATUS_INVALID_PARAMETER, - "(test b): RtlIntegerToChar(%lu, %d, %d, NULL) has result %lx, expected: %lx\n", + "(test b): RtlIntegerToChar(%u, %d, %d, NULL) has result %x, expected: %x\n", int2str[0].value, 20, 0, result, STATUS_INVALID_PARAMETER); result = pRtlIntegerToChar(int2str[0].value, int2str[0].base, 0, NULL); ok(result == STATUS_BUFFER_OVERFLOW, - "(test c): RtlIntegerToChar(%lu, %d, %d, NULL) has result %lx, expected: %lx\n", + "(test c): RtlIntegerToChar(%u, %d, %d, NULL) has result %x, expected: %x\n", int2str[0].value, int2str[0].base, 0, result, STATUS_BUFFER_OVERFLOW); result = pRtlIntegerToChar(int2str[0].value, int2str[0].base, int2str[0].MaximumLength, NULL); ok(result == STATUS_ACCESS_VIOLATION, - "(test d): RtlIntegerToChar(%lu, %d, %d, NULL) has result %lx, expected: %lx\n", + "(test d): RtlIntegerToChar(%u, %d, %d, NULL) has result %x, expected: %x\n", int2str[0].value, int2str[0].base, int2str[0].MaximumLength, result, STATUS_ACCESS_VIOLATION); } +static void test_RtlIsTextUnicode(void) +{ + char ascii[] = "A simple string"; + WCHAR unicode[] = {'A',' ','U','n','i','c','o','d','e',' ','s','t','r','i','n','g',0}; + WCHAR *be_unicode; + int flags; + int i; + + ok(!pRtlIsTextUnicode(ascii, sizeof(ascii), NULL), "ASCII text detected as Unicode\n"); + + ok(pRtlIsTextUnicode(unicode, sizeof(unicode), NULL), "Text should be Unicode\n"); + ok(!pRtlIsTextUnicode(unicode, sizeof(unicode) - 1, NULL), "Text should be Unicode\n"); + + flags = IS_TEXT_UNICODE_UNICODE_MASK; + ok(pRtlIsTextUnicode(unicode, sizeof(unicode), &flags), "Text should not pass a Unicode\n"); + todo_wine + ok(flags == (IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_CONTROLS), + "Expected flags 0x6, obtained %x\n", flags); + + flags = IS_TEXT_UNICODE_REVERSE_MASK; + ok(!pRtlIsTextUnicode(unicode, sizeof(unicode), &flags), "Text should not pass reverse Unicode tests\n"); + ok(flags == 0, "Expected flags 0, obtained %x\n", flags); + + flags = IS_TEXT_UNICODE_ODD_LENGTH; + ok(!pRtlIsTextUnicode(unicode, sizeof(unicode) - 1, &flags), "Odd length test should have passed\n"); + ok(flags == IS_TEXT_UNICODE_ODD_LENGTH, "Expected flags 0x200, obtained %x\n", flags); + + be_unicode = HeapAlloc(GetProcessHeap(), 0, sizeof(unicode) + sizeof(WCHAR)); + be_unicode[0] = 0xfffe; + for (i = 0; i < sizeof(unicode)/sizeof(unicode[0]); i++) + { + be_unicode[i + 1] = (unicode[i] >> 8) | ((unicode[i] & 0xff) << 8); + } + ok(!pRtlIsTextUnicode(be_unicode, sizeof(unicode) + 2, NULL), "Reverse endian should not be Unicode\n"); + todo_wine ok(!pRtlIsTextUnicode(&be_unicode[1], sizeof(unicode), NULL), "Reverse endian should not be Unicode\n"); + + flags = IS_TEXT_UNICODE_REVERSE_MASK; + ok(!pRtlIsTextUnicode(&be_unicode[1], sizeof(unicode), &flags), "Reverse endian should be Unicode\n"); + todo_wine + ok(flags == (IS_TEXT_UNICODE_REVERSE_ASCII16 | IS_TEXT_UNICODE_REVERSE_STATISTICS | IS_TEXT_UNICODE_REVERSE_CONTROLS), + "Expected flags 0x70, obtained %x\n", flags); + + flags = IS_TEXT_UNICODE_REVERSE_MASK; + ok(!pRtlIsTextUnicode(be_unicode, sizeof(unicode) + 2, &flags), "Reverse endian should be Unicode\n"); + todo_wine + ok(flags == (IS_TEXT_UNICODE_REVERSE_CONTROLS | IS_TEXT_UNICODE_REVERSE_SIGNATURE), + "Expected flags 0xc0, obtained %x\n", flags); + HeapFree(GetProcessHeap(), 0, be_unicode); +} + static const WCHAR szGuid[] = { '{','0','1','0','2','0','3','0','4','-', '0','5','0','6','-' ,'0','7','0','8','-','0','9','0','A','-', '0','B','0','C','0','D','0','E','0','F','0','A','}','\0' }; @@ -1684,14 +1736,14 @@ static void test_RtlGUIDFromString(void) UNICODE_STRING str; NTSTATUS ret; - str.Length = str.MaximumLength = (sizeof(szGuid) - 1) / sizeof(WCHAR); + str.Length = str.MaximumLength = sizeof(szGuid) - sizeof(WCHAR); str.Buffer = (LPWSTR)szGuid; ret = pRtlGUIDFromString(&str, &guid); - ok(ret == 0, "expected ret=0, got 0x%0lx\n", ret); + ok(ret == 0, "expected ret=0, got 0x%0x\n", ret); ok(memcmp(&guid, &IID_Endianess, sizeof(guid)) == 0, "Endianess broken\n"); - str.Length = str.MaximumLength = (sizeof(szGuid2) - 1) / sizeof(WCHAR); + str.Length = str.MaximumLength = sizeof(szGuid2) - sizeof(WCHAR); str.Buffer = (LPWSTR)szGuid2; ret = pRtlGUIDFromString(&str, &guid); @@ -1707,8 +1759,8 @@ static void test_RtlStringFromGUID(void) str.Buffer = NULL; ret = pRtlStringFromGUID(&IID_Endianess, &str); - ok(ret == 0, "expected ret=0, got 0x%0lx\n", ret); - ok(str.Buffer && !lstrcmpW(str.Buffer, szGuid), "Endianess broken\n"); + ok(ret == 0, "expected ret=0, got 0x%0x\n", ret); + ok(str.Buffer && !lstrcmpiW(str.Buffer, szGuid), "Endianess broken\n"); } START_TEST(rtlstr) @@ -1741,6 +1793,8 @@ START_TEST(rtlstr) test_RtlGUIDFromString(); if (pRtlStringFromGUID) test_RtlStringFromGUID(); + if (pRtlIsTextUnicode) + test_RtlIsTextUnicode(); if(0) { test_RtlUpcaseUnicodeChar(); diff --git a/rostests/winetests/ntdll/string.c b/rostests/winetests/ntdll/string.c index a1bc87229a8..e9bf5e10704 100755 --- a/rostests/winetests/ntdll/string.c +++ b/rostests/winetests/ntdll/string.c @@ -391,8 +391,6 @@ static void one_ultow_test(int test_num, const ulong2str_t *ulong2str) static void test_ulongtow(void) { int test_num; - int pos; - WCHAR expected_wstr[LARGE_STRI_BUFFER_LENGTH + 1]; LPWSTR result; for (test_num = 0; test_num < NB_ULONG2STR; test_num++) { @@ -407,32 +405,29 @@ static void test_ulongtow(void) } /* if */ } /* for */ - for (pos = 0; pos < LARGE_STRI_BUFFER_LENGTH; pos++) { - expected_wstr[pos] = ulong2str[0].Buffer[pos]; - } /* for */ - expected_wstr[LARGE_STRI_BUFFER_LENGTH] = '\0'; - result = p_itow(ulong2str[0].value, NULL, 10); - ok(result == NULL, - "(test a): _itow(%ld, NULL, 10) has result %p, expected: NULL\n", - ulong2str[0].value, result); + if (0) { + /* Crashes on XP and W2K3 */ + result = p_itow(ulong2str[0].value, NULL, 10); + ok(result == NULL, + "(test a): _itow(%d, NULL, 10) has result %p, expected: NULL\n", + ulong2str[0].value, result); + } - for (pos = 0; pos < LARGE_STRI_BUFFER_LENGTH; pos++) { - expected_wstr[pos] = ulong2str[0].Buffer[pos]; - } /* for */ - expected_wstr[LARGE_STRI_BUFFER_LENGTH] = '\0'; - result = p_ltow(ulong2str[0].value, NULL, 10); - ok(result == NULL, - "(test b): _ltow(%ld, NULL, 10) has result %p, expected: NULL\n", - ulong2str[0].value, result); + if (0) { + /* Crashes on XP and W2K3 */ + result = p_ltow(ulong2str[0].value, NULL, 10); + ok(result == NULL, + "(test b): _ltow(%d, NULL, 10) has result %p, expected: NULL\n", + ulong2str[0].value, result); + } - for (pos = 0; pos < LARGE_STRI_BUFFER_LENGTH; pos++) { - expected_wstr[pos] = ulong2str[0].Buffer[pos]; - } /* for */ - expected_wstr[LARGE_STRI_BUFFER_LENGTH] = '\0'; - result = p_ultow(ulong2str[0].value, NULL, 10); - ok(result == NULL, - "(test c): _ultow(%ld, NULL, 10) has result %p, expected: NULL\n", - ulong2str[0].value, result); + if (0) { + /* Crashes on XP and W2K3 */ + result = p_ultow(ulong2str[0].value, NULL, 10); + ok(result == NULL, + "(test c): _ultow(%d, NULL, 10) has result %p, expected: NULL\n", + ulong2str[0].value, result); + } } #define ULL(a,b) (((ULONGLONG)(a) << 32) | (b)) @@ -673,8 +668,9 @@ static void one_i64tow_test(int test_num, const ulonglong2str_t *ulonglong2str) result = p_i64tow(ulonglong2str->value, dest_wstr, ulonglong2str->base); pRtlUnicodeStringToAnsiString(&ansi_str, &unicode_string, 1); ok(result == dest_wstr, - "(test %d): _i64tow(%llu, [out], %d) has result %p, expected: %p\n", - test_num, ulonglong2str->value, ulonglong2str->base, result, dest_wstr); + "(test %d): _i64tow(0x%x%08x, [out], %d) has result %p, expected: %p\n", + test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value, + ulonglong2str->base, result, dest_wstr); if (ulonglong2str->mask & 0x04) { if (memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) != 0) { for (pos = 0; pos < LARGE_STRI_BUFFER_LENGTH; pos++) { @@ -683,14 +679,16 @@ static void one_i64tow_test(int test_num, const ulonglong2str_t *ulonglong2str) expected_wstr[LARGE_STRI_BUFFER_LENGTH] = '\0'; if (memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) != 0) { ok(memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0, - "(test %d): _i64tow(%llu, [out], %d) assigns string \"%s\", expected: \"%s\"\n", - test_num, ulonglong2str->value, ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer); + "(test %d): _i64tow(0x%x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n", + test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value, + ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer); } /* if */ } /* if */ } else { ok(memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0, - "(test %d): _i64tow(%llu, [out], %d) assigns string \"%s\", expected: \"%s\"\n", - test_num, ulonglong2str->value, ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer); + "(test %d): _i64tow(0x%x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n", + test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value, + ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer); } /* if */ pRtlFreeAnsiString(&ansi_str); } @@ -721,11 +719,13 @@ static void one_ui64tow_test(int test_num, const ulonglong2str_t *ulonglong2str) result = p_ui64tow(ulonglong2str->value, dest_wstr, ulonglong2str->base); pRtlUnicodeStringToAnsiString(&ansi_str, &unicode_string, 1); ok(result == dest_wstr, - "(test %d): _ui64tow(%llu, [out], %d) has result %p, expected: %p\n", - test_num, ulonglong2str->value, ulonglong2str->base, result, dest_wstr); + "(test %d): _ui64tow(0x%x%08x, [out], %d) has result %p, expected: %p\n", + test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value, + ulonglong2str->base, result, dest_wstr); ok(memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0, - "(test %d): _ui64tow(%llu, [out], %d) assigns string \"%s\", expected: \"%s\"\n", - test_num, ulonglong2str->value, ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer); + "(test %d): _ui64tow(0x%x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n", + test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value, + ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer); pRtlFreeAnsiString(&ansi_str); } @@ -733,8 +733,6 @@ static void one_ui64tow_test(int test_num, const ulonglong2str_t *ulonglong2str) static void test_ulonglongtow(void) { int test_num; - int pos; - WCHAR expected_wstr[LARGE_STRI_BUFFER_LENGTH + 1]; LPWSTR result; for (test_num = 0; test_num < NB_ULONGLONG2STR; test_num++) { @@ -748,24 +746,22 @@ static void test_ulonglongtow(void) } /* if */ } /* for */ - for (pos = 0; pos < LARGE_STRI_BUFFER_LENGTH; pos++) { - expected_wstr[pos] = ulong2str[0].Buffer[pos]; - } /* for */ - expected_wstr[LARGE_STRI_BUFFER_LENGTH] = '\0'; - result = p_i64tow(ulong2str[0].value, NULL, 10); - ok(result == NULL, - "(test d): _i64tow(%llu, NULL, 10) has result %p, expected: NULL\n", - ulonglong2str[0].value, result); + if (0) { + /* Crashes on XP and W2K3 */ + result = p_i64tow(ulonglong2str[0].value, NULL, 10); + ok(result == NULL, + "(test d): _i64tow(0x%x%08x, NULL, 10) has result %p, expected: NULL\n", + (DWORD)(ulonglong2str[0].value >> 32), (DWORD)ulonglong2str[0].value, result); + } if (p_ui64tow) { - for (pos = 0; pos < LARGE_STRI_BUFFER_LENGTH; pos++) { - expected_wstr[pos] = ulong2str[0].Buffer[pos]; - } /* for */ - expected_wstr[LARGE_STRI_BUFFER_LENGTH] = '\0'; - result = p_ui64tow(ulong2str[0].value, NULL, 10); - ok(result == NULL, - "(test e): _ui64tow(%llu, NULL, 10) has result %p, expected: NULL\n", - ulonglong2str[0].value, result); + if (0) { + /* Crashes on XP and W2K3 */ + result = p_ui64tow(ulonglong2str[0].value, NULL, 10); + ok(result == NULL, + "(test e): _ui64tow(0x%x%08x, NULL, 10) has result %p, expected: NULL\n", + (DWORD)(ulonglong2str[0].value >> 32), (DWORD)ulonglong2str[0].value, result); + } } /* if */ } @@ -863,7 +859,7 @@ static const str2long_t str2long[] = { { "0o7", 0 }, /* one digit octal */ { "0o8", 0 }, /* empty octal */ { "0o", 0 }, /* empty octal */ - { "0d1011101100", 0 }, /* explizit decimal with 0d */ + { "0d1011101100", 0 }, /* explicit decimal with 0d */ { "x89abcdef", 0 }, /* Hex with lower case digits a-f (x-notation) */ { "xFEDCBA00", 0 }, /* Hex with upper case digits A-F (x-notation) */ { "-xFEDCBA00", 0 }, /* Negative Hexadecimal (x-notation) */ @@ -891,7 +887,7 @@ static void test_wtoi(void) pRtlCreateUnicodeStringFromAsciiz(&uni, str2long[test_num].str); result = p_wtoi(uni.Buffer); ok(result == str2long[test_num].value, - "(test %d): call failed: _wtoi(\"%s\") has result %d, expected: %ld\n", + "(test %d): call failed: _wtoi(\"%s\") has result %d, expected: %d\n", test_num, str2long[test_num].str, result, str2long[test_num].value); pRtlFreeUnicodeString(&uni); } /* for */ @@ -908,7 +904,7 @@ static void test_wtol(void) pRtlCreateUnicodeStringFromAsciiz(&uni, str2long[test_num].str); result = p_wtol(uni.Buffer); ok(result == str2long[test_num].value, - "(test %d): call failed: _wtol(\"%s\") has result %ld, expected: %ld\n", + "(test %d): call failed: _wtol(\"%s\") has result %d, expected: %d\n", test_num, str2long[test_num].str, result, str2long[test_num].value); pRtlFreeUnicodeString(&uni); } /* for */ @@ -1020,7 +1016,7 @@ static const str2longlong_t str2longlong[] = { { "0o7", 0 }, /* one digit octal */ { "0o8", 0 }, /* empty octal */ { "0o", 0 }, /* empty octal */ - { "0d1011101100", 0 }, /* explizit decimal with 0d */ + { "0d1011101100", 0 }, /* explicit decimal with 0d */ { "x89abcdef", 0 }, /* Hex with lower case digits a-f (x-notation) */ { "xFEDCBA00", 0 }, /* Hex with upper case digits A-F (x-notation) */ { "-xFEDCBA00", 0 }, /* Negative Hexadecimal (x-notation) */ @@ -1046,8 +1042,9 @@ static void test_atoi64(void) for (test_num = 0; test_num < NB_STR2LONGLONG; test_num++) { result = p_atoi64(str2longlong[test_num].str); ok(result == str2longlong[test_num].value, - "(test %d): call failed: _atoi64(\"%s\") has result %lld, expected: %lld\n", - test_num, str2longlong[test_num].str, result, str2longlong[test_num].value); + "(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n", + test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result, + (DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value); } /* for */ } @@ -1062,14 +1059,15 @@ static void test_wtoi64(void) pRtlCreateUnicodeStringFromAsciiz(&uni, str2longlong[test_num].str); result = p_wtoi64(uni.Buffer); ok(result == str2longlong[test_num].value, - "(test %d): call failed: _wtoi64(\"%s\") has result %lld, expected: %lld\n", - test_num, str2longlong[test_num].str, result, str2longlong[test_num].value); + "(test %d): call failed: _wtoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n", + test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result, + (DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value); pRtlFreeUnicodeString(&uni); } /* for */ } static void test_wcsfuncs(void) -{ +{ static const WCHAR testing[] = {'T','e','s','t','i','n','g',0}; ok (p_wcschr(testing,0)!=NULL, "wcschr Not finding terminating character\n"); ok (p_wcsrchr(testing,0)!=NULL, "wcsrchr Not finding terminating character\n"); diff --git a/rostests/winetests/ntdll/testlist.c b/rostests/winetests/ntdll/testlist.c index 1797ab97be7..0162d0f8937 100644 --- a/rostests/winetests/ntdll/testlist.c +++ b/rostests/winetests/ntdll/testlist.c @@ -11,6 +11,7 @@ extern void func_change(void); extern void func_env(void); extern void func_error(void); extern void func_exception(void); +extern void func_file(void); extern void func_generated(void); extern void func_info(void); extern void func_large_int(void); @@ -31,7 +32,8 @@ const struct test winetest_testlist[] = { "env", func_env }, { "error", func_error }, { "exception", func_exception }, -// { "generated", func_generated }, + { "file", func_file }, + //{ "generated", func_generated }, { "info", func_info }, { "large_int", func_large_int }, { "om", func_om }, diff --git a/rostests/winetests/ntdll/time.c b/rostests/winetests/ntdll/time.c index 1f6cbc31811..2e9adbc11a5 100755 --- a/rostests/winetests/ntdll/time.c +++ b/rostests/winetests/ntdll/time.c @@ -53,7 +53,7 @@ static void test_pRtlTimeToTimeFields(void) /* test at the last second of the month */ pRtlTimeToTimeFields( &litime, &tfresult); ok( tfresult.Year == tftest.Year && tfresult.Month == tftest.Month && - tfresult.Day == tftest.Day && tfresult.Hour == tftest.Hour && + tfresult.Day == tftest.Day && tfresult.Hour == tftest.Hour && tfresult.Minute == tftest.Minute && tfresult.Second == tftest.Second, "#%d expected: %d-%d-%d %d:%d:%d got: %d-%d-%d %d:%d:%d\n", ++i, tftest.Year, tftest.Month, tftest.Day, @@ -71,7 +71,7 @@ static void test_pRtlTimeToTimeFields(void) pRtlTimeToTimeFields( &litime, &tfresult); ok( tfresult.Year == tftest.Year + (tftest.Month ==12) && tfresult.Month == tftest.Month % 12 + 1 && - tfresult.Day == 1 && tfresult.Hour == 0 && + tfresult.Day == 1 && tfresult.Hour == 0 && tfresult.Minute == 0 && tfresult.Second == 0, "#%d expected: %d-%d-%d %d:%d:%d got: %d-%d-%d %d:%d:%d\n", ++i, tftest.Year + (tftest.Month ==12), @@ -89,7 +89,7 @@ static void test_pRtlTimeToTimeFields(void) if( tftest.Month == 12) { tftest.Month = 1; tftest.Year += 1; - } else + } else tftest.Month += 1; tftest.Day = MonthLengths[IsLeapYear(tftest.Year)][tftest.Month - 1]; litime.QuadPart += (LONGLONG) tftest.Day * TICKSPERSEC * SECSPERDAY; diff --git a/rostests/winetests/odbccp32/misc.c b/rostests/winetests/odbccp32/misc.c index f5ea5361a0b..ba8e5f45f87 100644 --- a/rostests/winetests/odbccp32/misc.c +++ b/rostests/winetests/odbccp32/misc.c @@ -58,7 +58,7 @@ static void test_SQLInstallerError(void) sql_ret = SQLInstallerError(0, NULL, NULL, 0, NULL); ok(sql_ret == SQL_ERROR, "SQLInstallerError(0...) failed with %d instead of SQL_ERROR\n", sql_ret); /* However numbers greater than 8 do not return SQL_ERROR. - * I am currenly unsure as to whether it should return SQL_NO_DATA or "the same as for error 8"; + * I am currently unsure as to whether it should return SQL_NO_DATA or "the same as for error 8"; * I have never been able to generate 8 errors to test it */ sql_ret = SQLInstallerError(65535, NULL, NULL, 0, NULL); diff --git a/rostests/winetests/odbccp32/odbccp32.rbuild b/rostests/winetests/odbccp32/odbccp32.rbuild index 3c39cc72303..faad1e73436 100644 --- a/rostests/winetests/odbccp32/odbccp32.rbuild +++ b/rostests/winetests/odbccp32/odbccp32.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/ole32/clipboard.c b/rostests/winetests/ole32/clipboard.c index 0127ce5e44c..e365ee8fc69 100644 --- a/rostests/winetests/ole32/clipboard.c +++ b/rostests/winetests/ole32/clipboard.c @@ -57,6 +57,9 @@ typedef struct EnumFormatImpl { UINT cur; } EnumFormatImpl; +static BOOL expect_DataObjectImpl_QueryGetData = TRUE; +static ULONG DataObjectImpl_GetData_calls = 0; + static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc); static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj) @@ -194,6 +197,8 @@ static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pfor { DataObjectImpl *This = (DataObjectImpl*)iface; + DataObjectImpl_GetData_calls++; + if(pformatetc->lindex != -1) return DV_E_LINDEX; @@ -223,6 +228,9 @@ static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC UINT i; BOOL foundFormat = FALSE; + if (!expect_DataObjectImpl_QueryGetData) + ok(0, "unexpected call to DataObjectImpl_QueryGetData\n"); + if(pformatetc->lindex != -1) return DV_E_LINDEX; @@ -316,6 +324,97 @@ static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj) return S_OK; } +static void test_get_clipboard(void) +{ + HRESULT hr; + IDataObject *data_obj; + FORMATETC fmtetc; + STGMEDIUM stgmedium; + + hr = OleGetClipboard(NULL); + ok(hr == E_INVALIDARG, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr); + + hr = OleGetClipboard(&data_obj); + ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr); + + /* test IDataObject_QueryGetData */ + + /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */ + expect_DataObjectImpl_QueryGetData = FALSE; + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + hr = IDataObject_QueryGetData(data_obj, &fmtetc); + ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr); + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + fmtetc.dwAspect = 0xdeadbeef; + hr = IDataObject_QueryGetData(data_obj, &fmtetc); + ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + fmtetc.dwAspect = DVASPECT_THUMBNAIL; + hr = IDataObject_QueryGetData(data_obj, &fmtetc); + ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + fmtetc.lindex = 256; + hr = IDataObject_QueryGetData(data_obj, &fmtetc); + ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + fmtetc.cfFormat = CF_RIFF; + hr = IDataObject_QueryGetData(data_obj, &fmtetc); + ok(hr == DV_E_CLIPFORMAT, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr); + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + fmtetc.tymed = TYMED_FILE; + hr = IDataObject_QueryGetData(data_obj, &fmtetc); + ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr); + + expect_DataObjectImpl_QueryGetData = TRUE; + + /* test IDataObject_GetData */ + + DataObjectImpl_GetData_calls = 0; + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); + ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr); + ReleaseStgMedium(&stgmedium); + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + fmtetc.dwAspect = 0xdeadbeef; + hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); + ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr); + ReleaseStgMedium(&stgmedium); + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + fmtetc.dwAspect = DVASPECT_THUMBNAIL; + hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); + ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr); + ReleaseStgMedium(&stgmedium); + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + fmtetc.lindex = 256; + hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); + todo_wine + ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + fmtetc.cfFormat = CF_RIFF; + hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); + ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); + + InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); + fmtetc.tymed = TYMED_FILE; + hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); + ok(hr == DV_E_TYMED, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr); + + ok(DataObjectImpl_GetData_calls == 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls); + + IDataObject_Release(data_obj); +} + static void test_set_clipboard(void) { HRESULT hr; @@ -350,6 +449,8 @@ static void test_set_clipboard(void) hr = OleIsCurrentClipboard(data2); ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr); + test_get_clipboard(); + hr = OleSetClipboard(data2); ok(hr == S_OK, "failed to set clipboard to data2, hr = 0x%08x\n", hr); hr = OleIsCurrentClipboard(data1); diff --git a/rostests/winetests/ole32/marshal.c b/rostests/winetests/ole32/marshal.c index c7f79961bcf..fade8b075a1 100644 --- a/rostests/winetests/ole32/marshal.c +++ b/rostests/winetests/ole32/marshal.c @@ -29,6 +29,7 @@ #include "winbase.h" #include "objbase.h" #include "shlguid.h" +#include "shobjidl.h" #include "wine/test.h" @@ -1076,6 +1077,99 @@ static void test_tableweak_marshal_releasedata2(void) end_host_object(tid, thread); } +struct weak_and_normal_marshal_data +{ + IStream *pStreamWeak; + IStream *pStreamNormal; + HANDLE hReadyEvent; + HANDLE hQuitEvent; +}; + +static DWORD CALLBACK weak_and_normal_marshal_thread_proc(void *p) +{ + HRESULT hr; + struct weak_and_normal_marshal_data *data = p; + HANDLE hQuitEvent = data->hQuitEvent; + MSG msg; + + pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + hr = CoMarshalInterface(data->pStreamWeak, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLEWEAK); + ok_ole_success(hr, "CoMarshalInterface"); + + hr = CoMarshalInterface(data->pStreamNormal, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, "CoMarshalInterface"); + + /* force the message queue to be created before signaling parent thread */ + PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); + + SetEvent(data->hReadyEvent); + + while (WAIT_OBJECT_0 + 1 == MsgWaitForMultipleObjects(1, &hQuitEvent, FALSE, INFINITE, QS_ALLINPUT)) + { + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + DispatchMessage(&msg); + } + CloseHandle(hQuitEvent); + + CoUninitialize(); + + return 0; +} + +/* tests interaction between table-weak and normal marshalling of an object */ +static void test_tableweak_and_normal_marshal_and_unmarshal(void) +{ + HRESULT hr; + IUnknown *pProxyWeak = NULL; + IUnknown *pProxyNormal = NULL; + DWORD tid; + HANDLE thread; + struct weak_and_normal_marshal_data data; + + cLocks = 0; + + data.hReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + data.hQuitEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStreamWeak); + ok_ole_success(hr, CreateStreamOnHGlobal); + hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStreamNormal); + ok_ole_success(hr, CreateStreamOnHGlobal); + + thread = CreateThread(NULL, 0, weak_and_normal_marshal_thread_proc, &data, 0, &tid); + WaitForSingleObject(data.hReadyEvent, INFINITE); + CloseHandle(data.hReadyEvent); + + ok_more_than_one_lock(); + + IStream_Seek(data.pStreamWeak, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(data.pStreamWeak, &IID_IClassFactory, (void **)&pProxyWeak); + ok_ole_success(hr, CoUnmarshalInterface); + + ok_more_than_one_lock(); + + IStream_Seek(data.pStreamNormal, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(data.pStreamNormal, &IID_IClassFactory, (void **)&pProxyNormal); + ok_ole_success(hr, CoUnmarshalInterface); + + ok_more_than_one_lock(); + + IUnknown_Release(pProxyNormal); + + ok_more_than_one_lock(); + + IUnknown_Release(pProxyWeak); + + ok_no_locks(); + + IStream_Release(data.pStreamWeak); + IStream_Release(data.pStreamNormal); + + SetEvent(data.hQuitEvent); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); +} + /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */ static void test_tablestrong_marshal_and_unmarshal_twice(void) { @@ -2549,8 +2643,9 @@ static void test_local_server(void) hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL, &IID_IClassFactory, (LPVOID*)&cf); ok(hr == CO_E_SERVER_STOPPING || /* NT */ + hr == REGDB_E_CLASSNOTREG || /* win2k */ hr == S_OK /* Win9x */, - "CoGetClassObject should have returned CO_E_SERVER_STOPPING instead of 0x%08x\n", hr); + "CoGetClassObject should have returned CO_E_SERVER_STOPPING or REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr); hr = CoRevokeClassObject(cookie); ok_ole_success(hr, CoRevokeClassObject); @@ -2593,8 +2688,9 @@ static DWORD CALLBACK get_global_interface_proc(LPVOID pv) IClassFactory *cf; hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf); - ok(hr == CO_E_NOTINITIALIZED, - "IGlobalInterfaceTable_GetInterfaceFromGlobal should have failed with error CO_E_NOTINITIALIZED instead of 0x%08x\n", + ok(hr == CO_E_NOTINITIALIZED || + hr == E_UNEXPECTED, /* win2k */ + "IGlobalInterfaceTable_GetInterfaceFromGlobal should have failed with error CO_E_NOTINITIALIZED or E_UNEXPECTED instead of 0x%08x\n", hr); CoInitialize(NULL); @@ -2922,6 +3018,7 @@ START_TEST(marshal) test_tableweak_marshal_and_unmarshal_twice(); test_tableweak_marshal_releasedata1(); test_tableweak_marshal_releasedata2(); + test_tableweak_and_normal_marshal_and_unmarshal(); test_tablestrong_marshal_and_unmarshal_twice(); test_lock_object_external(); test_disconnect_stub(); diff --git a/rostests/winetests/ole32/moniker.c b/rostests/winetests/ole32/moniker.c index 3f3579ae765..b15cce43e5e 100644 --- a/rostests/winetests/ole32/moniker.c +++ b/rostests/winetests/ole32/moniker.c @@ -657,6 +657,7 @@ static void test_ROT(void) todo_wine { ok(hr == CO_E_WRONG_SERVER_IDENTITY, "IRunningObjectTable_Register should have returned CO_E_WRONG_SERVER_IDENTITY instead of 0x%08x\n", hr); } + if (hr == S_OK) IRunningObjectTable_Revoke(pROT, dwCookie); hr = IRunningObjectTable_Register(pROT, 0xdeadbeef, (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie); @@ -667,6 +668,49 @@ static void test_ROT(void) IRunningObjectTable_Release(pROT); } +static void test_ROT_multiple_entries(void) +{ + HRESULT hr; + IMoniker *pMoniker = NULL; + IRunningObjectTable *pROT = NULL; + DWORD dwCookie1, dwCookie2; + IUnknown *pObject = NULL; + static const WCHAR moniker_path[] = + {'\\', 'w','i','n','d','o','w','s','\\','s','y','s','t','e','m','\\','t','e','s','t','1','.','d','o','c',0}; + + hr = GetRunningObjectTable(0, &pROT); + ok_ole_success(hr, GetRunningObjectTable); + + hr = CreateFileMoniker(moniker_path, &pMoniker); + ok_ole_success(hr, CreateFileMoniker); + + hr = IRunningObjectTable_Register(pROT, 0, (IUnknown *)&Test_ClassFactory, pMoniker, &dwCookie1); + ok_ole_success(hr, IRunningObjectTable_Register); + + hr = IRunningObjectTable_Register(pROT, 0, (IUnknown *)&Test_ClassFactory, pMoniker, &dwCookie2); + ok(hr == MK_S_MONIKERALREADYREGISTERED, "IRunningObjectTable_Register should have returned MK_S_MONIKERALREADYREGISTERED instead of 0x%08x\n", hr); + + ok(dwCookie1 != dwCookie2, "cookie returned for registering duplicate object shouldn't match cookie of original object (0x%x)\n", dwCookie1); + + hr = IRunningObjectTable_GetObject(pROT, pMoniker, &pObject); + ok_ole_success(hr, IRunningObjectTable_GetObject); + IUnknown_Release(pObject); + + hr = IRunningObjectTable_Revoke(pROT, dwCookie1); + ok_ole_success(hr, IRunningObjectTable_Revoke); + + hr = IRunningObjectTable_GetObject(pROT, pMoniker, &pObject); + ok_ole_success(hr, IRunningObjectTable_GetObject); + IUnknown_Release(pObject); + + hr = IRunningObjectTable_Revoke(pROT, dwCookie2); + ok_ole_success(hr, IRunningObjectTable_Revoke); + + IMoniker_Release(pMoniker); + + IRunningObjectTable_Release(pROT); +} + static HRESULT WINAPI ParseDisplayName_QueryInterface(IParseDisplayName *iface, REFIID riid, void **ppv) { if (IsEqualIID(riid, &IID_IUnknown) || @@ -1801,6 +1845,7 @@ START_TEST(moniker) CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); test_ROT(); + test_ROT_multiple_entries(); test_MkParseDisplayName(); test_class_moniker(); test_file_monikers(); diff --git a/rostests/winetests/ole32/ole32.rbuild b/rostests/winetests/ole32/ole32.rbuild index 27202e575e9..4438cdf49bb 100644 --- a/rostests/winetests/ole32/ole32.rbuild +++ b/rostests/winetests/ole32/ole32.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/psapi/psapi.rbuild b/rostests/winetests/psapi/psapi.rbuild index 97725f7244a..9eb16472ef7 100644 --- a/rostests/winetests/psapi/psapi.rbuild +++ b/rostests/winetests/psapi/psapi.rbuild @@ -1,3 +1,6 @@ + + + . @@ -7,3 +10,4 @@ testlist.c psapi_main.c + diff --git a/rostests/winetests/psapi/psapi_main.c b/rostests/winetests/psapi/psapi_main.c index ee8f8ab803b..1978fd4d787 100644 --- a/rostests/winetests/psapi/psapi_main.c +++ b/rostests/winetests/psapi/psapi_main.c @@ -33,7 +33,7 @@ return FALSE; \ } -/* All PSAPI functions return non-zero and call SetLastError() +/* All PSAPI functions return non-zero and call SetLastError() * on failure so we can use some macros for convenience */ #define w32_suc(x) \ @@ -42,7 +42,7 @@ ? (ok(1, "succeeded\n"), 1) \ : GetLastError() == 0xdeadbeef \ ? (ok(0, "failed without error code\n"), 0) \ - : (ok(0, "failed with %ld\n", GetLastError()), 0)) + : (ok(0, "failed with %d\n", GetLastError()), 0)) #define w32_err(x, e) \ (SetLastError(0xdeadbeef), \ @@ -52,7 +52,7 @@ ? (ok(1, "failed with %d\n", e), 1) \ : GetLastError() == 0xdeadbeef \ ? (ok(0, "failed without error code\n"), 0) \ - : (ok(0, "expected error=%d but failed with %ld\n", \ + : (ok(0, "expected error=%d but failed with %d\n", \ e, GetLastError()), 0)) static BOOL (WINAPI *pEmptyWorkingSet)(HANDLE); @@ -67,7 +67,7 @@ static BOOL (WINAPI *pGetProcessMemoryInfo)(HANDLE, PPROCESS_MEMORY_COUNTERS, D static BOOL (WINAPI *pGetWsChanges)(HANDLE, PPSAPI_WS_WATCH_INFORMATION, DWORD); static BOOL (WINAPI *pInitializeProcessForWsWatch)(HANDLE); static BOOL (WINAPI *pQueryWorkingSet)(HANDLE, PVOID, DWORD); - + static BOOL InitFunctionPtrs(HMODULE hpsapi) { PSAPI_GET_PROC(EmptyWorkingSet); @@ -95,9 +95,9 @@ static void test_EnumProcesses(void) DWORD pid, cbUsed = 0xdeadbeef; if(w32_suc(pEnumProcesses(NULL, 0, &cbUsed))) - ok(cbUsed == 0, "cbUsed=%ld\n", cbUsed); + ok(cbUsed == 0, "cbUsed=%d\n", cbUsed); if(w32_suc(pEnumProcesses(&pid, 4, &cbUsed))) - ok(cbUsed == 4, "cbUsed=%ld\n", cbUsed); + ok(cbUsed == 4, "cbUsed=%d\n", cbUsed); } static void test_EnumProcessModules(void) @@ -111,7 +111,7 @@ static void test_EnumProcessModules(void) if(!w32_suc(pEnumProcessModules(hpQV, &hMod, sizeof(HMODULE), &cbNeeded))) return; ok(cbNeeded / sizeof(HMODULE) >= 3 && cbNeeded / sizeof(HMODULE) <= 5 * sizeof(HMODULE), - "cbNeeded=%ld\n", cbNeeded); + "cbNeeded=%d\n", cbNeeded); ok(hMod == GetModuleHandle(NULL), "hMod=%p GetModuleHandle(NULL)=%p\n", hMod, GetModuleHandle(NULL)); } @@ -120,7 +120,7 @@ static void test_GetModuleInformation(void) { HMODULE hMod = GetModuleHandle(NULL); MODULEINFO info; - + w32_err(pGetModuleInformation(NULL, hMod, &info, sizeof(info)), ERROR_INVALID_HANDLE); w32_err(pGetModuleInformation(hpQI, hMod, &info, sizeof(info)), ERROR_ACCESS_DENIED); w32_err(pGetModuleInformation(hpQV, hBad, &info, sizeof(info)), ERROR_INVALID_HANDLE); @@ -144,12 +144,12 @@ static void test_GetMappedFileName(void) HMODULE hMod = GetModuleHandle(NULL); char szMapPath[MAX_PATH], szModPath[MAX_PATH], *szMapBaseName; DWORD ret; - + w32_err(pGetMappedFileNameA(NULL, hMod, szMapPath, sizeof(szMapPath)), ERROR_INVALID_HANDLE); w32_err(pGetMappedFileNameA(hpSR, hMod, szMapPath, sizeof(szMapPath)), ERROR_ACCESS_DENIED); if(!w32_suc(ret = pGetMappedFileNameA(hpQI, hMod, szMapPath, sizeof(szMapPath)))) return; - ok(ret == strlen(szMapPath), "szMapPath=\"%s\" ret=%ld\n", szMapPath, ret); + ok(ret == strlen(szMapPath), "szMapPath=\"%s\" ret=%d\n", szMapPath, ret); ok(szMapPath[0] == '\\', "szMapPath=\"%s\"\n", szMapPath); szMapBaseName = strrchr(szMapPath, '\\'); /* That's close enough for us */ if(!szMapBaseName || !*szMapBaseName) @@ -180,11 +180,11 @@ static void test_GetProcessImageFileName(void) else if(GetLastError() == 0xdeadbeef) ok(0, "failed without error code\n"); else - ok(0, "failed with %ld\n", GetLastError()); + ok(0, "failed with %d\n", GetLastError()); return; } - + w32_err(pGetProcessImageFileNameA(NULL, szImgPath, sizeof(szImgPath)), ERROR_INVALID_HANDLE); w32_err(pGetProcessImageFileNameA(hpSR, szImgPath, sizeof(szImgPath)), ERROR_ACCESS_DENIED); w32_err(pGetProcessImageFileNameA(hpQI, szImgPath, 0), ERROR_INSUFFICIENT_BUFFER); @@ -192,9 +192,9 @@ static void test_GetProcessImageFileName(void) !w32_suc(pGetMappedFileNameA(hpQV, hMod, szMapPath, sizeof(szMapPath)))) return; /* Windows returns 2*strlen-1 */ - ok(ret >= strlen(szImgPath), "szImgPath=\"%s\" ret=%ld\n", szImgPath, ret); + ok(ret >= strlen(szImgPath), "szImgPath=\"%s\" ret=%d\n", szImgPath, ret); ok(!strcmp(szImgPath, szMapPath), - "szImgPath=\"%s\" szMapPath=\"%s\"\n", szImgPath, szMapPath); + "szImgPath=\"%s\" szMapPath=\"%s\"\n", szImgPath, szMapPath); } static void test_GetModuleFileNameEx(void) @@ -202,15 +202,15 @@ static void test_GetModuleFileNameEx(void) HMODULE hMod = GetModuleHandle(NULL); char szModExPath[MAX_PATH+1], szModPath[MAX_PATH+1]; DWORD ret; - + w32_err(pGetModuleFileNameExA(NULL, hMod, szModExPath, sizeof(szModExPath)), ERROR_INVALID_HANDLE); w32_err(pGetModuleFileNameExA(hpQI, hMod, szModExPath, sizeof(szModExPath)), ERROR_ACCESS_DENIED); w32_err(pGetModuleFileNameExA(hpQV, hBad, szModExPath, sizeof(szModExPath)), ERROR_INVALID_HANDLE); if(!w32_suc(ret = pGetModuleFileNameExA(hpQV, NULL, szModExPath, sizeof(szModExPath)))) return; - ok(ret == strlen(szModExPath), "szModExPath=\"%s\" ret=%ld\n", szModExPath, ret); + ok(ret == strlen(szModExPath), "szModExPath=\"%s\" ret=%d\n", szModExPath, ret); GetModuleFileNameA(NULL, szModPath, sizeof(szModPath)); - ok(!strncmp(szModExPath, szModPath, MAX_PATH), + ok(!strncmp(szModExPath, szModPath, MAX_PATH), "szModExPath=\"%s\" szModPath=\"%s\"\n", szModExPath, szModPath); } @@ -225,7 +225,7 @@ static void test_GetModuleBaseName(void) w32_err(pGetModuleBaseNameA(hpQV, hBad, szModBaseName, sizeof(szModBaseName)), ERROR_INVALID_HANDLE); if(!w32_suc(ret = pGetModuleBaseNameA(hpQV, NULL, szModBaseName, sizeof(szModBaseName)))) return; - ok(ret == strlen(szModBaseName), "szModBaseName=\"%s\" ret=%ld\n", szModBaseName, ret); + ok(ret == strlen(szModBaseName), "szModBaseName=\"%s\" ret=%d\n", szModBaseName, ret); GetModuleFileNameA(NULL, szModPath, sizeof(szModPath)); ok(!strcmp(strrchr(szModPath, '\\') + 1, szModBaseName), "szModPath=\"%s\" szModBaseName=\"%s\"\n", szModPath, szModBaseName); @@ -236,24 +236,24 @@ static void test_ws_functions(void) PSAPI_WS_WATCH_INFORMATION wswi[4096]; ULONG_PTR pages[4096]; char *addr; - int i; - + unsigned int i; + todo_wine w32_err(pEmptyWorkingSet(NULL), ERROR_INVALID_HANDLE); todo_wine w32_err(pEmptyWorkingSet(hpSR), ERROR_ACCESS_DENIED); w32_suc(pEmptyWorkingSet(hpAA)); - + todo_wine w32_err(pInitializeProcessForWsWatch(NULL), ERROR_INVALID_HANDLE); w32_suc(pInitializeProcessForWsWatch(hpAA)); - + if(!w32_suc(addr = VirtualAlloc(NULL, 1, MEM_COMMIT, PAGE_READWRITE))) return; if(!VirtualLock(addr, 1)) { - trace("locking failed (error=%ld) - skipping test\n", GetLastError()); + trace("locking failed (error=%d) - skipping test\n", GetLastError()); goto free_page; } - + todo_wine if(w32_suc(pQueryWorkingSet(hpQI, pages, 4096 * sizeof(ULONG_PTR)))) { for(i = 0; i < pages[0]; i++) @@ -262,7 +262,7 @@ static void test_ws_functions(void) ok(1, "QueryWorkingSet found our page\n"); goto test_gwsc; } - + ok(0, "QueryWorkingSet didn't find our page\n"); } @@ -278,7 +278,7 @@ test_gwsc: ok(0, "GetWsChanges didn't find our page\n"); } - + free_page: VirtualFree(addr, 0, MEM_RELEASE); } @@ -286,7 +286,7 @@ free_page: START_TEST(psapi_main) { HMODULE hpsapi = LoadLibraryA("psapi.dll"); - + if(!hpsapi) { trace("Could not load psapi.dll\n"); @@ -320,6 +320,6 @@ START_TEST(psapi_main) CloseHandle(hpQV); CloseHandle(hpAA); } - + FreeLibrary(hpsapi); } diff --git a/rostests/winetests/riched20/editor.c b/rostests/winetests/riched20/editor.c index 090eaad0320..1d64580b02d 100644 --- a/rostests/winetests/riched20/editor.c +++ b/rostests/winetests/riched20/editor.c @@ -127,7 +127,9 @@ struct find_s find_tests2[] = { /* The backwards case of bug 4479; bounds look right * Fails because backward find is wrong */ {19, 20, "WINE", FR_MATCHCASE, 0, 0}, - {0, 20, "WINE", FR_MATCHCASE, -1, 0} + {0, 20, "WINE", FR_MATCHCASE, -1, 0}, + + {0, -1, "wineWine wine", 0, -1, 0}, }; static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) { @@ -261,6 +263,40 @@ static void test_EM_GETLINE(void) DestroyWindow(hwndRichEdit); } +static void test_EM_LINELENGTH(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + const char * text = + "richedit1\r" + "richedit1\n" + "richedit1\r\n" + "richedit1"; + int offset_test[10][2] = { + {0, 9}, + {5, 9}, + {10, 9}, + {15, 9}, + {20, 9}, + {25, 9}, + {30, 9}, + {35, 9}, + {40, 0}, + {45, 0}, + }; + int i; + LRESULT result; + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text); + + for (i = 0; i < 10; i++) { + result = SendMessage(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0); + ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n", + offset_test[i][0], result, offset_test[i][1]); + } + + DestroyWindow(hwndRichEdit); +} + static int get_scroll_pos_y(HWND hwnd) { POINT p = {-1, -1}; @@ -404,6 +440,57 @@ static void test_EM_SETCHARFORMAT(void) (LPARAM) &cf2); ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); + cf2.cbSize = sizeof(CHARFORMAT2); + SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, + (LPARAM) &cf2); + + /* Test state of modify flag before and after valid EM_SETCHARFORMAT */ + cf2.cbSize = sizeof(CHARFORMAT2); + SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, + (LPARAM) &cf2); + cf2.dwMask = CFM_ITALIC | cf2.dwMask; + cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; + + /* wParam==0 is default char format, does not set modify */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); + ok(rc == 0, "Text marked as modified, expected not modified!\n"); + rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, 0, (LPARAM) &cf2); + ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); + rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); + ok(rc == 0, "Text marked as modified, expected not modified!\n"); + + /* wParam==SCF_SELECTION sets modify if nonempty selection */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); + ok(rc == 0, "Text marked as modified, expected not modified!\n"); + rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2); + ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); + rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); + ok(rc == 0, "Text marked as modified, expected not modified!\n"); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine"); + rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); + ok(rc == 0, "Text marked as modified, expected not modified!\n"); + rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2); + ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); + rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); + ok(rc == 0, "Text marked as modified, expected not modified!\n"); + SendMessage(hwndRichEdit, EM_SETSEL, 0, 2); + rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2); + ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); + rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); + ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc); + + /* wParam==SCF_ALL sets modify regardless of whether text is present */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); + ok(rc == 0, "Text marked as modified, expected not modified!\n"); + rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2); + ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); + rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); + ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc); + DestroyWindow(hwndRichEdit); } @@ -438,10 +525,17 @@ static void test_EM_SETTEXTMODE(void) cf2.dwMask = CFM_ITALIC | cf2.dwMask; cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; + rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); + ok(rc == 0, "Text marked as modified, expected not modified!\n"); + /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine; however, SCF_ALL has been implemented*/ rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2); ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); + + rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); + ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine"); /*Select the string "wine"*/ @@ -680,9 +774,12 @@ static void test_WM_GETTEXT(void) /* Test for behavior in overflow case */ memset(buffer, 0, 1024); result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer); - ok(result == 0, - "WM_GETTEXT returned %d, expected 0\n", result); + ok(result == 0 || + result == lstrlenA(text) - 1, /* XP, win2k3 */ + "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text) - 1); result = strcmp(buffer,text); + if (result) + result = strncmp(buffer, text, lstrlenA(text) - 1); /* XP, win2k3 */ ok(result == 0, "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); @@ -704,15 +801,75 @@ static void test_WM_GETTEXT(void) /* Test for behavior of CRLF conversion in case of overflow */ memset(buffer, 0, 1024); result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer); - ok(result == 0, - "WM_GETTEXT returned %d, expected 0\n", result); + ok(result == 0 || + result == lstrlenA(text2) - 1, /* XP, win2k3 */ + "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text2) - 1); result = strcmp(buffer,text2); + if (result) + result = strncmp(buffer, text2, lstrlenA(text2) - 1); /* XP, win2k3 */ ok(result == 0, "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); DestroyWindow(hwndRichEdit); } +static void test_EM_GETTEXTRANGE(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + const char * text1 = "foo bar\r\nfoo bar"; + const char * text2 = "foo bar\rfoo bar"; + const char * expect = "bar\rfoo"; + char buffer[1024] = {0}; + LRESULT result; + TEXTRANGEA textRange; + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); + + textRange.lpstrText = buffer; + textRange.chrg.cpMin = 4; + textRange.chrg.cpMax = 11; + result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); + ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); + + textRange.lpstrText = buffer; + textRange.chrg.cpMin = 4; + textRange.chrg.cpMax = 11; + result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); + ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + DestroyWindow(hwndRichEdit); +} + +static void test_EM_GETSELTEXT(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + const char * text1 = "foo bar\r\nfoo bar"; + const char * text2 = "foo bar\rfoo bar"; + const char * expect = "bar\rfoo"; + char buffer[1024] = {0}; + LRESULT result; + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); + + SendMessage(hwndRichEdit, EM_SETSEL, 4, 11); + result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer); + ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); + + SendMessage(hwndRichEdit, EM_SETSEL, 4, 11); + result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer); + ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + DestroyWindow(hwndRichEdit); +} + /* FIXME: need to test unimplemented options and robustly test wparam */ static void test_EM_SETOPTIONS(void) { @@ -852,7 +1009,7 @@ static void test_EM_SCROLL(void) "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE " "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE " "LONG LINE \nb\nc\nd\ne"); - for (j = 0; j < 12; j++) /* reset scrol position to top */ + for (j = 0; j < 12; j++) /* reset scroll position to top */ SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* get first visible line */ @@ -1041,6 +1198,20 @@ static void test_ES_PASSWORD(void) DestroyWindow(hwndRichEdit); } +static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie, + LPBYTE pbBuff, + LONG cb, + LONG *pcb) +{ + char** str = (char**)dwCookie; + *pcb = cb; + if (*pcb > 0) { + memcpy(*str, pbBuff, *pcb); + *str += *pcb; + } + return 0; +} + static void test_WM_SETTEXT() { HWND hwndRichEdit = new_richedit(NULL); @@ -1057,8 +1228,11 @@ static void test_WM_SETTEXT() const char * TestItem6_after = "TestSomeText \r\nTestSomeText"; const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText"; const char * TestItem7_after = "TestSomeText\r\n \r\nTestSomeText"; + char buf[1024] = {0}; LRESULT result; + EDITSTREAM es; + char * p; /* This test attempts to show that WM_SETTEXT on a riched20 control causes any solitary \r to be converted to \r\n on return. Properly paired @@ -1086,10 +1260,76 @@ static void test_WM_SETTEXT() TEST_SETTEXT(TestItem6, TestItem6_after) TEST_SETTEXT(TestItem7, TestItem7_after) + /* The following test demonstrates that WM_SETTEXT supports RTF strings */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1); + p = buf; + es.dwCookie = (DWORD_PTR)&p; + es.dwError = 0; + es.pfnCallback = test_WM_SETTEXT_esCallback; + memset(buf, 0, sizeof(buf)); + SendMessage(hwndRichEdit, EM_STREAMOUT, + (WPARAM)(SF_RTF), (LPARAM)&es); + trace("EM_STREAMOUT produced: \n%s\n", buf); + TEST_SETTEXT(buf, TestItem1) + #undef TEST_SETTEXT DestroyWindow(hwndRichEdit); } +static void test_EM_STREAMOUT(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + int r; + EDITSTREAM es; + char buf[1024] = {0}; + char * p; + + const char * TestItem1 = "TestSomeText"; + const char * TestItem2 = "TestSomeText\r"; + const char * TestItem3 = "TestSomeText\r\n"; + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1); + p = buf; + es.dwCookie = (DWORD_PTR)&p; + es.dwError = 0; + es.pfnCallback = test_WM_SETTEXT_esCallback; + memset(buf, 0, sizeof(buf)); + SendMessage(hwndRichEdit, EM_STREAMOUT, + (WPARAM)(SF_TEXT), (LPARAM)&es); + r = strlen(buf); + ok(r == 12, "streamed text length is %d, expecting 12\n", r); + ok(strcmp(buf, TestItem1) == 0, + "streamed text different, got %s\n", buf); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem2); + p = buf; + es.dwCookie = (DWORD_PTR)&p; + es.dwError = 0; + es.pfnCallback = test_WM_SETTEXT_esCallback; + memset(buf, 0, sizeof(buf)); + SendMessage(hwndRichEdit, EM_STREAMOUT, + (WPARAM)(SF_TEXT), (LPARAM)&es); + r = strlen(buf); + /* Here again, \r gets converted to \r\n, like WM_GETTEXT */ + ok(r == 14, "streamed text length is %d, expecting 14\n", r); + ok(strcmp(buf, TestItem3) == 0, + "streamed text different from, got %s\n", buf); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem3); + p = buf; + es.dwCookie = (DWORD_PTR)&p; + es.dwError = 0; + es.pfnCallback = test_WM_SETTEXT_esCallback; + memset(buf, 0, sizeof(buf)); + SendMessage(hwndRichEdit, EM_STREAMOUT, + (WPARAM)(SF_TEXT), (LPARAM)&es); + r = strlen(buf); + ok(r == 14, "streamed text length is %d, expecting 14\n", r); + ok(strcmp(buf, TestItem3) == 0, + "streamed text different, got %s\n", buf); + + DestroyWindow(hwndRichEdit); +} + static void test_EM_SETTEXTEX(void) { HWND hwndRichEdit = new_richedit(NULL); @@ -1126,8 +1366,10 @@ static void test_EM_SETTEXTEX(void) ' ','\r', 0}; #define MAX_BUF_LEN 1024 WCHAR buf[MAX_BUF_LEN]; + char * p; int result; CHARRANGE cr; + EDITSTREAM es; setText.codepage = 1200; /* no constant for unicode */ getText.codepage = 1200; /* no constant for unicode */ @@ -1274,6 +1516,31 @@ static void test_EM_SETTEXTEX(void) "EM_SETTEXTEX to replace selection with more text failed: %i.\n", lstrlenW(buf) ); + /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "TestSomeText"); /* TestItem1 */ + p = (char *)buf; + es.dwCookie = (DWORD_PTR)&p; + es.dwError = 0; + es.pfnCallback = test_WM_SETTEXT_esCallback; + memset(buf, 0, sizeof(buf)); + SendMessage(hwndRichEdit, EM_STREAMOUT, + (WPARAM)(SF_RTF), (LPARAM)&es); + trace("EM_STREAMOUT produced: \n%s\n", (char *)buf); + + setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */ + getText.codepage = 1200; /* no constant for unicode */ + getText.cb = MAX_BUF_LEN; + getText.flags = GT_DEFAULT; + getText.lpDefaultChar = NULL; + getText.lpUsedDefChar = NULL; + + setText.flags = 0; + SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) buf); + SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf); + ok(lstrcmpW(buf, TestItem1) == 0, + "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); + + DestroyWindow(hwndRichEdit); } @@ -1492,21 +1759,21 @@ static void test_WM_SETFONT(void) GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont); ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName), - "EM_GETCHARFOMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n", + "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n", sentLogFont.lfFaceName,returnedCF2A.szFaceName); SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2,(LPARAM) MAKELONG((WORD) TRUE, 0)); SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A); GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont); ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName), - "EM_GETCHARFOMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n", + "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n", sentLogFont.lfFaceName,returnedCF2A.szFaceName); SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3,(LPARAM) MAKELONG((WORD) TRUE, 0)); SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A); GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont); ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName), - "EM_GETCHARFOMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n", + "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n", sentLogFont.lfFaceName,returnedCF2A.szFaceName); /* This last test is special since we send in NULL. We clear the variables @@ -1519,7 +1786,7 @@ static void test_WM_SETFONT(void) SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A); GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont); ok (!strcmp("System",returnedCF2A.szFaceName), - "EM_GETCHARFOMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName); + "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName); DestroyWindow(hwndRichEdit); } @@ -1532,7 +1799,7 @@ static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie, { const char** str = (const char**)dwCookie; int size = strlen(*str); - if(size > 3) /* let's make it peice-meal for fun */ + if(size > 3) /* let's make it piecemeal for fun */ size = 3; *pcb = cb; if (*pcb > size) { @@ -1793,7 +2060,7 @@ static void test_EM_EXSETSEL(void) DestroyWindow(hwndRichEdit); } -static void test_EM_REPLACESEL(void) +static void test_EM_REPLACESEL(int redraw) { HWND hwndRichEdit = new_richedit(NULL); char buffer[1024] = {0}; @@ -1818,6 +2085,9 @@ static void test_EM_REPLACESEL(void) hwndRichEdit = new_richedit(NULL); + trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw); + SendMessage(hwndRichEdit, WM_SETREDRAW, redraw, 0); + /* Test behavior with carriage returns and newlines */ SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1"); @@ -1834,6 +2104,10 @@ static void test_EM_REPLACESEL(void) ok(strcmp(buffer, "RichEdit1") == 0, "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n"); + /* Test number of lines reported after EM_REPLACESEL */ + r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1\r"); ok(10 == r, "EM_REPLACESEL returned %d, expected 10\n", r); @@ -1849,6 +2123,10 @@ static void test_EM_REPLACESEL(void) ok(strcmp(buffer, "RichEdit1\r") == 0, "EM_GETTEXTEX returned incorrect string\n"); + /* Test number of lines reported after EM_REPLACESEL */ + r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r); + /* Win98's riched20 and WinXP's riched20 disagree on what to return from EM_REPLACESEL. The general rule seems to be that Win98's riched20 returns the number of characters *inserted* into the control (after @@ -1861,6 +2139,10 @@ static void test_EM_REPLACESEL(void) ok(11 == r /* WinXP */ || 10 == r /* Win98 */, "EM_REPLACESEL returned %d, expected 11 or 10\n", r); + /* Test number of lines reported after EM_REPLACESEL */ + r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r); + r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r); ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin); @@ -1907,6 +2189,10 @@ static void test_EM_REPLACESEL(void) ok(strcmp(buffer, "\r\r") == 0, "EM_GETTEXTEX returned incorrect string\n"); + /* Test number of lines reported after EM_REPLACESEL */ + r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n"); ok(3 == r /* WinXP */ || 1 == r /* Win98 */, @@ -1926,6 +2212,10 @@ static void test_EM_REPLACESEL(void) ok(strcmp(buffer, " ") == 0, "EM_GETTEXTEX returned incorrect string\n"); + /* Test number of lines reported after EM_REPLACESEL */ + r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\r\r\r\n\r\r\r"); ok(9 == r /* WinXP */ || 7 == r /* Win98 */, @@ -1945,6 +2235,10 @@ static void test_EM_REPLACESEL(void) ok(strcmp(buffer, "\r\r\r \r\r\r") == 0, "EM_GETTEXTEX returned incorrect string\n"); + /* Test number of lines reported after EM_REPLACESEL */ + r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\n"); ok(5 == r /* WinXP */ || 2 == r /* Win98 */, @@ -1964,6 +2258,10 @@ static void test_EM_REPLACESEL(void) ok(strcmp(buffer, " \r") == 0, "EM_GETTEXTEX returned incorrect string\n"); + /* Test number of lines reported after EM_REPLACESEL */ + r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\r"); ok(5 == r /* WinXP */ || 3 == r /* Win98 */, @@ -1983,6 +2281,10 @@ static void test_EM_REPLACESEL(void) ok(strcmp(buffer, " \r\r") == 0, "EM_GETTEXTEX returned incorrect string\n"); + /* Test number of lines reported after EM_REPLACESEL */ + r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\rX\r\n\r\r"); ok(6 == r /* WinXP */ || 5 == r /* Win98 */, @@ -2002,6 +2304,10 @@ static void test_EM_REPLACESEL(void) ok(strcmp(buffer, "\rX\r\r\r") == 0, "EM_GETTEXTEX returned incorrect string\n"); + /* Test number of lines reported after EM_REPLACESEL */ + r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + ok(r == 5, "EM_GETLINECOUNT returned %d, expected 5\n", r); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n"); ok(2 == r, "EM_REPLACESEL returned %d, expected 2\n", r); @@ -2020,6 +2326,10 @@ static void test_EM_REPLACESEL(void) ok(strcmp(buffer, "\r\r") == 0, "EM_GETTEXTEX returned incorrect string\n"); + /* Test number of lines reported after EM_REPLACESEL */ + r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n\n\n\r\r\r\r\n"); ok(9 == r /* WinXP */ || 7 == r /* Win98 */, @@ -2039,6 +2349,10 @@ static void test_EM_REPLACESEL(void) ok(strcmp(buffer, "\r\r\r\r\r\r ") == 0, "EM_GETTEXTEX returned incorrect string\n"); + /* Test number of lines reported after EM_REPLACESEL */ + r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r); + DestroyWindow(hwndRichEdit); } @@ -2199,6 +2513,139 @@ static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, return 1; /* indicates callback failed */ } +static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie, + LPBYTE pbBuff, + LONG cb, + LONG *pcb) +{ + const char** str = (const char**)dwCookie; + int size = strlen(*str); + *pcb = cb; + if (*pcb > size) { + *pcb = size; + } + if (*pcb > 0) { + memcpy(pbBuff, *str, *pcb); + *str += *pcb; + } + return 0; +} + + +static void test_EM_STREAMIN(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + LRESULT result; + EDITSTREAM es; + char buffer[1024] = {0}; + + const char * streamText0 = "{\\rtf1 TestSomeText}"; + const char * streamText0a = "{\\rtf1 TestSomeText\\par}"; + const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}"; + + const char * streamText1 = + "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" \ + "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" \ + "}\r\n"; + + /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */ + const char * streamText2 = + "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;" \ + "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255" \ + "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 " \ + "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 " \ + "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 " \ + "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 " \ + "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }"; + + const char * streamText3 = "RichEdit1"; + + /* Minimal test without \par at the end */ + es.dwCookie = (DWORD_PTR)&streamText0; + es.dwError = 0; + es.pfnCallback = test_EM_STREAMIN_esCallback; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok (result == 12, + "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result); + result = strcmp (buffer,"TestSomeText"); + ok (result == 0, + "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer); + ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0); + + /* Native richedit 2.0 ignores last \par */ + es.dwCookie = (DWORD_PTR)&streamText0a; + es.dwError = 0; + es.pfnCallback = test_EM_STREAMIN_esCallback; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok (result == 12, + "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result); + result = strcmp (buffer,"TestSomeText"); + ok (result == 0, + "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer); + ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es.dwError, 0); + + /* Native richedit 2.0 ignores last \par, next-to-last \par appears */ + es.dwCookie = (DWORD_PTR)&streamText0b; + es.dwError = 0; + es.pfnCallback = test_EM_STREAMIN_esCallback; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok (result == 14, + "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result); + result = strcmp (buffer,"TestSomeText\r\n"); + ok (result == 0, + "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer); + ok(es.dwError == 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es.dwError, 0); + + es.dwCookie = (DWORD_PTR)&streamText1; + es.dwError = 0; + es.pfnCallback = test_EM_STREAMIN_esCallback; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok (result == 12, + "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result); + result = strcmp (buffer,"TestSomeText"); + ok (result == 0, + "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer); + ok(es.dwError == 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es.dwError, 0); + + es.dwCookie = (DWORD_PTR)&streamText2; + es.dwError = 0; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok (result == 0, + "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result); + ok (strlen(buffer) == 0, + "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer); + ok(es.dwError == -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es.dwError, -16); + + es.dwCookie = (DWORD_PTR)&streamText3; + es.dwError = 0; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok (result == 0, + "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result); + ok (strlen(buffer) == 0, + "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer); + ok(es.dwError == -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es.dwError, -16); + + DestroyWindow(hwndRichEdit); +} + static void test_EM_StreamIn_Undo(void) { /* The purpose of this test is to determine when a EM_StreamIn should be @@ -2684,6 +3131,82 @@ static void test_eventMask(void) } +static int received_WM_NOTIFY = 0; +static int modify_at_WM_NOTIFY = 0; +static HWND hwndRichedit_WM_NOTIFY; + +static LRESULT WINAPI WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + if(message == WM_NOTIFY) + { + received_WM_NOTIFY = 1; + modify_at_WM_NOTIFY = SendMessage(hwndRichedit_WM_NOTIFY, EM_GETMODIFY, 0, 0); + } + return DefWindowProcA(hwnd, message, wParam, lParam); +} + +static void test_WM_NOTIFY(void) +{ + HWND parent; + WNDCLASSA cls; + CHARFORMAT2 cf2; + + /* register class to capture WM_NOTIFY */ + cls.style = 0; + cls.lpfnWndProc = WM_NOTIFY_ParentMsgCheckProcA; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "WM_NOTIFY_ParentClass"; + if(!RegisterClassA(&cls)) assert(0); + + parent = CreateWindow(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE, + 0, 0, 200, 60, NULL, NULL, NULL, NULL); + ok (parent != 0, "Failed to create parent window\n"); + + hwndRichedit_WM_NOTIFY = new_richedit(parent); + ok(hwndRichedit_WM_NOTIFY != 0, "Failed to create edit window\n"); + + SendMessage(hwndRichedit_WM_NOTIFY, EM_SETEVENTMASK, 0, ENM_SELCHANGE); + + /* Notifications for selection change should only be sent when selection + actually changes. EM_SETCHARFORMAT is one message that calls + ME_CommitUndo, which should check whether message should be sent */ + received_WM_NOTIFY = 0; + cf2.cbSize = sizeof(CHARFORMAT2); + SendMessage(hwndRichedit_WM_NOTIFY, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, + (LPARAM) &cf2); + cf2.dwMask = CFM_ITALIC | cf2.dwMask; + cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; + SendMessage(hwndRichedit_WM_NOTIFY, EM_SETCHARFORMAT, 0, (LPARAM) &cf2); + ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n"); + + /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is + already at 0. */ + received_WM_NOTIFY = 0; + modify_at_WM_NOTIFY = 0; + SendMessage(hwndRichedit_WM_NOTIFY, WM_SETTEXT, 0, (LPARAM)"sometext"); + ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n"); + ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n"); + + received_WM_NOTIFY = 0; + modify_at_WM_NOTIFY = 0; + SendMessage(hwndRichedit_WM_NOTIFY, EM_SETSEL, 4, 4); + ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n"); + + received_WM_NOTIFY = 0; + modify_at_WM_NOTIFY = 0; + SendMessage(hwndRichedit_WM_NOTIFY, WM_SETTEXT, 0, (LPARAM)"sometext"); + ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n"); + ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n"); + + DestroyWindow(hwndRichedit_WM_NOTIFY); + DestroyWindow(parent); +} START_TEST( editor ) { @@ -2694,18 +3217,20 @@ START_TEST( editor ) * RICHED20.DLL, so the linker doesn't actually link to it. */ hmoduleRichEdit = LoadLibrary("RICHED20.DLL"); ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError()); - test_WM_CHAR(); test_EM_FINDTEXT(); test_EM_GETLINE(); test_EM_SCROLLCARET(); test_EM_SCROLL(); test_WM_SETTEXT(); + test_EM_LINELENGTH(); test_EM_SETCHARFORMAT(); test_EM_SETTEXTMODE(); test_TM_PLAINTEXT(); test_EM_SETOPTIONS(); test_WM_GETTEXT(); + test_EM_GETTEXTRANGE(); + test_EM_GETSELTEXT(); test_EM_AUTOURLDETECT(); test_EM_SETUNDOLIMIT(); test_ES_PASSWORD(); @@ -2717,11 +3242,15 @@ START_TEST( editor ) test_EM_GETMODIFY(); test_EM_EXSETSEL(); test_WM_PASTE(); + test_EM_STREAMIN(); + test_EM_STREAMOUT(); test_EM_StreamIn_Undo(); test_EM_FORMATRANGE(); test_unicode_conversions(); test_EM_GETTEXTLENGTHEX(); - test_EM_REPLACESEL(); + test_EM_REPLACESEL(1); + test_EM_REPLACESEL(0); + test_WM_NOTIFY(); test_eventMask(); /* Set the environment variable WINETEST_RICHED20 to keep windows diff --git a/rostests/winetests/riched20/riched20.rbuild b/rostests/winetests/riched20/riched20.rbuild index 86c225b7b2d..94404acbe00 100644 --- a/rostests/winetests/riched20/riched20.rbuild +++ b/rostests/winetests/riched20/riched20.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/riched32/editor.c b/rostests/winetests/riched32/editor.c index 66a30909f3e..ff82654ff6e 100644 --- a/rostests/winetests/riched32/editor.c +++ b/rostests/winetests/riched32/editor.c @@ -64,6 +64,9 @@ static void test_WM_SETTEXT() const char * TestItem11 = "TestSomeText TestSomeText"; const char * TestItem12 = "TestSomeText \r\nTestSomeText"; const char * TestItem13 = "TestSomeText\r\n \r\nTestSomeText"; + const char * TestItem14 = "TestSomeText\n"; + const char * TestItem15 = "TestSomeText\r\r\r"; + const char * TestItem16 = "TestSomeText\r\r\rSomeMoreText"; char buf[1024] = {0}; LRESULT result; @@ -72,9 +75,19 @@ static void test_WM_SETTEXT() return it as is. In particular, \r\r\n is NOT converted, unlike riched20. Currently, builtin riched32 mangles solitary \r or \n when not part of a \r\n pair. + + For riched32, the rules for breaking lines seem to be the following: + - \r\n is one line break. This is the normal case. + - \r{0,N}\n is one line break. In particular, \n by itself is a line break. + - \n{1,N} are that many line breaks. + - \r with text or other characters (except \n) past it, is a line break. That + is, a run of \r{N} without a terminating \n is considered N line breaks + - \r at the end of the text is NOT a line break. This differs from riched20, + where \r at the end of the text is a proper line break. This causes + TestItem2 to fail its test. */ -#define TEST_SETTEXT(a, b, is_todo) \ +#define TEST_SETTEXT(a, b, nlines, is_todo, is_todo2) \ result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \ ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \ result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf); \ @@ -88,21 +101,30 @@ static void test_WM_SETTEXT() } else { \ ok(result == 0, \ "WM_SETTEXT round trip: strcmp = %ld\n", result); \ + } \ + result = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); \ + if (is_todo2) todo_wine { \ + ok(result == nlines, "EM_GETLINECOUNT returned %ld, expected %d\n", result, nlines); \ + } else { \ + ok(result == nlines, "EM_GETLINECOUNT returned %ld, expected %d\n", result, nlines); \ } - TEST_SETTEXT(TestItem1, TestItem1, 0) - TEST_SETTEXT(TestItem2, TestItem2, 1) - TEST_SETTEXT(TestItem3, TestItem3, 1) - TEST_SETTEXT(TestItem4, TestItem4, 1) - TEST_SETTEXT(TestItem5, TestItem5, 1) - TEST_SETTEXT(TestItem6, TestItem6, 1) - TEST_SETTEXT(TestItem7, TestItem7, 1) - TEST_SETTEXT(TestItem8, TestItem8, 0) - TEST_SETTEXT(TestItem9, TestItem9, 0) - TEST_SETTEXT(TestItem10, TestItem10, 0) - TEST_SETTEXT(TestItem11, TestItem11, 0) - TEST_SETTEXT(TestItem12, TestItem12, 0) - TEST_SETTEXT(TestItem13, TestItem13, 0) + TEST_SETTEXT(TestItem1, TestItem1, 1, 0, 0) + TEST_SETTEXT(TestItem2, TestItem2, 1, 0, 0) + TEST_SETTEXT(TestItem3, TestItem3, 2, 0, 0) + TEST_SETTEXT(TestItem4, TestItem4, 3, 0, 0) + TEST_SETTEXT(TestItem5, TestItem5, 2, 0, 0) + TEST_SETTEXT(TestItem6, TestItem6, 3, 0, 0) + TEST_SETTEXT(TestItem7, TestItem7, 4, 0, 0) + TEST_SETTEXT(TestItem8, TestItem8, 2, 0, 0) + TEST_SETTEXT(TestItem9, TestItem9, 3, 0, 0) + TEST_SETTEXT(TestItem10, TestItem10, 3, 0, 0) + TEST_SETTEXT(TestItem11, TestItem11, 1, 0, 0) + TEST_SETTEXT(TestItem12, TestItem12, 2, 0, 0) + TEST_SETTEXT(TestItem13, TestItem13, 3, 0, 0) + TEST_SETTEXT(TestItem14, TestItem14, 2, 0, 0) + TEST_SETTEXT(TestItem15, TestItem15, 3, 0, 0) + TEST_SETTEXT(TestItem16, TestItem16, 4, 0, 0) #undef TEST_SETTEXT DestroyWindow(hwndRichEdit); @@ -131,6 +153,551 @@ static void test_WM_GETTEXTLENGTH(void) DestroyWindow(hwndRichEdit); } +static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie, + LPBYTE pbBuff, + LONG cb, + LONG *pcb) +{ + const char** str = (const char**)dwCookie; + int size = strlen(*str); + *pcb = cb; + if (*pcb > size) { + *pcb = size; + } + if (*pcb > 0) { + memcpy(pbBuff, *str, *pcb); + *str += *pcb; + } + return 0; +} + + +static void test_EM_STREAMIN(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + LRESULT result; + EDITSTREAM es; + char buffer[1024] = {0}; + + const char * streamText0 = "{\\rtf1 TestSomeText}"; + const char * streamText0a = "{\\rtf1 TestSomeText\\par}"; + const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}"; + + const char * streamText1 = + "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" \ + "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" \ + "}\r\n"; + + /* This should be accepted in richedit 1.0 emulation. See bug #8326 */ + const char * streamText2 = + "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;" \ + "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255" \ + "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 " \ + "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 " \ + "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 " \ + "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 " \ + "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }"; + + const char * streamText3 = "RichEdit1"; + + /* Minimal test without \par at the end */ + es.dwCookie = (DWORD_PTR)&streamText0; + es.dwError = 0; + es.pfnCallback = test_EM_STREAMIN_esCallback; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok (result == 12, + "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result); + result = strcmp (buffer,"TestSomeText"); + ok (result == 0, + "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer); + ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0); + + /* Native richedit 2.0 ignores last \par */ + es.dwCookie = (DWORD_PTR)&streamText0a; + es.dwError = 0; + es.pfnCallback = test_EM_STREAMIN_esCallback; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok (result == 12, + "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result); + result = strcmp (buffer,"TestSomeText"); + ok (result == 0, + "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer); + ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0); + + /* Native richedit 2.0 ignores last \par, next-to-last \par appears */ + es.dwCookie = (DWORD_PTR)&streamText0b; + es.dwError = 0; + es.pfnCallback = test_EM_STREAMIN_esCallback; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok (result == 14, + "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result); + result = strcmp (buffer,"TestSomeText\r\n"); + ok (result == 0, + "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer); + ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0); + + es.dwCookie = (DWORD_PTR)&streamText1; + es.dwError = 0; + es.pfnCallback = test_EM_STREAMIN_esCallback; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok (result == 12, + "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result); + result = strcmp (buffer,"TestSomeText"); + ok (result == 0, + "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer); + ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0); + + + es.dwCookie = (DWORD_PTR)&streamText2; + es.dwError = 0; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + todo_wine { + ok (result == 9, + "EM_STREAMIN: Test 2 returned %ld, expected 9\n", result); + } + result = strcmp (buffer,"RichEdit1"); + todo_wine { + ok (result == 0, + "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer); + } + ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0); + + es.dwCookie = (DWORD_PTR)&streamText3; + es.dwError = 0; + SendMessage(hwndRichEdit, EM_STREAMIN, + (WPARAM)(SF_RTF), (LPARAM)&es); + + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok (result == 0, + "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result); + ok (strlen(buffer) == 0, + "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer); + ok(es.dwError == -16, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, -16); + + DestroyWindow(hwndRichEdit); +} + +static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie, + LPBYTE pbBuff, + LONG cb, + LONG *pcb) +{ + char** str = (char**)dwCookie; + *pcb = cb; + if (*pcb > 0) { + memcpy(*str, pbBuff, *pcb); + *str += *pcb; + } + return 0; +} + +static void test_EM_STREAMOUT(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + int r; + EDITSTREAM es; + char buf[1024] = {0}; + char * p; + + const char * TestItem1 = "TestSomeText"; + const char * TestItem2 = "TestSomeText\r"; + const char * TestItem3 = "TestSomeText\r\n"; + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1); + p = buf; + es.dwCookie = (DWORD_PTR)&p; + es.dwError = 0; + es.pfnCallback = test_WM_SETTEXT_esCallback; + memset(buf, 0, sizeof(buf)); + SendMessage(hwndRichEdit, EM_STREAMOUT, + (WPARAM)(SF_TEXT), (LPARAM)&es); + r = strlen(buf); + ok(r == 12, "streamed text length is %d, expecting 12\n", r); + ok(strcmp(buf, TestItem1) == 0, + "streamed text different, got %s\n", buf); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem2); + p = buf; + es.dwCookie = (DWORD_PTR)&p; + es.dwError = 0; + es.pfnCallback = test_WM_SETTEXT_esCallback; + memset(buf, 0, sizeof(buf)); + SendMessage(hwndRichEdit, EM_STREAMOUT, + (WPARAM)(SF_TEXT), (LPARAM)&es); + r = strlen(buf); + + ok(r == 13, "streamed text length is %d, expecting 13\n", r); + ok(strcmp(buf, TestItem2) == 0, + "streamed text different, got %s\n", buf); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem3); + p = buf; + es.dwCookie = (DWORD_PTR)&p; + es.dwError = 0; + es.pfnCallback = test_WM_SETTEXT_esCallback; + memset(buf, 0, sizeof(buf)); + SendMessage(hwndRichEdit, EM_STREAMOUT, + (WPARAM)(SF_TEXT), (LPARAM)&es); + r = strlen(buf); + ok(r == 14, "streamed text length is %d, expecting 14\n", r); + ok(strcmp(buf, TestItem3) == 0, + "streamed text different, got %s\n", buf); + + DestroyWindow(hwndRichEdit); +} + +static const struct getline_s { + int line; + size_t buffer_len; + const char *text; + int wine_todo; +} gl[] = { + {0, 10, "foo bar\r\n", 0}, + {1, 10, "\n", 0}, + {2, 10, "bar\n", 0}, + {3, 10, "\r\n", 0}, + + /* Buffer smaller than line length */ + {0, 2, "foo bar\r", 0}, + {0, 1, "foo bar\r", 0}, + {0, 0, "foo bar\r", 0} +}; + +static void test_EM_GETLINE(void) +{ + int i; + HWND hwndRichEdit = new_richedit(NULL); + static const int nBuf = 1024; + char dest[1024], origdest[1024]; + const char text[] = "foo bar\r\n" + "\n" + "bar\n"; + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text); + + memset(origdest, 0xBB, nBuf); + for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++) + { + int nCopied; + int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text)); + int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text) + 1); + memset(dest, 0xBB, nBuf); + *(WORD *) dest = gl[i].buffer_len; + + /* EM_GETLINE appends a "\r\0" to the end of the line + * nCopied counts up to and including the '\r' */ + nCopied = SendMessage(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM) dest); + if (gl[i].wine_todo) todo_wine { + ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied, + expected_nCopied); + } else + ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied, + expected_nCopied); + /* two special cases since a parameter is passed via dest */ + if (gl[i].buffer_len == 0) + ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2), + "buffer_len=0\n"); + else if (gl[i].buffer_len == 1) + ok(dest[0] == gl[i].text[0] && !dest[1] && + !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n"); + else + { + if (gl[i].wine_todo) todo_wine { + ok(!strncmp(dest, gl[i].text, expected_bytes_written), + "%d: expected_bytes_written=%d\n", i, expected_bytes_written); + ok(!strncmp(dest + expected_bytes_written, origdest + + expected_bytes_written, nBuf - expected_bytes_written), + "%d: expected_bytes_written=%d\n", i, expected_bytes_written); + } + else + { + ok(!strncmp(dest, gl[i].text, expected_bytes_written), + "%d: expected_bytes_written=%d\n", i, expected_bytes_written); + ok(!strncmp(dest + expected_bytes_written, origdest + + expected_bytes_written, nBuf - expected_bytes_written), + "%d: expected_bytes_written=%d\n", i, expected_bytes_written); + } + } + } + + DestroyWindow(hwndRichEdit); +} + +static void test_EM_LINELENGTH(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + const char * text = + "richedit1\r" + "richedit1\n" + "richedit1\r\n" + "richedit1\r\r\r\r\r\n"; + int offset_test[10][2] = { + {0, 9}, + {5, 9}, + {10, 9}, + {15, 9}, + {20, 9}, + {25, 9}, + {30, 9}, + {35, 9}, + {40, 9}, /* <----- in the middle of the \r run, but run not counted */ + {45, 0}, + }; + int i; + LRESULT result; + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text); + + for (i = 0; i < 10; i++) { + result = SendMessage(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0); + ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n", + offset_test[i][0], result, offset_test[i][1]); + } + + DestroyWindow(hwndRichEdit); +} + +static void test_EM_GETTEXTRANGE(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + const char * text1 = "foo bar\r\nfoo bar"; + const char * text2 = "foo bar\rfoo bar"; + const char * expect1 = "bar\r\nfoo"; + const char * expect2 = "bar\rfoo"; + char buffer[1024] = {0}; + LRESULT result; + TEXTRANGEA textRange; + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); + + textRange.lpstrText = buffer; + textRange.chrg.cpMin = 4; + textRange.chrg.cpMax = 12; + result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); + ok(result == 8, "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(expect1, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); + + textRange.lpstrText = buffer; + textRange.chrg.cpMin = 4; + textRange.chrg.cpMax = 11; + result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); + ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); + + ok(!strcmp(expect2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + + DestroyWindow(hwndRichEdit); +} + +static void test_EM_GETSELTEXT(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + const char * text1 = "foo bar\r\nfoo bar"; + const char * text2 = "foo bar\rfoo bar"; + const char * expect1 = "bar\r\nfoo"; + const char * expect2 = "bar\rfoo"; + char buffer[1024] = {0}; + LRESULT result; + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); + + SendMessage(hwndRichEdit, EM_SETSEL, 4, 12); + result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer); + ok(result == 8, "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(expect1, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); + + SendMessage(hwndRichEdit, EM_SETSEL, 4, 11); + result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer); + ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); + + ok(!strcmp(expect2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + + DestroyWindow(hwndRichEdit); +} + +static const char haystack[] = "WINEWine wineWine wine WineWine"; + /* ^0 ^10 ^20 ^30 */ + +struct find_s { + int start; + int end; + const char *needle; + int flags; + int expected_loc; + int _todo_wine; +}; + + +struct find_s find_tests[] = { + /* Find in empty text */ + {0, -1, "foo", FR_DOWN, -1, 0}, + {0, -1, "foo", 0, -1, 0}, + {0, -1, "", FR_DOWN, -1, 0}, + {20, 5, "foo", FR_DOWN, -1, 0}, + {5, 20, "foo", FR_DOWN, -1, 0} +}; + +struct find_s find_tests2[] = { + /* No-result find */ + {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1, 0}, + {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1, 0}, + + /* Subsequent finds */ + {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4, 0}, + {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13, 0}, + {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0}, + {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0}, + + /* Find backwards */ + {19, 20, "Wine", FR_MATCHCASE, -1, 0}, + {10, 20, "Wine", FR_MATCHCASE, 13, 0}, + {20, 10, "Wine", FR_MATCHCASE, -1, 0}, + + /* Case-insensitive */ + {1, 31, "wInE", FR_DOWN, 4, 0}, + {1, 31, "Wine", FR_DOWN, 4, 0}, + + /* High-to-low ranges */ + {20, 5, "Wine", FR_DOWN, -1, 0}, + {2, 1, "Wine", FR_DOWN, -1, 0}, + {30, 29, "Wine", FR_DOWN, -1, 0}, + {20, 5, "Wine", 0, /*13*/ -1, 0}, + + /* Find nothing */ + {5, 10, "", FR_DOWN, -1, 0}, + {10, 5, "", FR_DOWN, -1, 0}, + {0, -1, "", FR_DOWN, -1, 0}, + {10, 5, "", 0, -1, 0}, + + /* Whole-word search */ + {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0}, + {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 0}, + {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0}, + {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0, 0}, + {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23, 0}, + {11, -1, "winewine", FR_WHOLEWORD, 23, 0}, + {31, -1, "winewine", FR_WHOLEWORD, -1, 0}, + + /* Bad ranges */ + {5, 200, "XXX", FR_DOWN, -1, 0}, + {-20, 20, "Wine", FR_DOWN, -1, 0}, + {-20, 20, "Wine", FR_DOWN, -1, 0}, + {-15, -20, "Wine", FR_DOWN, -1, 0}, + {1<<12, 1<<13, "Wine", FR_DOWN, -1, 0}, + + /* Check the case noted in bug 4479 where matches at end aren't recognized */ + {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0}, + {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0}, + {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0}, + {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0}, + {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0}, + + /* The backwards case of bug 4479; bounds look right + * Fails because backward find is wrong */ + {19, 20, "WINE", FR_MATCHCASE, -1, 0}, + {0, 20, "WINE", FR_MATCHCASE, 0, 0}, + + {0, -1, "wineWine wine", FR_DOWN, 0, 0}, + {0, -1, "wineWine wine", 0, 0, 0}, + {0, -1, "INEW", 0, 1, 0}, + {0, 31, "INEW", 0, 1, 0}, + {4, -1, "INEW", 0, 10, 0}, +}; + +static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) { + int findloc; + FINDTEXT ft; + memset(&ft, 0, sizeof(ft)); + ft.chrg.cpMin = f->start; + ft.chrg.cpMax = f->end; + ft.lpstrText = f->needle; + findloc = SendMessage(hwnd, EM_FINDTEXT, f->flags, (LPARAM) &ft); + ok(findloc == f->expected_loc, + "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n", + name, id, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc); +} + +static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f, + int id) { + int findloc; + FINDTEXTEX ft; + int expected_end_loc; + + memset(&ft, 0, sizeof(ft)); + ft.chrg.cpMin = f->start; + ft.chrg.cpMax = f->end; + ft.lpstrText = f->needle; + findloc = SendMessage(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM) &ft); + ok(findloc == f->expected_loc, + "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n", + name, id, f->needle, f->start, f->end, f->flags, findloc); + ok(ft.chrgText.cpMin == f->expected_loc, + "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d, expected %d\n", + name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin, f->expected_loc); + expected_end_loc = ((f->expected_loc == -1) ? -1 + : f->expected_loc + strlen(f->needle)); + ok(ft.chrgText.cpMax == expected_end_loc, + "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n", + name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax, expected_end_loc); +} + +static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find, + int num_tests) +{ + int i; + + for (i = 0; i < num_tests; i++) { + if (find[i]._todo_wine) { + todo_wine { + check_EM_FINDTEXT(hwnd, name, &find[i], i); + check_EM_FINDTEXTEX(hwnd, name, &find[i], i); + } + } else { + check_EM_FINDTEXT(hwnd, name, &find[i], i); + check_EM_FINDTEXTEX(hwnd, name, &find[i], i); + } + } +} + +static void test_EM_FINDTEXT(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + + /* Empty rich edit control */ + run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests, + sizeof(find_tests)/sizeof(struct find_s)); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack); + + /* Haystack text */ + run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2, + sizeof(find_tests2)/sizeof(struct find_s)); + + DestroyWindow(hwndRichEdit); +} + + + START_TEST( editor ) { MSG msg; @@ -142,7 +709,14 @@ START_TEST( editor ) ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError()); test_WM_SETTEXT(); + test_EM_GETTEXTRANGE(); + test_EM_GETSELTEXT(); test_WM_GETTEXTLENGTH(); + test_EM_STREAMIN(); + test_EM_STREAMOUT(); + test_EM_GETLINE(); + test_EM_LINELENGTH(); + test_EM_FINDTEXT(); /* Set the environment variable WINETEST_RICHED32 to keep windows * responsive and open for 30 seconds. This is useful for debugging. diff --git a/rostests/winetests/riched32/riched32.rbuild b/rostests/winetests/riched32/riched32.rbuild index 4c328a2301f..0b2cca9a566 100644 --- a/rostests/winetests/riched32/riched32.rbuild +++ b/rostests/winetests/riched32/riched32.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/rpcrt4/cstub.c b/rostests/winetests/rpcrt4/cstub.c index 6a38397f679..a47fa6eeb14 100644 --- a/rostests/winetests/rpcrt4/cstub.c +++ b/rostests/winetests/rpcrt4/cstub.c @@ -924,6 +924,8 @@ static void test_delegating_Invoke(IPSFactoryBuffer *ppsf) ok(*(DWORD*)msg.Buffer == 0xabcdef, "buf[0] %08x\n", *(DWORD*)msg.Buffer); ok(*((DWORD*)msg.Buffer + 1) == S_OK, "buf[1] %08x\n", *((DWORD*)msg.Buffer + 1)); } + /* free the buffer allocated by delegating_invoke_chan_get_buffer */ + HeapFree(GetProcessHeap(), 0, msg.Buffer); IRpcStubBuffer_Release(pstub); } diff --git a/rostests/winetests/rpcrt4/generated.c b/rostests/winetests/rpcrt4/generated.c index fb7d7cca108..b281d0bb1fc 100644 --- a/rostests/winetests/rpcrt4/generated.c +++ b/rostests/winetests/rpcrt4/generated.c @@ -21,7 +21,7 @@ #include "wine/test.h" /*********************************************************************** - * Compability macros + * Compatibility macros */ #define DWORD_PTR UINT_PTR diff --git a/rostests/winetests/rpcrt4/ndr_marshall.c b/rostests/winetests/rpcrt4/ndr_marshall.c index eadb9c7395b..1ff5e3b0438 100644 --- a/rostests/winetests/rpcrt4/ndr_marshall.c +++ b/rostests/winetests/rpcrt4/ndr_marshall.c @@ -72,6 +72,31 @@ static const MIDL_STUB_DESC Object_StubDesc = 0 /* Reserved5 */ }; +static RPC_DISPATCH_FUNCTION IFoo_table[] = +{ + 0 +}; + +static RPC_DISPATCH_TABLE IFoo_v0_0_DispatchTable = +{ + 0, + IFoo_table +}; + +static const RPC_SERVER_INTERFACE IFoo___RpcServerInterface = +{ + sizeof(RPC_SERVER_INTERFACE), + {{0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x34}},{0,0}}, + {{0x8a885d04,0x1ceb,0x11c9,{0x9f,0xe8,0x08,0x00,0x2b,0x10,0x48,0x60}},{2,0}}, + &IFoo_v0_0_DispatchTable, + 0, + 0, + 0, + 0, + 0, +}; + +static RPC_IF_HANDLE IFoo_v0_0_s_ifspec = (RPC_IF_HANDLE)& IFoo___RpcServerInterface; static void test_ndr_simple_type(void) { @@ -251,7 +276,7 @@ todo_wine { ok(mem != StubMsg.BufferStart + wiredatalen - srcsize, "%s: mem points to buffer %p %p\n", msgpfx, mem, StubMsg.BufferStart); else ok(mem == StubMsg.BufferStart + wiredatalen - srcsize, "%s: mem doesn't point to buffer %p %p\n", msgpfx, mem, StubMsg.BufferStart); - ok(!cmp(mem, memsrc, size), "%s: incorrecly unmarshaled\n", msgpfx); + ok(!cmp(mem, memsrc, size), "%s: incorrectly unmarshaled\n", msgpfx); ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen); ok(StubMsg.MemorySize == 0, "%s: memorysize %d\n", msgpfx, StubMsg.MemorySize); if (formattypes[2] != 0xd /* FC_ENUM16 */) { @@ -452,6 +477,161 @@ static void test_simple_types(void) } +static void test_nontrivial_pointer_types(void) +{ + RPC_MESSAGE RpcMessage; + MIDL_STUB_MESSAGE StubMsg; + MIDL_STUB_DESC StubDesc; + void *ptr; + char **p1; + char *p2; + char ch; + unsigned char *mem, *mem_orig; + + static const unsigned char fmtstr_ref_unique_out[] = + { + 0x12, 0x8, /* FC_UP [simple_pointer] */ + 0x2, /* FC_CHAR */ + 0x5c, /* FC_PAD */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] [pointer_deref] */ + NdrFcShort( 0xfffffffa ), /* Offset= -6 (0) */ + }; + + p1 = &p2; + p2 = &ch; + ch = 0x22; + + StubDesc = Object_StubDesc; + StubDesc.pFormatTypes = fmtstr_ref_unique_out; + + NdrClientInitializeNew( + &RpcMessage, + &StubMsg, + &StubDesc, + 0); + + StubMsg.BufferLength = 0; + NdrPointerBufferSize( &StubMsg, + (unsigned char *)p1, + &fmtstr_ref_unique_out[4] ); + + /* Windows overestimates the buffer size */ + ok(StubMsg.BufferLength >= 5, "length %d\n", StubMsg.BufferLength); + + /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/ + StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength); + StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength; + + ptr = NdrPointerMarshall( &StubMsg, (unsigned char *)p1, &fmtstr_ref_unique_out[4] ); + ok(ptr == NULL, "ret %p\n", ptr); + ok(StubMsg.Buffer - StubMsg.BufferStart == 5, "Buffer %p Start %p len %d\n", + StubMsg.Buffer, StubMsg.BufferStart, StubMsg.Buffer - StubMsg.BufferStart); + ok(*(unsigned int *)StubMsg.BufferStart != 0, "pointer ID marshalled incorrectly\n"); + ok(*(unsigned char *)(StubMsg.BufferStart + 4) == 0x22, "char data marshalled incorrectly: 0x%x\n", + *(unsigned char *)(StubMsg.BufferStart + 4)); + + StubMsg.Buffer = StubMsg.BufferStart; + StubMsg.MemorySize = 0; + mem = NULL; + + /* Client */ + my_alloc_called = 0; + StubMsg.Buffer = StubMsg.BufferStart; + mem = mem_orig = HeapAlloc(GetProcessHeap(), 0, sizeof(void *)); + *(void **)mem = NULL; + NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 0); + ok(mem == mem_orig, "mem alloced\n"); + ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called); + + my_alloc_called = 0; + StubMsg.Buffer = StubMsg.BufferStart; + NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 1); + todo_wine { + ok(mem == mem_orig, "mem alloced\n"); + ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called); + } + + my_free_called = 0; + StubMsg.Buffer = StubMsg.BufferStart; + NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] ); + ok(my_free_called == 1, "free called %d\n", my_free_called); + + mem = my_alloc(sizeof(void *)); + *(void **)mem = NULL; + my_free_called = 0; + StubMsg.Buffer = StubMsg.BufferStart; + NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] ); + ok(my_free_called == 0, "free called %d\n", my_free_called); + my_free(mem); + + mem = my_alloc(sizeof(void *)); + *(void **)mem = my_alloc(sizeof(char)); + my_free_called = 0; + StubMsg.Buffer = StubMsg.BufferStart; + NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] ); + ok(my_free_called == 1, "free called %d\n", my_free_called); + my_free(mem); + + /* Server */ + my_alloc_called = 0; + StubMsg.IsClient = 0; + mem = NULL; + StubMsg.Buffer = StubMsg.BufferStart; + NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 0); + ok(mem != StubMsg.BufferStart, "mem pointing at buffer\n"); + todo_wine + ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called); + NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] ); + + my_alloc_called = 0; + mem = NULL; + StubMsg.Buffer = StubMsg.BufferStart; + NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 1); + ok(mem != StubMsg.BufferStart, "mem pointing at buffer\n"); + todo_wine + ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called); + NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] ); + + my_alloc_called = 0; + mem = mem_orig; + *(void **)mem = NULL; + StubMsg.Buffer = StubMsg.BufferStart; + NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 0); + todo_wine { + ok(mem == mem_orig, "mem alloced\n"); + ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called); + } + + my_alloc_called = 0; + mem = mem_orig; + *(void **)mem = NULL; + StubMsg.Buffer = StubMsg.BufferStart; + NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 1); + todo_wine { + ok(mem == mem_orig, "mem alloced\n"); + ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called); + } + + mem = my_alloc(sizeof(void *)); + *(void **)mem = NULL; + my_free_called = 0; + StubMsg.Buffer = StubMsg.BufferStart; + NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] ); + ok(my_free_called == 0, "free called %d\n", my_free_called); + my_free(mem); + + mem = my_alloc(sizeof(void *)); + *(void **)mem = my_alloc(sizeof(char)); + my_free_called = 0; + StubMsg.Buffer = StubMsg.BufferStart; + NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] ); + ok(my_free_called == 1, "free called %d\n", my_free_called); + my_free(mem); + + HeapFree(GetProcessHeap(), 0, mem_orig); + HeapFree(GetProcessHeap(), 0, StubMsg.RpcMsg->Buffer); +} + static void test_simple_struct_marshal(const unsigned char *formattypes, void *memsrc, long srcsize, @@ -520,7 +700,7 @@ todo_wine { my_alloc_called = 0; ok(StubMsg.MemorySize == 0, "%s: memorysize touched in unmarshal\n", msgpfx); - /* if we're a server we still use the suppiled memory */ + /* If we're a server we still use the supplied memory */ StubMsg.Buffer = StubMsg.BufferStart; StubMsg.IsClient = 0; ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 0 ); @@ -866,11 +1046,27 @@ static void test_client_init(void) MIDL_STUB_MESSAGE stubMsg; RPC_MESSAGE rpcMsg; - memset(&rpcMsg, 0, sizeof(rpcMsg)); + memset(&rpcMsg, 0xcc, sizeof(rpcMsg)); memset(&stubMsg, 0xcc, sizeof(stubMsg)); NdrClientInitializeNew(&rpcMsg, &stubMsg, &Object_StubDesc, 1); +#define TEST_POINTER_UNSET(field) ok(rpcMsg.field == (void *)0xcccccccc, #field " should have been unset instead of %p\n", rpcMsg.field) + + ok(rpcMsg.Handle == NULL, "rpcMsg.Handle should have been NULL instead of %p\n", rpcMsg.Handle); + TEST_POINTER_UNSET(Buffer); + ok(rpcMsg.BufferLength == 0xcccccccc, "rpcMsg.BufferLength should have been unset instead of %d\n", rpcMsg.BufferLength); + ok(rpcMsg.ProcNum == 0x8001, "rpcMsg.ProcNum should have been 0x8001 instead of 0x%x\n", rpcMsg.ProcNum); + TEST_POINTER_UNSET(TransferSyntax); + ok(rpcMsg.RpcInterfaceInformation == Object_StubDesc.RpcInterfaceInformation, + "rpcMsg.RpcInterfaceInformation should have been %p instead of %p\n", + Object_StubDesc.RpcInterfaceInformation, rpcMsg.RpcInterfaceInformation); + /* Note: ReservedForRuntime not tested */ + TEST_POINTER_UNSET(ManagerEpv); + TEST_POINTER_UNSET(ImportContext); + ok(rpcMsg.RpcFlags == 0, "rpcMsg.RpcFlags should have been 0 instead of 0x%lx\n", rpcMsg.RpcFlags); +#undef TEST_POINTER_UNSET + #define TEST_ZERO(field, fmt) ok(stubMsg.field == 0, #field " should have been set to zero instead of " fmt "\n", stubMsg.field) #define TEST_POINTER_UNSET(field) ok(stubMsg.field == (void *)0xcccccccc, #field " should have been unset instead of %p\n", stubMsg.field) #define TEST_ULONG_UNSET(field) ok(stubMsg.field == 0xcccccccc, #field " should have been unset instead of 0x%x\n", stubMsg.field) @@ -1509,10 +1705,120 @@ static void test_nonconformant_string(void) HeapFree(GetProcessHeap(), 0, StubMsg.RpcMsg->Buffer); } +static void test_ndr_buffer(void) +{ + static unsigned char ncalrpc[] = "ncalrpc"; + static unsigned char endpoint[] = "winetest:test_ndr_buffer"; + RPC_MESSAGE RpcMessage; + MIDL_STUB_MESSAGE StubMsg; + MIDL_STUB_DESC StubDesc = Object_StubDesc; + unsigned char *ret; + unsigned char *binding; + RPC_BINDING_HANDLE Handle; + RPC_STATUS status; + + StubDesc.RpcInterfaceInformation = (void *)&IFoo___RpcServerInterface; + + status = RpcServerUseProtseqEp(ncalrpc, 20, endpoint, NULL); + ok(RPC_S_OK == status, "RpcServerUseProtseqEp failed with status %lu\n", status); + status = RpcServerRegisterIf(IFoo_v0_0_s_ifspec, NULL, NULL); + ok(RPC_S_OK == status, "RpcServerRegisterIf failed with status %lu\n", status); + status = RpcServerListen(1, 20, TRUE); + ok(RPC_S_OK == status, "RpcServerListen failed with status %lu\n", status); + if (status != RPC_S_OK) + { + /* Failed to create a server, running client tests is useless */ + return; + } + + status = RpcStringBindingCompose(NULL, ncalrpc, NULL, endpoint, NULL, &binding); + ok(status == RPC_S_OK, "RpcStringBindingCompose failed (%lu)\n", status); + + status = RpcBindingFromStringBinding(binding, &Handle); + ok(status == RPC_S_OK, "RpcBindingFromStringBinding failed (%lu)\n", status); + RpcStringFree(&binding); + + NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 5); + + ret = NdrGetBuffer(&StubMsg, 10, Handle); + ok(ret == StubMsg.Buffer, "NdrGetBuffer should have returned the same value as StubMsg.Buffer instead of %p\n", ret); + ok(RpcMessage.Handle != NULL, "RpcMessage.Handle should not have been NULL\n"); + ok(RpcMessage.Buffer != NULL, "RpcMessage.Buffer should not have been NULL\n"); + ok(RpcMessage.BufferLength == 10, "RpcMessage.BufferLength should have been 10 instead of %d\n", RpcMessage.BufferLength); + ok(RpcMessage.RpcFlags == 0, "RpcMessage.RpcFlags should have been 0x0 instead of 0x%lx\n", RpcMessage.RpcFlags); + ok(StubMsg.Buffer != NULL, "Buffer should not have been NULL\n"); + ok(!StubMsg.BufferStart, "BufferStart should have been NULL instead of %p\n", StubMsg.BufferStart); + ok(!StubMsg.BufferEnd, "BufferEnd should have been NULL instead of %p\n", StubMsg.BufferEnd); +todo_wine + ok(StubMsg.BufferLength == 0, "BufferLength should have left as 0 instead of being set to %d\n", StubMsg.BufferLength); + ok(StubMsg.fBufferValid == TRUE, "fBufferValid should have been TRUE instead of 0x%x\n", StubMsg.fBufferValid); + + StubMsg.BufferLength = 1; + NdrFreeBuffer(&StubMsg); + ok(RpcMessage.Handle != NULL, "RpcMessage.Handle should not have been NULL\n"); + ok(RpcMessage.Buffer != NULL, "RpcMessage.Buffer should not have been NULL\n"); + ok(RpcMessage.BufferLength == 10, "RpcMessage.BufferLength should have been left as 10 instead of %d\n", RpcMessage.BufferLength); + ok(StubMsg.Buffer != NULL, "Buffer should not have been NULL\n"); + ok(StubMsg.BufferLength == 1, "BufferLength should have left as 1 instead of being set to %d\n", StubMsg.BufferLength); + ok(StubMsg.fBufferValid == FALSE, "fBufferValid should have been FALSE instead of 0x%x\n", StubMsg.fBufferValid); + + /* attempt double-free */ + NdrFreeBuffer(&StubMsg); + + RpcBindingFree(&Handle); + + status = RpcServerUnregisterIf(NULL, NULL, FALSE); + ok(status == RPC_S_OK, "RpcServerUnregisterIf failed (%lu)\n", status); +} + +static void test_NdrMapCommAndFaultStatus(void) +{ + RPC_STATUS rpc_status; + MIDL_STUB_MESSAGE StubMsg; + RPC_MESSAGE RpcMessage; + + NdrClientInitializeNew(&RpcMessage, &StubMsg, &Object_StubDesc, 5); + + for (rpc_status = 0; rpc_status < 10000; rpc_status++) + { + RPC_STATUS status; + ULONG comm_status = 0; + ULONG fault_status = 0; + ULONG expected_comm_status = 0; + ULONG expected_fault_status = 0; + status = NdrMapCommAndFaultStatus(&StubMsg, &comm_status, &fault_status, rpc_status); + ok(status == RPC_S_OK, "NdrMapCommAndFaultStatus failed with error %ld\n", status); + switch (rpc_status) + { + case ERROR_INVALID_HANDLE: + case RPC_S_INVALID_BINDING: + case RPC_S_UNKNOWN_IF: + case RPC_S_SERVER_UNAVAILABLE: + case RPC_S_SERVER_TOO_BUSY: + case RPC_S_CALL_FAILED_DNE: + case RPC_S_PROTOCOL_ERROR: + case RPC_S_UNSUPPORTED_TRANS_SYN: + case RPC_S_UNSUPPORTED_TYPE: + case RPC_S_PROCNUM_OUT_OF_RANGE: + case EPT_S_NOT_REGISTERED: + case RPC_S_COMM_FAILURE: + expected_comm_status = rpc_status; + break; + default: + expected_fault_status = rpc_status; + } + ok(comm_status == expected_comm_status, "NdrMapCommAndFaultStatus should have mapped %ld to comm status %d instead of %d\n", + rpc_status, expected_comm_status, comm_status); + ok(fault_status == expected_fault_status, "NdrMapCommAndFaultStatus should have mapped %ld to fault status %d instead of %d\n", + rpc_status, expected_fault_status, fault_status); + } +} + START_TEST( ndr_marshall ) { test_ndr_simple_type(); test_simple_types(); + test_nontrivial_pointer_types(); test_simple_struct(); test_fullpointer_xlat(); test_client_init(); @@ -1521,4 +1827,6 @@ START_TEST( ndr_marshall ) test_conformant_array(); test_conformant_string(); test_nonconformant_string(); + test_ndr_buffer(); + test_NdrMapCommAndFaultStatus(); } diff --git a/rostests/winetests/rpcrt4/rpc.c b/rostests/winetests/rpcrt4/rpc.c index a72037012be..4197707d7d4 100644 --- a/rostests/winetests/rpcrt4/rpc.c +++ b/rostests/winetests/rpcrt4/rpc.c @@ -21,11 +21,14 @@ #include #include +#include +#define WIN32_NO_STATUS #include "wine/test.h" #include #include #include #include +#include #include "rpc.h" #include "rpcdce.h" @@ -110,6 +113,7 @@ static void UuidConversionAndComparison(void) { ok( (UuidFromStringA((unsigned char*)str, &Uuid1) == RPC_S_INVALID_STRING_UUID), "Invalid UUID String\n" ); str[i2] = x; /* change it back so remaining tests are interesting. */ } + RpcStringFree((unsigned char **)&str); } /* Uuid to String to Uuid (wchar) */ @@ -130,6 +134,7 @@ static void UuidConversionAndComparison(void) { ok( (UuidFromStringW(wstr, &Uuid1) == RPC_S_INVALID_STRING_UUID), "Invalid UUID WString\n" ); wstr[i2] = wx; /* change it back so remaining tests are interesting. */ } + RpcStringFreeW(&wstr); } } @@ -321,6 +326,12 @@ static void test_towers(void) ret = TowerConstruct(&mapi_if_id, &ndr_syntax, "ncacn_ip_tcp", "135", "10.0.0.1", &tower); ok(ret == RPC_S_OK, "TowerConstruct failed with error %ld\n", ret); + if (ret == RPC_S_INVALID_RPC_PROTSEQ) + { + /* Windows Vista fails with this error and crashes if we continue */ + skip("TowerConstruct failed, we are most likely on Windows Vista\n"); + return; + } /* first check we have the right amount of data */ ok(tower->tower_length == sizeof(tower_data_tcp_ip1) || @@ -372,6 +383,272 @@ static void test_towers(void) I_RpcFree(address); I_RpcFree(tower); + + /* test the behaviour for np with no address */ + ret = TowerConstruct(&mapi_if_id, &ndr_syntax, "ncacn_np", "\\pipe\\test", NULL, &tower); + ok(ret == RPC_S_OK, "TowerConstruct failed with error %ld\n", ret); + ret = TowerExplode(tower, NULL, NULL, NULL, NULL, &address); + ok(ret == RPC_S_OK, "TowerExplode failed with error %ld\n", ret); + /* Windows XP SP3 sets address to NULL */ + ok(!address || !strcmp(address, ""), "address was \"%s\" instead of \"\"\n or NULL (XP SP3)", address); + + I_RpcFree(address); + I_RpcFree(tower); +} + +static void test_I_RpcMapWin32Status(void) +{ + LONG win32status; + RPC_STATUS rpc_status; + BOOL w2k3_up = FALSE; + + /* Windows 2003 and Vista return STATUS_UNSUCCESSFUL if given an unknown status */ + win32status = I_RpcMapWin32Status(9999); + if (win32status == STATUS_UNSUCCESSFUL) + { + trace("We are on Windows 2003 or Vista\n"); + w2k3_up = TRUE; + } + + for (rpc_status = 0; rpc_status < 10000; rpc_status++) + { + LONG expected_win32status; + win32status = I_RpcMapWin32Status(rpc_status); + switch (rpc_status) + { + case ERROR_SUCCESS: expected_win32status = ERROR_SUCCESS; break; + case ERROR_ACCESS_DENIED: expected_win32status = STATUS_ACCESS_DENIED; break; + case ERROR_INVALID_HANDLE: expected_win32status = RPC_NT_SS_CONTEXT_MISMATCH; break; + case ERROR_OUTOFMEMORY: expected_win32status = STATUS_NO_MEMORY; break; + case ERROR_INVALID_PARAMETER: expected_win32status = STATUS_INVALID_PARAMETER; break; + case ERROR_INSUFFICIENT_BUFFER: expected_win32status = STATUS_BUFFER_TOO_SMALL; break; + case ERROR_MAX_THRDS_REACHED: expected_win32status = STATUS_NO_MEMORY; break; + case ERROR_NOACCESS: expected_win32status = STATUS_ACCESS_VIOLATION; break; + case ERROR_NOT_ENOUGH_SERVER_MEMORY: expected_win32status = STATUS_INSUFF_SERVER_RESOURCES; break; + case ERROR_WRONG_PASSWORD: expected_win32status = STATUS_WRONG_PASSWORD; break; + case ERROR_INVALID_LOGON_HOURS: expected_win32status = STATUS_INVALID_LOGON_HOURS; break; + case ERROR_PASSWORD_EXPIRED: expected_win32status = STATUS_PASSWORD_EXPIRED; break; + case ERROR_ACCOUNT_DISABLED: expected_win32status = STATUS_ACCOUNT_DISABLED; break; + case ERROR_INVALID_SECURITY_DESCR: expected_win32status = STATUS_INVALID_SECURITY_DESCR; break; + case RPC_S_INVALID_STRING_BINDING: expected_win32status = RPC_NT_INVALID_STRING_BINDING; break; + case RPC_S_WRONG_KIND_OF_BINDING: expected_win32status = RPC_NT_WRONG_KIND_OF_BINDING; break; + case RPC_S_INVALID_BINDING: expected_win32status = RPC_NT_INVALID_BINDING; break; + case RPC_S_PROTSEQ_NOT_SUPPORTED: expected_win32status = RPC_NT_PROTSEQ_NOT_SUPPORTED; break; + case RPC_S_INVALID_RPC_PROTSEQ: expected_win32status = RPC_NT_INVALID_RPC_PROTSEQ; break; + case RPC_S_INVALID_STRING_UUID: expected_win32status = RPC_NT_INVALID_STRING_UUID; break; + case RPC_S_INVALID_ENDPOINT_FORMAT: expected_win32status = RPC_NT_INVALID_ENDPOINT_FORMAT; break; + case RPC_S_INVALID_NET_ADDR: expected_win32status = RPC_NT_INVALID_NET_ADDR; break; + case RPC_S_NO_ENDPOINT_FOUND: expected_win32status = RPC_NT_NO_ENDPOINT_FOUND; break; + case RPC_S_INVALID_TIMEOUT: expected_win32status = RPC_NT_INVALID_TIMEOUT; break; + case RPC_S_OBJECT_NOT_FOUND: expected_win32status = RPC_NT_OBJECT_NOT_FOUND; break; + case RPC_S_ALREADY_REGISTERED: expected_win32status = RPC_NT_ALREADY_REGISTERED; break; + case RPC_S_TYPE_ALREADY_REGISTERED: expected_win32status = RPC_NT_TYPE_ALREADY_REGISTERED; break; + case RPC_S_ALREADY_LISTENING: expected_win32status = RPC_NT_ALREADY_LISTENING; break; + case RPC_S_NO_PROTSEQS_REGISTERED: expected_win32status = RPC_NT_NO_PROTSEQS_REGISTERED; break; + case RPC_S_NOT_LISTENING: expected_win32status = RPC_NT_NOT_LISTENING; break; + case RPC_S_UNKNOWN_MGR_TYPE: expected_win32status = RPC_NT_UNKNOWN_MGR_TYPE; break; + case RPC_S_UNKNOWN_IF: expected_win32status = RPC_NT_UNKNOWN_IF; break; + case RPC_S_NO_BINDINGS: expected_win32status = RPC_NT_NO_BINDINGS; break; + case RPC_S_NO_PROTSEQS: expected_win32status = RPC_NT_NO_PROTSEQS; break; + case RPC_S_CANT_CREATE_ENDPOINT: expected_win32status = RPC_NT_CANT_CREATE_ENDPOINT; break; + case RPC_S_OUT_OF_RESOURCES: expected_win32status = RPC_NT_OUT_OF_RESOURCES; break; + case RPC_S_SERVER_UNAVAILABLE: expected_win32status = RPC_NT_SERVER_UNAVAILABLE; break; + case RPC_S_SERVER_TOO_BUSY: expected_win32status = RPC_NT_SERVER_TOO_BUSY; break; + case RPC_S_INVALID_NETWORK_OPTIONS: expected_win32status = RPC_NT_INVALID_NETWORK_OPTIONS; break; + case RPC_S_NO_CALL_ACTIVE: expected_win32status = RPC_NT_NO_CALL_ACTIVE; break; + case RPC_S_CALL_FAILED: expected_win32status = RPC_NT_CALL_FAILED; break; + case RPC_S_CALL_FAILED_DNE: expected_win32status = RPC_NT_CALL_FAILED_DNE; break; + case RPC_S_PROTOCOL_ERROR: expected_win32status = RPC_NT_PROTOCOL_ERROR; break; + case RPC_S_UNSUPPORTED_TRANS_SYN: expected_win32status = RPC_NT_UNSUPPORTED_TRANS_SYN; break; + case RPC_S_UNSUPPORTED_TYPE: expected_win32status = RPC_NT_UNSUPPORTED_TYPE; break; + case RPC_S_INVALID_TAG: expected_win32status = RPC_NT_INVALID_TAG; break; + case RPC_S_INVALID_BOUND: expected_win32status = RPC_NT_INVALID_BOUND; break; + case RPC_S_NO_ENTRY_NAME: expected_win32status = RPC_NT_NO_ENTRY_NAME; break; + case RPC_S_INVALID_NAME_SYNTAX: expected_win32status = RPC_NT_INVALID_NAME_SYNTAX; break; + case RPC_S_UNSUPPORTED_NAME_SYNTAX: expected_win32status = RPC_NT_UNSUPPORTED_NAME_SYNTAX; break; + case RPC_S_UUID_NO_ADDRESS: expected_win32status = RPC_NT_UUID_NO_ADDRESS; break; + case RPC_S_DUPLICATE_ENDPOINT: expected_win32status = RPC_NT_DUPLICATE_ENDPOINT; break; + case RPC_S_UNKNOWN_AUTHN_TYPE: expected_win32status = RPC_NT_UNKNOWN_AUTHN_TYPE; break; + case RPC_S_MAX_CALLS_TOO_SMALL: expected_win32status = RPC_NT_MAX_CALLS_TOO_SMALL; break; + case RPC_S_STRING_TOO_LONG: expected_win32status = RPC_NT_STRING_TOO_LONG; break; + case RPC_S_PROTSEQ_NOT_FOUND: expected_win32status = RPC_NT_PROTSEQ_NOT_FOUND; break; + case RPC_S_PROCNUM_OUT_OF_RANGE: expected_win32status = RPC_NT_PROCNUM_OUT_OF_RANGE; break; + case RPC_S_BINDING_HAS_NO_AUTH: expected_win32status = RPC_NT_BINDING_HAS_NO_AUTH; break; + case RPC_S_UNKNOWN_AUTHN_SERVICE: expected_win32status = RPC_NT_UNKNOWN_AUTHN_SERVICE; break; + case RPC_S_UNKNOWN_AUTHN_LEVEL: expected_win32status = RPC_NT_UNKNOWN_AUTHN_LEVEL; break; + case RPC_S_INVALID_AUTH_IDENTITY: expected_win32status = RPC_NT_INVALID_AUTH_IDENTITY; break; + case RPC_S_UNKNOWN_AUTHZ_SERVICE: expected_win32status = RPC_NT_UNKNOWN_AUTHZ_SERVICE; break; + case EPT_S_INVALID_ENTRY: expected_win32status = EPT_NT_INVALID_ENTRY; break; + case EPT_S_CANT_PERFORM_OP: expected_win32status = EPT_NT_CANT_PERFORM_OP; break; + case EPT_S_NOT_REGISTERED: expected_win32status = EPT_NT_NOT_REGISTERED; break; + case EPT_S_CANT_CREATE: expected_win32status = EPT_NT_CANT_CREATE; break; + case RPC_S_NOTHING_TO_EXPORT: expected_win32status = RPC_NT_NOTHING_TO_EXPORT; break; + case RPC_S_INCOMPLETE_NAME: expected_win32status = RPC_NT_INCOMPLETE_NAME; break; + case RPC_S_INVALID_VERS_OPTION: expected_win32status = RPC_NT_INVALID_VERS_OPTION; break; + case RPC_S_NO_MORE_MEMBERS: expected_win32status = RPC_NT_NO_MORE_MEMBERS; break; + case RPC_S_NOT_ALL_OBJS_UNEXPORTED: expected_win32status = RPC_NT_NOT_ALL_OBJS_UNEXPORTED; break; + case RPC_S_INTERFACE_NOT_FOUND: expected_win32status = RPC_NT_INTERFACE_NOT_FOUND; break; + case RPC_S_ENTRY_ALREADY_EXISTS: expected_win32status = RPC_NT_ENTRY_ALREADY_EXISTS; break; + case RPC_S_ENTRY_NOT_FOUND: expected_win32status = RPC_NT_ENTRY_NOT_FOUND; break; + case RPC_S_NAME_SERVICE_UNAVAILABLE: expected_win32status = RPC_NT_NAME_SERVICE_UNAVAILABLE; break; + case RPC_S_INVALID_NAF_ID: expected_win32status = RPC_NT_INVALID_NAF_ID; break; + case RPC_S_CANNOT_SUPPORT: expected_win32status = RPC_NT_CANNOT_SUPPORT; break; + case RPC_S_NO_CONTEXT_AVAILABLE: expected_win32status = RPC_NT_NO_CONTEXT_AVAILABLE; break; + case RPC_S_INTERNAL_ERROR: expected_win32status = RPC_NT_INTERNAL_ERROR; break; + case RPC_S_ZERO_DIVIDE: expected_win32status = RPC_NT_ZERO_DIVIDE; break; + case RPC_S_ADDRESS_ERROR: expected_win32status = RPC_NT_ADDRESS_ERROR; break; + case RPC_S_FP_DIV_ZERO: expected_win32status = RPC_NT_FP_DIV_ZERO; break; + case RPC_S_FP_UNDERFLOW: expected_win32status = RPC_NT_FP_UNDERFLOW; break; + case RPC_S_FP_OVERFLOW: expected_win32status = RPC_NT_FP_OVERFLOW; break; + case RPC_S_CALL_IN_PROGRESS: expected_win32status = RPC_NT_CALL_IN_PROGRESS; break; + case RPC_S_NO_MORE_BINDINGS: expected_win32status = RPC_NT_NO_MORE_BINDINGS; break; + case RPC_S_CALL_CANCELLED: expected_win32status = RPC_NT_CALL_CANCELLED; break; + case RPC_S_INVALID_OBJECT: expected_win32status = RPC_NT_INVALID_OBJECT; break; + case RPC_S_INVALID_ASYNC_HANDLE: expected_win32status = RPC_NT_INVALID_ASYNC_HANDLE; break; + case RPC_S_INVALID_ASYNC_CALL: expected_win32status = RPC_NT_INVALID_ASYNC_CALL; break; + case RPC_S_GROUP_MEMBER_NOT_FOUND: expected_win32status = RPC_NT_GROUP_MEMBER_NOT_FOUND; break; + case RPC_X_NO_MORE_ENTRIES: expected_win32status = RPC_NT_NO_MORE_ENTRIES; break; + case RPC_X_SS_CHAR_TRANS_OPEN_FAIL: expected_win32status = RPC_NT_SS_CHAR_TRANS_OPEN_FAIL; break; + case RPC_X_SS_CHAR_TRANS_SHORT_FILE: expected_win32status = RPC_NT_SS_CHAR_TRANS_SHORT_FILE; break; + case RPC_X_SS_IN_NULL_CONTEXT: expected_win32status = RPC_NT_SS_IN_NULL_CONTEXT; break; + case RPC_X_SS_CONTEXT_DAMAGED: expected_win32status = RPC_NT_SS_CONTEXT_DAMAGED; break; + case RPC_X_SS_HANDLES_MISMATCH: expected_win32status = RPC_NT_SS_HANDLES_MISMATCH; break; + case RPC_X_SS_CANNOT_GET_CALL_HANDLE: expected_win32status = RPC_NT_SS_CANNOT_GET_CALL_HANDLE; break; + case RPC_X_NULL_REF_POINTER: expected_win32status = RPC_NT_NULL_REF_POINTER; break; + case RPC_X_ENUM_VALUE_OUT_OF_RANGE: expected_win32status = RPC_NT_ENUM_VALUE_OUT_OF_RANGE; break; + case RPC_X_BYTE_COUNT_TOO_SMALL: expected_win32status = RPC_NT_BYTE_COUNT_TOO_SMALL; break; + case RPC_X_BAD_STUB_DATA: expected_win32status = RPC_NT_BAD_STUB_DATA; break; + case RPC_X_PIPE_CLOSED: expected_win32status = RPC_NT_PIPE_CLOSED; break; + case RPC_X_PIPE_DISCIPLINE_ERROR: expected_win32status = RPC_NT_PIPE_DISCIPLINE_ERROR; break; + case RPC_X_PIPE_EMPTY: expected_win32status = RPC_NT_PIPE_EMPTY; break; + case ERROR_PASSWORD_MUST_CHANGE: expected_win32status = STATUS_PASSWORD_MUST_CHANGE; break; + case ERROR_ACCOUNT_LOCKED_OUT: expected_win32status = STATUS_ACCOUNT_LOCKED_OUT; break; + default: + if (w2k3_up) + expected_win32status = STATUS_UNSUCCESSFUL; + else + expected_win32status = rpc_status; + } + ok(win32status == expected_win32status, "I_RpcMapWin32Status(%ld) should have returned 0x%x instead of 0x%x\n", + rpc_status, expected_win32status, win32status); + } +} + +static void test_RpcStringBindingParseA(void) +{ + static unsigned char valid_binding[] = "00000000-0000-0000-c000-000000000046@ncacn_np:.[endpoint=\\pipe\\test]"; + static unsigned char valid_binding2[] = "00000000-0000-0000-c000-000000000046@ncacn_np:.[\\pipe\\test]"; + static unsigned char invalid_uuid_binding[] = "{00000000-0000-0000-c000-000000000046}@ncacn_np:.[endpoint=\\pipe\\test]"; + static unsigned char invalid_ep_binding[] = "00000000-0000-0000-c000-000000000046@ncacn_np:.[endpoint=test]"; + static unsigned char invalid_binding[] = "00000000-0000-0000-c000-000000000046@ncacn_np"; + RPC_STATUS status; + unsigned char *uuid; + unsigned char *protseq; + unsigned char *network_addr; + unsigned char *endpoint; + unsigned char *options; + + /* test all parameters */ + status = RpcStringBindingParseA(valid_binding, &uuid, &protseq, &network_addr, &endpoint, &options); + ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %ld\n", status); + ok(!strcmp((char *)uuid, "00000000-0000-0000-c000-000000000046"), "uuid should have been 00000000-0000-0000-C000-000000000046 instead of %s\n", uuid); + ok(!strcmp((char *)protseq, "ncacn_np"), "protseq should have been ncacn_np instead of %s\n", protseq); + ok(!strcmp((char *)network_addr, "."), "network_addr should have been . instead of %s\n", network_addr); + todo_wine + ok(!strcmp((char *)endpoint, "pipetest"), "endpoint should have been pipetest instead of %s\n", endpoint); + todo_wine + ok(options && !strcmp((char *)options, ""), "options should have been \"\" of \"%s\"\n", options); + RpcStringFreeA(&uuid); + RpcStringFreeA(&protseq); + RpcStringFreeA(&network_addr); + RpcStringFreeA(&endpoint); + RpcStringFreeA(&options); + + /* test all parameters with different type of string binding */ + status = RpcStringBindingParseA(valid_binding2, &uuid, &protseq, &network_addr, &endpoint, &options); + ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %ld\n", status); + ok(!strcmp((char *)uuid, "00000000-0000-0000-c000-000000000046"), "uuid should have been 00000000-0000-0000-C000-000000000046 instead of %s\n", uuid); + ok(!strcmp((char *)protseq, "ncacn_np"), "protseq should have been ncacn_np instead of %s\n", protseq); + ok(!strcmp((char *)network_addr, "."), "network_addr should have been . instead of %s\n", network_addr); + todo_wine + ok(!strcmp((char *)endpoint, "pipetest"), "endpoint should have been pipetest instead of %s\n", endpoint); + todo_wine + ok(options && !strcmp((char *)options, ""), "options should have been \"\" of \"%s\"\n", options); + RpcStringFreeA(&uuid); + RpcStringFreeA(&protseq); + RpcStringFreeA(&network_addr); + RpcStringFreeA(&endpoint); + RpcStringFreeA(&options); + + /* test with as many parameters NULL as possible */ + status = RpcStringBindingParseA(valid_binding, NULL, &protseq, NULL, NULL, NULL); + ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %ld\n", status); + ok(!strcmp((char *)protseq, "ncacn_np"), "protseq should have been ncacn_np instead of %s\n", protseq); + RpcStringFreeA(&protseq); + + /* test with invalid uuid */ + status = RpcStringBindingParseA(invalid_uuid_binding, NULL, &protseq, NULL, NULL, NULL); + todo_wine + ok(status == RPC_S_INVALID_STRING_UUID, "RpcStringBindingParseA should have returned RPC_S_INVALID_STRING_UUID instead of %ld\n", status); + todo_wine + ok(protseq == NULL, "protseq was %p instead of NULL\n", protseq); + + /* test with invalid endpoint */ + status = RpcStringBindingParseA(invalid_ep_binding, NULL, &protseq, NULL, NULL, NULL); + ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %ld\n", status); + RpcStringFreeA(&protseq); + + /* test with invalid binding */ + status = RpcStringBindingParseA(invalid_binding, &uuid, &protseq, &network_addr, &endpoint, &options); + todo_wine + ok(status == RPC_S_INVALID_STRING_BINDING, "RpcStringBindingParseA should have returned RPC_S_INVALID_STRING_BINDING instead of %ld\n", status); + todo_wine + ok(uuid == NULL, "uuid was %p instead of NULL\n", uuid); + ok(protseq == NULL, "protseq was %p instead of NULL\n", protseq); + todo_wine + ok(network_addr == NULL, "network_addr was %p instead of NULL\n", network_addr); + ok(endpoint == NULL, "endpoint was %p instead of NULL\n", endpoint); + ok(options == NULL, "options was %p instead of NULL\n", options); +} + +static void test_I_RpcExceptionFilter(void) +{ + ULONG exception; + int retval; + int (WINAPI *pI_RpcExceptionFilter)(ULONG) = (void *)GetProcAddress(GetModuleHandle("rpcrt4.dll"), "I_RpcExceptionFilter"); + + if (!pI_RpcExceptionFilter) + { + skip("I_RpcExceptionFilter not exported\n"); + return; + } + + for (exception = 0; exception < STATUS_REG_NAT_CONSUMPTION; exception++) + { + /* skip over uninteresting bits of the number space */ + if (exception == 2000) exception = 0x40000000; + if (exception == 0x40000005) exception = 0x80000000; + if (exception == 0x80000005) exception = 0xc0000000; + + retval = pI_RpcExceptionFilter(exception); + switch (exception) + { + case STATUS_DATATYPE_MISALIGNMENT: + case STATUS_BREAKPOINT: + case STATUS_ACCESS_VIOLATION: + case STATUS_ILLEGAL_INSTRUCTION: + case STATUS_PRIVILEGED_INSTRUCTION: + case 0xc00000aa /* STATUS_INSTRUCTION_MISALIGNMENT */: + case STATUS_STACK_OVERFLOW: + case 0xc0000194 /* STATUS_POSSIBLE_DEADLOCK */: + ok(retval == EXCEPTION_CONTINUE_SEARCH, "I_RpcExceptionFilter(0x%x) should have returned %d instead of %d\n", + exception, EXCEPTION_CONTINUE_SEARCH, retval); + break; + default: + ok(retval == EXCEPTION_EXECUTE_HANDLER, "I_RpcExceptionFilter(0x%x) should have returned %d instead of %d\n", + exception, EXCEPTION_EXECUTE_HANDLER, retval); + } + } } START_TEST( rpc ) @@ -382,4 +659,7 @@ START_TEST( rpc ) TestDceErrorInqText(); test_rpc_ncacn_ip_tcp(); test_towers(); + test_I_RpcMapWin32Status(); + test_RpcStringBindingParseA(); + test_I_RpcExceptionFilter(); } diff --git a/rostests/winetests/rpcrt4/rpc_async.c b/rostests/winetests/rpcrt4/rpc_async.c new file mode 100644 index 00000000000..0cc5557ce06 --- /dev/null +++ b/rostests/winetests/rpcrt4/rpc_async.c @@ -0,0 +1,91 @@ +/* + * Unit test suite for rpc functions + * + * Copyright 2008 Robert Shearman (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "wine/test.h" + +#include +#include + +RPC_STATUS (RPC_ENTRY *pRpcAsyncInitializeHandle)(PRPC_ASYNC_STATE,unsigned int); +RPC_STATUS (RPC_ENTRY *pRpcAsyncGetCallStatus)(PRPC_ASYNC_STATE); + +static void test_RpcAsyncInitializeHandle(void) +{ + char buffer[256]; + RPC_ASYNC_STATE async; + RPC_STATUS status; + int i; + + status = pRpcAsyncInitializeHandle((PRPC_ASYNC_STATE)buffer, sizeof(buffer)); + ok(status == ERROR_INVALID_PARAMETER, "RpcAsyncInitializeHandle with large Size should have returned ERROR_INVALID_PARAMETER instead of %ld\n", status); + + status = pRpcAsyncInitializeHandle(&async, sizeof(async) - 1); + ok(status == ERROR_INVALID_PARAMETER, "RpcAsyncInitializeHandle with small Size should have returned ERROR_INVALID_PARAMETER instead of %ld\n", status); + + memset(&async, 0xcc, sizeof(async)); + status = pRpcAsyncInitializeHandle(&async, sizeof(async)); + ok(status == RPC_S_OK, "RpcAsyncInitializeHandle failed with error %ld\n", status); + + ok(async.Size == sizeof(async), "async.Size wrong: %d\n", async.Size); + ok(async.Signature == 0x43595341, "async.Signature should be 0x43595341, but is 0x%x instead\n", async.Signature); + ok(async.Lock == 0, "async.Lock should be 0, but is %d instead\n", async.Lock); + ok(async.Flags == 0, "async.Flags should be 0, but is %d instead\n", async.Flags); + ok(async.StubInfo == NULL, "async.StubInfo should be NULL, not %p\n", async.StubInfo); + ok(async.UserInfo == (void *)0xcccccccc, "async.UserInfo should be unset, not %p\n", async.UserInfo); + ok(async.RuntimeInfo == NULL, "async.RuntimeInfo should be NULL, not %p\n", async.RuntimeInfo); + ok(async.Event == 0xcccccccc, "async.Event should be unset, not %d\n", async.Event); + ok(async.NotificationType == 0xcccccccc, "async.NotificationType should be unset, not %d\n", async.NotificationType); + for (i = 0; i < 4; i++) + ok(async.Reserved[i] == 0x0, "async.Reserved[%d] should be 0x0, not 0x%lx\n", i, async.Reserved[i]); +} + +static void test_RpcAsyncGetCallStatus(void) +{ + RPC_ASYNC_STATE async; + RPC_STATUS status; + + status = pRpcAsyncInitializeHandle(&async, sizeof(async)); + ok(status == RPC_S_OK, "RpcAsyncInitializeHandle failed with error %ld\n", status); + + status = pRpcAsyncGetCallStatus(&async); + todo_wine + ok(status == RPC_S_INVALID_BINDING, "RpcAsyncGetCallStatus should have returned RPC_S_INVALID_BINDING instead of %ld\n", status); + + memset(&async, 0, sizeof(async)); + status = pRpcAsyncGetCallStatus(&async); + todo_wine + ok(status == RPC_S_INVALID_BINDING, "RpcAsyncGetCallStatus should have returned RPC_S_INVALID_BINDING instead of %ld\n", status); +} + +START_TEST( rpc_async ) +{ + HMODULE hRpcRt4 = GetModuleHandle("rpcrt4.dll"); + pRpcAsyncInitializeHandle = (void *)GetProcAddress(hRpcRt4, "RpcAsyncInitializeHandle"); + pRpcAsyncGetCallStatus = (void *)GetProcAddress(hRpcRt4, "RpcAsyncGetCallStatus"); + if (!pRpcAsyncInitializeHandle || !pRpcAsyncGetCallStatus) + { + skip("asynchronous functions not available\n"); + return; + } + test_RpcAsyncInitializeHandle(); + test_RpcAsyncGetCallStatus(); +} diff --git a/rostests/winetests/rpcrt4/rpcrt4.rbuild b/rostests/winetests/rpcrt4/rpcrt4.rbuild index d1badbcda0d..5e8209495e0 100644 --- a/rostests/winetests/rpcrt4/rpcrt4.rbuild +++ b/rostests/winetests/rpcrt4/rpcrt4.rbuild @@ -21,6 +21,7 @@ generated.c ndr_marshall.c rpc.c + rpc_async.c server.c testlist.c - \ No newline at end of file + diff --git a/rostests/winetests/rpcrt4/server.c b/rostests/winetests/rpcrt4/server.c index 7f255189fe3..eb1baacd6c5 100644 --- a/rostests/winetests/rpcrt4/server.c +++ b/rostests/winetests/rpcrt4/server.c @@ -36,6 +36,17 @@ static const char *progname; static HANDLE stop_event; +static void (WINAPI *pNDRSContextMarshall2)(RPC_BINDING_HANDLE, NDR_SCONTEXT, void*, NDR_RUNDOWN, void*, ULONG); +static NDR_SCONTEXT (WINAPI *pNDRSContextUnmarshall2)(RPC_BINDING_HANDLE, void*, ULONG, void*, ULONG); + +static void InitFunctionPointers(void) +{ + HMODULE hrpcrt4 = GetModuleHandleA("rpcrt4.dll"); + + pNDRSContextMarshall2 = (void *)GetProcAddress(hrpcrt4, "NDRSContextMarshall2"); + pNDRSContextUnmarshall2 = (void *)GetProcAddress(hrpcrt4, "NDRSContextUnmarshall2"); +} + void __RPC_FAR *__RPC_USER midl_user_allocate(size_t n) { @@ -92,6 +103,12 @@ s_str_length(const char *s) return strlen(s); } +int +s_str_t_length(str_t s) +{ + return strlen(s); +} + int s_cstr_length(const char *s, int n) { @@ -316,10 +333,10 @@ s_square_encu(encu_t *eu) } } -int -s_sum_parr(int *a[3]) +void +s_check_se2(se_t *s) { - return s_sum_pcarr(a, 3); + ok(s->f == E2, "check_se2\n"); } int @@ -331,6 +348,12 @@ s_sum_pcarr(int *a[], int n) return s; } +int +s_sum_parr(int *a[3]) +{ + return s_sum_pcarr(a, 3); +} + int s_enum_ord(e_t e) { @@ -497,6 +520,16 @@ s_sum_L1_norms(int n, vector_t *vs) return sum; } +s123_t * +s_get_s123(void) +{ + s123_t *s = MIDL_user_allocate(sizeof *s); + s->f1 = 1; + s->f2 = 2; + s->f3 = 3; + return s; +} + str_t s_get_filename(void) { @@ -526,40 +559,40 @@ s_context_handle_test(void) binding = I_RpcGetCurrentCallHandle(); ok(binding != NULL, "I_RpcGetCurrentCallHandle returned NULL\n"); - h = NDRSContextUnmarshall2(binding, NULL, NDR_LOCAL_DATA_REPRESENTATION, NULL, 0); + h = pNDRSContextUnmarshall2(binding, NULL, NDR_LOCAL_DATA_REPRESENTATION, NULL, 0); ok(h != NULL, "NDRSContextUnmarshall2 returned NULL\n"); /* marshal a context handle with NULL userContext */ memset(buf, 0xcc, sizeof(buf)); - NDRSContextMarshall2(binding, h, buf, NULL, NULL, 0); + pNDRSContextMarshall2(binding, h, buf, NULL, NULL, 0); ok(*(ULONG *)buf == 0, "attributes should have been set to 0 instead of 0x%x\n", *(ULONG *)buf); ok(UuidIsNil((UUID *)&buf[4], &status), "uuid should have been nil\n"); - h = NDRSContextUnmarshall2(binding, NULL, NDR_LOCAL_DATA_REPRESENTATION, NULL, 0); + h = pNDRSContextUnmarshall2(binding, NULL, NDR_LOCAL_DATA_REPRESENTATION, NULL, 0); ok(h != NULL, "NDRSContextUnmarshall2 returned NULL\n"); /* marshal a context handle with non-NULL userContext */ memset(buf, 0xcc, sizeof(buf)); h->userContext = (void *)0xdeadbeef; - NDRSContextMarshall2(binding, h, buf, NULL, NULL, 0); + pNDRSContextMarshall2(binding, h, buf, NULL, NULL, 0); ok(*(ULONG *)buf == 0, "attributes should have been set to 0 instead of 0x%x\n", *(ULONG *)buf); ok(!UuidIsNil((UUID *)&buf[4], &status), "uuid should not have been nil\n"); - h = NDRSContextUnmarshall2(binding, buf, NDR_LOCAL_DATA_REPRESENTATION, NULL, 0); + h = pNDRSContextUnmarshall2(binding, buf, NDR_LOCAL_DATA_REPRESENTATION, NULL, 0); ok(h != NULL, "NDRSContextUnmarshall2 returned NULL\n"); ok(h->userContext == (void *)0xdeadbeef, "userContext of interface didn't unmarshal properly: %p\n", h->userContext); /* marshal a context handle with an interface specified */ - h = NDRSContextUnmarshall2(binding, NULL, NDR_LOCAL_DATA_REPRESENTATION, &server_if.InterfaceId, 0); + h = pNDRSContextUnmarshall2(binding, NULL, NDR_LOCAL_DATA_REPRESENTATION, &server_if.InterfaceId, 0); ok(h != NULL, "NDRSContextUnmarshall2 returned NULL\n"); memset(buf, 0xcc, sizeof(buf)); h->userContext = (void *)0xcafebabe; - NDRSContextMarshall2(binding, h, buf, NULL, &server_if.InterfaceId, 0); + pNDRSContextMarshall2(binding, h, buf, NULL, &server_if.InterfaceId, 0); ok(*(ULONG *)buf == 0, "attributes should have been set to 0 instead of 0x%x\n", *(ULONG *)buf); ok(!UuidIsNil((UUID *)&buf[4], &status), "uuid should not have been nil\n"); - h = NDRSContextUnmarshall2(binding, buf, NDR_LOCAL_DATA_REPRESENTATION, &server_if.InterfaceId, 0); + h = pNDRSContextUnmarshall2(binding, buf, NDR_LOCAL_DATA_REPRESENTATION, &server_if.InterfaceId, 0); ok(h != NULL, "NDRSContextUnmarshall2 returned NULL\n"); ok(h->userContext == (void *)0xcafebabe, "userContext of interface didn't unmarshal properly: %p\n", h->userContext); @@ -569,7 +602,7 @@ s_context_handle_test(void) { RPC_SERVER_INTERFACE server_if_clone = server_if; - NDRSContextUnmarshall2(binding, buf, NDR_LOCAL_DATA_REPRESENTATION, &server_if_clone.InterfaceId, 0); + pNDRSContextUnmarshall2(binding, buf, NDR_LOCAL_DATA_REPRESENTATION, &server_if_clone.InterfaceId, 0); } /* test different interface data, but different pointer */ @@ -588,9 +621,9 @@ s_context_handle_test(void) 0, 0, }; - NDRSContextMarshall2(binding, h, buf, NULL, &server_if.InterfaceId, 0); + pNDRSContextMarshall2(binding, h, buf, NULL, &server_if.InterfaceId, 0); - NDRSContextUnmarshall2(binding, buf, NDR_LOCAL_DATA_REPRESENTATION, &server_if2.InterfaceId, 0); + pNDRSContextUnmarshall2(binding, buf, NDR_LOCAL_DATA_REPRESENTATION, &server_if2.InterfaceId, 0); } } @@ -634,25 +667,21 @@ make_cmdline(char buffer[MAX_PATH], const char *test) sprintf(buffer, "%s server %s", progname, test); } -static int +static void run_client(const char *test) { char cmdline[MAX_PATH]; PROCESS_INFORMATION info; STARTUPINFOA startup; - DWORD exitcode; memset(&startup, 0, sizeof startup); startup.cb = sizeof startup; make_cmdline(cmdline, test); ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - ok(GetExitCodeProcess(info.hProcess, &exitcode), "GetExitCodeProcess\n"); + winetest_wait_child_process( info.hProcess ); ok(CloseHandle(info.hProcess), "CloseHandle\n"); ok(CloseHandle(info.hThread), "CloseHandle\n"); - - return exitcode == 0; } static void @@ -682,6 +711,7 @@ basic_tests(void) str_struct_t ss = {string}; wstr_struct_t ws = {wstring}; str_t str; + se_t se; ok(int_return() == INT_CODE, "RPC int_return\n"); @@ -697,6 +727,7 @@ basic_tests(void) ok(x == 25, "RPC square_ref\n"); ok(str_length(string) == strlen(string), "RPC str_length\n"); + ok(str_t_length(string) == strlen(string), "RPC str_length\n"); ok(dot_self(&a) == 59, "RPC dot_self\n"); ok(str_struct_len(&ss) == lstrlenA(string), "RPC str_struct_len\n"); @@ -750,6 +781,9 @@ basic_tests(void) ok(enum_ord(E3) == 3, "RPC enum_ord\n"); ok(enum_ord(E4) == 4, "RPC enum_ord\n"); + se.f = E2; + check_se2(&se); + memset(&aligns, 0, sizeof(aligns)); aligns.c = 3; aligns.i = 4; @@ -963,6 +997,7 @@ pointer_tests(void) name_t name; void *buffer; int *pa2; + s123_t *s123; ok(test_list_length(list) == 3, "RPC test_list_length\n"); ok(square_puint(p1) == 121, "RPC square_puint\n"); @@ -1016,6 +1051,10 @@ pointer_tests(void) pa2 = a; ok(sum_pcarr2(4, &pa2) == 10, "RPC sum_pcarr2\n"); + + s123 = get_s123(); + ok(s123->f1 == 1 && s123->f2 == 2 && s123->f3 == 3, "RPC get_s123\n"); + MIDL_user_free(s123); } static int @@ -1200,22 +1239,38 @@ server(void) static unsigned char port[] = PORT; static unsigned char np[] = "ncacn_np"; static unsigned char pipe[] = PIPE; + RPC_STATUS status, iptcp_status, np_status; - ok(RPC_S_OK == RpcServerUseProtseqEp(iptcp, 20, port, NULL), "RpcServerUseProtseqEp\n"); - //ok(RPC_S_OK == RpcServerRegisterIf(s_IServer_v0_0_s_ifspec, NULL, NULL), "RpcServerRegisterIf\n"); - ok(RPC_S_OK == RpcServerListen(1, 20, TRUE), "RpcServerListen\n"); + iptcp_status = RpcServerUseProtseqEp(iptcp, 20, port, NULL); + ok(iptcp_status == RPC_S_OK, "RpcServerUseProtseqEp(ncacn_ip_tcp) failed with status %ld\n", iptcp_status); + np_status = RpcServerUseProtseqEp(np, 0, pipe, NULL); + ok(np_status == RPC_S_OK, "RpcServerUseProtseqEp(ncacn_np) failed with status %ld\n", np_status); + //status = RpcServerRegisterIf(s_IServer_v0_0_s_ifspec, NULL, NULL); + //ok(status == RPC_S_OK, "RpcServerRegisterIf failed with status %ld\n", status); + status = RpcServerListen(1, 20, TRUE); + ok(status == RPC_S_OK, "RpcServerListen failed with status %ld\n", status); stop_event = CreateEvent(NULL, FALSE, FALSE, NULL); - ok(stop_event != NULL, "CreateEvent failed\n"); + ok(stop_event != NULL, "CreateEvent failed with error %d\n", GetLastError()); - ok(run_client("tcp_basic"), "tcp_basic client test failed\n"); + if (iptcp_status == RPC_S_OK) + run_client("tcp_basic"); + else + skip("tcp_basic tests skipped due to earlier failure\n"); - ok(RPC_S_OK == RpcServerUseProtseqEp(np, 0, pipe, NULL), "RpcServerUseProtseqEp\n"); - ok(run_client("np_basic"), "np_basic client test failed\n"); + if (np_status == RPC_S_OK) + run_client("np_basic"); + else + { + skip("np_basic tests skipped due to earlier failure\n"); + /* np client is what signals stop_event, so bail out if we didn't run do it */ + return; + } ok(WAIT_OBJECT_0 == WaitForSingleObject(stop_event, 60000), "WaitForSingleObject\n"); + status = RpcMgmtWaitServerListen(); todo_wine { - ok(RPC_S_OK == RpcMgmtWaitServerListen(), "RpcMgmtWaitServerListening\n"); + ok(status == RPC_S_OK, "RpcMgmtWaitServerListening failed with status %ld\n", status); } } @@ -1224,6 +1279,8 @@ START_TEST(server) int argc; char **argv; + InitFunctionPointers(); + argc = winetest_get_mainargs(&argv); progname = argv[0]; diff --git a/rostests/winetests/rpcrt4/server.idl b/rostests/winetests/rpcrt4/server.idl index ec517572dc3..33e3a480a1c 100644 --- a/rostests/winetests/rpcrt4/server.idl +++ b/rostests/winetests/rpcrt4/server.idl @@ -82,6 +82,7 @@ cpp_quote("#endif") void square_out(int x, [out] int *y); void square_ref([in, out] int *x); int str_length([string] const char *s); + int str_t_length(str_t s); int cstr_length([string, size_is(n)] const char *s, int n); int dot_self(vector_t *v); double square_half(double x, [out] double *y); @@ -208,11 +209,17 @@ cpp_quote("#endif") case E2: float f2; } encue_t; + typedef struct + { + e_t f; + } se_t; + double square_encu(encu_t *eu); int sum_parr(int *a[3]); int sum_pcarr([size_is(n)] int *a[], int n); int enum_ord(e_t e); double square_encue(encue_t *eue); + void check_se2(se_t *s); int sum_toplev_conf_2n([size_is(n * 2)] int *x, int n); int sum_toplev_conf_cond([size_is(c ? a : b)] int *x, int a, int b, int c); @@ -300,6 +307,18 @@ cpp_quote("#endif") int sum_pcarr2(int n, [size_is(, n)] int **pa); int sum_L1_norms(int n, [size_is(n)] vector_t *vs); + /* Don't use this except in the get_s123 test. */ + typedef struct + { + int f1; + int f2; + int f3; + } s123_t; + + /* Make sure WIDL generates a type format string for a previously unseen + type as a return value. */ + s123_t *get_s123(void); + void get_5numbers([in] int count, [out, length_is(count)] pints_t pn[5]); void get_numbers([in] int length, [in] int size, [out, length_is(length), size_is(size)] pints_t pn[]); str_t get_filename(void); diff --git a/rostests/winetests/rpcrt4/testlist.c b/rostests/winetests/rpcrt4/testlist.c index 3a7fecf1fdc..8983d699dff 100644 --- a/rostests/winetests/rpcrt4/testlist.c +++ b/rostests/winetests/rpcrt4/testlist.c @@ -10,6 +10,7 @@ extern void func_cstub(void); extern void func_generated(void); extern void func_ndr_marshall(void); extern void func_rpc(void); +extern void func_rpc_async(void); extern void func_server(void); const struct test winetest_testlist[] = @@ -18,6 +19,7 @@ const struct test winetest_testlist[] = { "generated", func_generated }, { "ndr_marshall", func_ndr_marshall }, { "rpc", func_rpc }, + { "rpc_async", func_rpc_async }, { "server", func_server }, { 0, 0 } }; diff --git a/rostests/winetests/rsabase/rsabase.rbuild b/rostests/winetests/rsabase/rsabase.rbuild index f6399a28fd6..65d4fc5ad8b 100644 --- a/rostests/winetests/rsabase/rsabase.rbuild +++ b/rostests/winetests/rsabase/rsabase.rbuild @@ -1,6 +1,6 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/rsaenh/rsaenh.c b/rostests/winetests/rsaenh/rsaenh.c index 4fef6e9fb5b..0119f287a57 100644 --- a/rostests/winetests/rsaenh/rsaenh.c +++ b/rostests/winetests/rsaenh/rsaenh.c @@ -27,6 +27,7 @@ #include "winbase.h" #include "winerror.h" #include "wincrypt.h" +#include "winreg.h" static HCRYPTPROV hProv; static const char szContainer[] = "winetest"; @@ -55,6 +56,33 @@ static const cryptdata cTestData[4] = { 12,12,16} }; +/* + * 1. Take the MD5 Hash of the container name (with an extra null byte) + * 2. Turn the hash into a 4 DWORD hex value + * 3. Append a '_' + * 4. Add the MachineGuid + * + */ +static void uniquecontainer(char *unique) +{ + /* MD5 hash of "winetest\0" in 4 DWORD hex */ + static const char szContainer_md5[] = "9d20fd8d05ed2b8455d125d0bf6d6a70"; + static const char szCryptography[] = "Software\\Microsoft\\Cryptography"; + static const char szMachineGuid[] = "MachineGuid"; + HKEY hkey; + char guid[MAX_PATH]; + DWORD size = MAX_PATH; + + /* Get the MachineGUID */ + RegOpenKeyA(HKEY_LOCAL_MACHINE, szCryptography, &hkey); + RegQueryValueExA(hkey, szMachineGuid, NULL, NULL, (LPBYTE)guid, &size); + RegCloseKey(hkey); + + lstrcpy(unique, szContainer_md5); + lstrcat(unique, "_"); + lstrcat(unique, guid); +} + static void printBytes(const char *heading, const BYTE *pb, size_t cb) { size_t i; @@ -1849,11 +1877,21 @@ static void test_null_provider(void) SetLastError(0xdeadbeef); result = CryptGetProvParam(prov, PP_UNIQUE_CONTAINER, (LPBYTE)szName, &dataLen, 0); if (!result && GetLastError() == NTE_BAD_TYPE) + { skip("PP_UNIQUE_CONTAINER is not supported (win9x or NT)\n"); + } else - ok(result && dataLen == strlen(szContainer)+1 && strcmp(szContainer,szName) == 0, - "failed getting PP_UNIQUE_CONTAINER. result = %s. Error 0x%08X. returned length = %d\n", - (result)? "TRUE":"FALSE",GetLastError(),dataLen); + { + char container[MAX_PATH]; + + ok(result, "failed getting PP_UNIQUE_CONTAINER : 0x%08X\n", GetLastError()); + uniquecontainer(container); + todo_wine + { + ok(dataLen == strlen(container)+1, "Expected a param length of 70, got %d\n", dataLen); + ok(!strcmp(container, szName), "Wrong container name : %s\n", szName); + } + } result = CryptGetUserKey(prov, AT_KEYEXCHANGE, &key); ok(!result && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08x\n", GetLastError()); diff --git a/rostests/winetests/rsaenh/rsaenh.rbuild b/rostests/winetests/rsaenh/rsaenh.rbuild index 94d58ac95b8..7ef53f8c231 100644 --- a/rostests/winetests/rsaenh/rsaenh.rbuild +++ b/rostests/winetests/rsaenh/rsaenh.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/schannel/main.c b/rostests/winetests/schannel/main.c index af245d85c04..814b60a696c 100644 --- a/rostests/winetests/schannel/main.c +++ b/rostests/winetests/schannel/main.c @@ -156,13 +156,19 @@ static void testGetInfo(void) if (!pTables) return; status = pTables->GetInfo(&PackageInfo); - ok(status == STATUS_SUCCESS, "status: 0x%x\n", status); - ok(PackageInfo.fCapabilities == 0x107b3, "fCapabilities: 0x%lx\n", - PackageInfo.fCapabilities); - ok(PackageInfo.wVersion == 1, "wVersion: %d\n", PackageInfo.wVersion); - ok(PackageInfo.wRPCID == 14, "wRPCID: %d\n", PackageInfo.wRPCID); - ok(PackageInfo.cbMaxToken == 0x4000, "cbMaxToken: 0x%lx\n", - PackageInfo.cbMaxToken); + ok(status == STATUS_SUCCESS || + status == SEC_E_UNSUPPORTED_FUNCTION, /* win2k3 */ + "status: 0x%x\n", status); + + if (status == STATUS_SUCCESS) + { + ok(PackageInfo.fCapabilities == 0x107b3, "fCapabilities: 0x%lx\n", + PackageInfo.fCapabilities); + ok(PackageInfo.wVersion == 1, "wVersion: %d\n", PackageInfo.wVersion); + ok(PackageInfo.wRPCID == 14, "wRPCID: %d\n", PackageInfo.wRPCID); + ok(PackageInfo.cbMaxToken == 0x4000, "cbMaxToken: 0x%lx\n", + PackageInfo.cbMaxToken); + } } START_TEST(main) diff --git a/rostests/winetests/schannel/schannel.rbuild b/rostests/winetests/schannel/schannel.rbuild index d8d051b2d00..500c97bcd15 100644 --- a/rostests/winetests/schannel/schannel.rbuild +++ b/rostests/winetests/schannel/schannel.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/setupapi/devinst.c b/rostests/winetests/setupapi/devinst.c new file mode 100644 index 00000000000..727e4540c47 --- /dev/null +++ b/rostests/winetests/setupapi/devinst.c @@ -0,0 +1,1096 @@ +/* + * Devinst tests + * + * Copyright 2006 Christian Gmeiner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winreg.h" +#include "guiddef.h" +#include "setupapi.h" + +#include "wine/test.h" + +/* function pointers */ +static HMODULE hSetupAPI; +static HDEVINFO (WINAPI *pSetupDiCreateDeviceInfoList)(GUID*,HWND); +static HDEVINFO (WINAPI *pSetupDiCreateDeviceInfoListExW)(GUID*,HWND,PCWSTR,PVOID); +static BOOL (WINAPI *pSetupDiCreateDeviceInterfaceA)(HDEVINFO, PSP_DEVINFO_DATA, const GUID *, PCSTR, DWORD, PSP_DEVICE_INTERFACE_DATA); +static BOOL (WINAPI *pSetupDiCallClassInstaller)(DI_FUNCTION, HDEVINFO, PSP_DEVINFO_DATA); +static BOOL (WINAPI *pSetupDiDestroyDeviceInfoList)(HDEVINFO); +static BOOL (WINAPI *pSetupDiEnumDeviceInfo)(HDEVINFO, DWORD, PSP_DEVINFO_DATA); +static BOOL (WINAPI *pSetupDiEnumDeviceInterfaces)(HDEVINFO, PSP_DEVINFO_DATA, const GUID *, DWORD, PSP_DEVICE_INTERFACE_DATA); +static BOOL (WINAPI *pSetupDiInstallClassA)(HWND, PCSTR, DWORD, HSPFILEQ); +static HKEY (WINAPI *pSetupDiOpenClassRegKeyExA)(GUID*,REGSAM,DWORD,PCSTR,PVOID); +static HKEY (WINAPI *pSetupDiOpenDevRegKey)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM); +static HKEY (WINAPI *pSetupDiCreateDevRegKeyW)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, HINF, PCWSTR); +static BOOL (WINAPI *pSetupDiCreateDeviceInfoA)(HDEVINFO, PCSTR, GUID *, PCSTR, HWND, DWORD, PSP_DEVINFO_DATA); +static BOOL (WINAPI *pSetupDiCreateDeviceInfoW)(HDEVINFO, PCWSTR, GUID *, PCWSTR, HWND, DWORD, PSP_DEVINFO_DATA); +static BOOL (WINAPI *pSetupDiGetDeviceInstanceIdA)(HDEVINFO, PSP_DEVINFO_DATA, PSTR, DWORD, PDWORD); +static BOOL (WINAPI *pSetupDiGetDeviceInterfaceDetailA)(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA); +static BOOL (WINAPI *pSetupDiGetDeviceInterfaceDetailW)(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA_W, DWORD, PDWORD, PSP_DEVINFO_DATA); +static BOOL (WINAPI *pSetupDiRegisterDeviceInfo)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PSP_DETSIG_CMPPROC, PVOID, PSP_DEVINFO_DATA); +static HDEVINFO (WINAPI *pSetupDiGetClassDevsA)(CONST GUID *, LPCSTR, HWND, DWORD); +static HDEVINFO (WINAPI *pSetupDiGetClassDevsW)(CONST GUID *, LPCWSTR, HWND, DWORD); +static BOOL (WINAPI *pSetupDiSetDeviceRegistryPropertyA)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, const BYTE *, DWORD); +static BOOL (WINAPI *pSetupDiSetDeviceRegistryPropertyW)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, const BYTE *, DWORD); +static BOOL (WINAPI *pSetupDiGetDeviceRegistryPropertyA)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD); +static BOOL (WINAPI *pSetupDiGetDeviceRegistryPropertyW)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD); + +static void init_function_pointers(void) +{ + hSetupAPI = GetModuleHandleA("setupapi.dll"); + + pSetupDiCreateDeviceInfoA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoA"); + pSetupDiCreateDeviceInfoW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoW"); + pSetupDiCreateDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoList"); + pSetupDiCreateDeviceInfoListExW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoListExW"); + pSetupDiCreateDeviceInterfaceA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInterfaceA"); + pSetupDiDestroyDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiDestroyDeviceInfoList"); + pSetupDiCallClassInstaller = (void *)GetProcAddress(hSetupAPI, "SetupDiCallClassInstaller"); + pSetupDiEnumDeviceInfo = (void *)GetProcAddress(hSetupAPI, "SetupDiEnumDeviceInfo"); + pSetupDiEnumDeviceInterfaces = (void *)GetProcAddress(hSetupAPI, "SetupDiEnumDeviceInterfaces"); + pSetupDiGetDeviceInstanceIdA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInstanceIdA"); + pSetupDiGetDeviceInterfaceDetailA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInterfaceDetailA"); + pSetupDiGetDeviceInterfaceDetailW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInterfaceDetailW"); + pSetupDiInstallClassA = (void *)GetProcAddress(hSetupAPI, "SetupDiInstallClassA"); + pSetupDiOpenClassRegKeyExA = (void *)GetProcAddress(hSetupAPI, "SetupDiOpenClassRegKeyExA"); + pSetupDiOpenDevRegKey = (void *)GetProcAddress(hSetupAPI, "SetupDiOpenDevRegKey"); + pSetupDiCreateDevRegKeyW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDevRegKeyW"); + pSetupDiRegisterDeviceInfo = (void *)GetProcAddress(hSetupAPI, "SetupDiRegisterDeviceInfo"); + pSetupDiGetClassDevsA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetClassDevsA"); + pSetupDiGetClassDevsW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetClassDevsW"); + pSetupDiSetDeviceRegistryPropertyA = (void *)GetProcAddress(hSetupAPI, "SetupDiSetDeviceRegistryPropertyA"); + pSetupDiSetDeviceRegistryPropertyW = (void *)GetProcAddress(hSetupAPI, "SetupDiSetDeviceRegistryPropertyW"); + pSetupDiGetDeviceRegistryPropertyA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceRegistryPropertyA"); + pSetupDiGetDeviceRegistryPropertyW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceRegistryPropertyW"); +} + +/* RegDeleteTreeW from dlls/advapi32/registry.c */ +LSTATUS WINAPI devinst_RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey) +{ + LONG ret; + DWORD dwMaxSubkeyLen, dwMaxValueLen; + DWORD dwMaxLen, dwSize; + WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; + HKEY hSubKey = hKey; + + if(lpszSubKey) + { + ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); + if (ret) return ret; + } + + /* Get highest length for keys, values */ + ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL, + &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL); + if (ret) goto cleanup; + + dwMaxSubkeyLen++; + dwMaxValueLen++; + dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen); + if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR)) + { + /* Name too big: alloc a buffer for it */ + if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR)))) + { + ret = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + } + + + /* Recursively delete all the subkeys */ + while (TRUE) + { + dwSize = dwMaxLen; + if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, + NULL, NULL, NULL)) break; + + ret = devinst_RegDeleteTreeW(hSubKey, lpszName); + if (ret) goto cleanup; + } + + if (lpszSubKey) + ret = RegDeleteKeyW(hKey, lpszSubKey); + else + while (TRUE) + { + dwSize = dwMaxLen; + if (RegEnumValueW(hKey, 0, lpszName, &dwSize, + NULL, NULL, NULL, NULL)) break; + + ret = RegDeleteValueW(hKey, lpszName); + if (ret) goto cleanup; + } + +cleanup: + /* Free buffer if allocated */ + if (lpszName != szNameBuf) + HeapFree( GetProcessHeap(), 0, lpszName); + if(lpszSubKey) + RegCloseKey(hSubKey); + return ret; +} + + +static void test_SetupDiCreateDeviceInfoListEx(void) +{ + HDEVINFO devlist; + BOOL ret; + DWORD error; + static CHAR notnull[] = "NotNull"; + static const WCHAR machine[] = { 'd','u','m','m','y',0 }; + + SetLastError(0xdeadbeef); + /* create empty DeviceInfoList, but set Reserved to a value, which is not NULL */ + devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, notnull); + + error = GetLastError(); + if (error == ERROR_CALL_NOT_IMPLEMENTED) + { + skip("SetupDiCreateDeviceInfoListExW is not implemented\n"); + return; + } + ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE); + ok(error == ERROR_INVALID_PARAMETER, "GetLastError returned wrong value : %d, (expected %d)\n", error, ERROR_INVALID_PARAMETER); + + SetLastError(0xdeadbeef); + /* create empty DeviceInfoList, but set MachineName to something */ + devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, machine, NULL); + + error = GetLastError(); + ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE); + ok(error == ERROR_INVALID_MACHINENAME, "GetLastError returned wrong value : %d, (expected %d)\n", error, ERROR_INVALID_MACHINENAME); + + /* create empty DeviceInfoList */ + devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); + ok(devlist && devlist != INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected != %p)\n", devlist, error, INVALID_HANDLE_VALUE); + + /* destroy DeviceInfoList */ + ret = pSetupDiDestroyDeviceInfoList(devlist); + ok(ret, "SetupDiDestroyDeviceInfoList failed : %d\n", error); +} + +static void test_SetupDiOpenClassRegKeyExA(void) +{ + /* This is a unique guid for testing purposes */ + GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, + 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + static const CHAR guidString[] = "{6a55b5a4-3f65-11db-b704-0011955c2bdb}"; + HKEY hkey; + + /* Check return value for nonexistent key */ + hkey = pSetupDiOpenClassRegKeyExA(&guid, KEY_ALL_ACCESS, + DIOCR_INSTALLER, NULL, NULL); + ok(hkey == INVALID_HANDLE_VALUE, + "returned %p (expected INVALID_HANDLE_VALUE)\n", hkey); + + /* Test it for a key that exists */ + hkey = SetupDiOpenClassRegKey(NULL, KEY_ALL_ACCESS); + if (hkey != INVALID_HANDLE_VALUE) + { + HKEY classKey; + if (RegCreateKeyA(hkey, guidString, &classKey) == ERROR_SUCCESS) + { + RegCloseKey(classKey); + SetLastError(0xdeadbeef); + classKey = pSetupDiOpenClassRegKeyExA(&guid, KEY_ALL_ACCESS, + DIOCR_INSTALLER, NULL, NULL); + ok(classKey != INVALID_HANDLE_VALUE, + "opening class registry key failed with error %d\n", + GetLastError()); + if (classKey != INVALID_HANDLE_VALUE) + RegCloseKey(classKey); + RegDeleteKeyA(hkey, guidString); + } + else + trace("failed to create registry key for test\n"); + } + else + trace("failed to open classes key\n"); +} + +static void append_str(char **str, const char *data) +{ + sprintf(*str, data); + *str += strlen(*str); +} + +static void create_inf_file(LPCSTR filename) +{ + char data[1024]; + char *ptr = data; + DWORD dwNumberOfBytesWritten; + HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + append_str(&ptr, "[Version]\n"); + append_str(&ptr, "Signature=\"$Chicago$\"\n"); + append_str(&ptr, "Class=Bogus\n"); + append_str(&ptr, "ClassGUID={6a55b5a4-3f65-11db-b704-0011955c2bdb}\n"); + append_str(&ptr, "[ClassInstall32]\n"); + append_str(&ptr, "AddReg=BogusClass.NT.AddReg\n"); + append_str(&ptr, "[BogusClass.NT.AddReg]\n"); + append_str(&ptr, "HKR,,,,\"Wine test devices\"\n"); + + WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL); + CloseHandle(hf); +} + +static void get_temp_filename(LPSTR path) +{ + static char curr[MAX_PATH] = { 0 }; + char temp[MAX_PATH]; + LPSTR ptr; + + if (!*curr) + GetCurrentDirectoryA(MAX_PATH, curr); + GetTempFileNameA(curr, "set", 0, temp); + ptr = strrchr(temp, '\\'); + + lstrcpyA(path, ptr + 1); +} + +static void testInstallClass(void) +{ + static const WCHAR classKey[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\','C','l','a','s','s','\\', + '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-', + '1','1','d','b','-','b','7','0','4','-', + '0','0','1','1','9','5','5','c','2','b','d','b','}',0}; + static const CHAR classKey_win9x[] = + "System\\CurrentControlSet\\Services\\Class\\" + "{6a55b5a4-3f65-11db-b704-0011955c2bdb}"; + static const CHAR bogus_win9x[] = + "System\\CurrentControlSet\\Services\\Class\\Bogus"; + char tmpfile[MAX_PATH]; + BOOL ret; + HKEY hkey; + + if (!pSetupDiInstallClassA) + { + skip("No SetupDiInstallClassA\n"); + return; + } + tmpfile[0] = '.'; + tmpfile[1] = '\\'; + get_temp_filename(tmpfile + 2); + create_inf_file(tmpfile + 2); + + ret = pSetupDiInstallClassA(NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + ret = pSetupDiInstallClassA(NULL, NULL, DI_NOVCP, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + ret = pSetupDiInstallClassA(NULL, tmpfile + 2, DI_NOVCP, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + ret = pSetupDiInstallClassA(NULL, tmpfile + 2, 0, NULL); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + /* The next call will succeed. Information is put into the registry but the + * location(s) is/are depending on the Windows version. + */ + ret = pSetupDiInstallClassA(NULL, tmpfile, 0, NULL); + ok(ret, "SetupDiInstallClassA failed: %08x\n", GetLastError()); + if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, classKey_win9x, &hkey)) + { + /* We are on win9x */ + RegCloseKey(hkey); + ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, classKey_win9x), + "Couldn't delete win9x classkey\n"); + ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, bogus_win9x), + "Couldn't delete win9x bogus services class\n"); + } + else + { + /* NT4 and above */ + ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, classKey), + "Couldn't delete NT classkey\n"); + } + DeleteFile(tmpfile); +} + +static void testCreateDeviceInfo(void) +{ + BOOL ret; + HDEVINFO set; + GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, + 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + + if (!pSetupDiCreateDeviceInfoList || !pSetupDiEnumDeviceInfo || + !pSetupDiDestroyDeviceInfoList || !pSetupDiCreateDeviceInfoA) + { + skip("No SetupDiCreateDeviceInfoA\n"); + return; + } + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInfoA(NULL, NULL, NULL, NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DEVINST_NAME, + "Expected ERROR_INVALID_DEVINST_NAME, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInfoA(NULL, "Root\\LEGACY_BOGUS\\0000", NULL, + NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError()); + set = pSetupDiCreateDeviceInfoList(&guid, NULL); + ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n", + GetLastError()); + if (set) + { + SP_DEVINFO_DATA devInfo = { 0 }; + DWORD i; + + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", NULL, + NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + /* Finally, with all three required parameters, this succeeds: */ + ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid, + NULL, NULL, 0, NULL); + ok(ret, "pSetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); + /* This fails because the device ID already exists.. */ + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid, + NULL, NULL, 0, &devInfo); + ok(!ret && GetLastError() == ERROR_DEVINST_ALREADY_EXISTS, + "Expected ERROR_DEVINST_ALREADY_EXISTS, got %08x\n", GetLastError()); + /* whereas this "fails" because cbSize is wrong.. */ + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL, + DICD_GENERATE_ID, &devInfo); + ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER, + "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError()); + devInfo.cbSize = sizeof(devInfo); + ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL, + DICD_GENERATE_ID, &devInfo); + /* and this finally succeeds. */ + ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); + /* There were three devices added, however - the second failure just + * resulted in the SP_DEVINFO_DATA not getting copied. + */ + SetLastError(0xdeadbeef); + i = 0; + while (pSetupDiEnumDeviceInfo(set, i, &devInfo)) + i++; + ok(i == 3, "Expected 3 devices, got %d\n", i); + ok(GetLastError() == ERROR_NO_MORE_ITEMS, + "SetupDiEnumDeviceInfo failed: %08x\n", GetLastError()); + pSetupDiDestroyDeviceInfoList(set); + } +} + +static void testGetDeviceInstanceId(void) +{ + BOOL ret; + HDEVINFO set; + GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, + 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + SP_DEVINFO_DATA devInfo = { 0 }; + + if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList || + !pSetupDiCreateDeviceInfoA || !pSetupDiGetDeviceInstanceIdA) + { + skip("No SetupDiGetDeviceInstanceIdA\n"); + return; + } + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInstanceIdA(NULL, NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInstanceIdA(NULL, &devInfo, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError()); + set = pSetupDiCreateDeviceInfoList(&guid, NULL); + ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n", + GetLastError()); + if (set) + { + char instanceID[MAX_PATH]; + DWORD size; + + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInstanceIdA(set, NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + devInfo.cbSize = sizeof(devInfo); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid, + NULL, NULL, 0, &devInfo); + ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError()); + ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID, + sizeof(instanceID), NULL); + ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError()); + ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0000"), + "Unexpected instance ID %s\n", instanceID); + ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, + NULL, NULL, DICD_GENERATE_ID, &devInfo); + ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); + ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID, + sizeof(instanceID), NULL); + ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError()); + ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0001"), + "Unexpected instance ID %s\n", instanceID); + pSetupDiDestroyDeviceInfoList(set); + } +} + +static void testRegisterDeviceInfo(void) +{ + BOOL ret; + GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, + 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + HDEVINFO set; + + if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList || + !pSetupDiRegisterDeviceInfo) + { + skip("No SetupDiRegisterDeviceInfo\n"); + return; + } + SetLastError(0xdeadbeef); + ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL); + set = pSetupDiCreateDeviceInfoList(&guid, NULL); + ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError()); + if (set) + { + SP_DEVINFO_DATA devInfo = { 0 }; + + SetLastError(0xdeadbeef); + ret = pSetupDiRegisterDeviceInfo(set, NULL, 0, NULL, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + devInfo.cbSize = sizeof(devInfo); + SetLastError(0xdeadbeef); + ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ret = pSetupDiCreateDeviceInfoA(set, "USB\\BOGUS\\0000", &guid, + NULL, NULL, 0, &devInfo); + ok(ret || GetLastError() == ERROR_DEVINST_ALREADY_EXISTS, + "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError()); + if (ret) + { + /* If it already existed, registering it again will fail */ + ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, + NULL); + ok(ret, "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError()); + } + /* FIXME: On Win2K+ systems, this is now persisted to registry in + * HKLM\System\CCS\Enum\USB\Bogus\0000. I don't check because the + * Win9x location is different. + * FIXME: the key also becomes undeletable. How to get rid of it? + */ + pSetupDiDestroyDeviceInfoList(set); + } +} + +static void testCreateDeviceInterface(void) +{ + BOOL ret; + GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, + 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + HDEVINFO set; + + if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList || + !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA || + !pSetupDiEnumDeviceInterfaces) + { + skip("No SetupDiCreateDeviceInterfaceA\n"); + return; + } + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, &guid, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + set = pSetupDiCreateDeviceInfoList(&guid, NULL); + ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError()); + if (set) + { + SP_DEVINFO_DATA devInfo = { 0 }; + SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData), + { 0 } }; + DWORD i; + + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInterfaceA(set, NULL, NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0, + NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + devInfo.cbSize = sizeof(devInfo); + ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid, + NULL, NULL, 0, &devInfo); + ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0, + NULL); + ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER, + "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError()); + ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, + NULL); + ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError()); + /* Creating the same interface a second time succeeds */ + ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, + NULL); + ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError()); + ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, "Oogah", 0, + NULL); + ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError()); + ret = pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, 0, + &interfaceData); + ok(ret, "SetupDiEnumDeviceInterfaces failed: %d\n", GetLastError()); + i = 0; + while (pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, i, + &interfaceData)) + i++; + ok(i == 2, "expected 2 interfaces, got %d\n", i); + ok(GetLastError() == ERROR_NO_MORE_ITEMS, + "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError()); + pSetupDiDestroyDeviceInfoList(set); + } +} + +static void testGetDeviceInterfaceDetail(void) +{ + BOOL ret; + GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, + 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + HDEVINFO set; + + if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList || + !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA || + !pSetupDiGetDeviceInterfaceDetailA) + { + skip("No SetupDiGetDeviceInterfaceDetailA\n"); + return; + } + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInterfaceDetailA(NULL, NULL, NULL, 0, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + set = pSetupDiCreateDeviceInfoList(&guid, NULL); + ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError()); + if (set) + { + SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } }; + SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData), + { 0 } }; + DWORD size = 0; + + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInterfaceDetailA(set, NULL, NULL, 0, NULL, + NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid, + NULL, NULL, 0, &devInfo); + ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, + &interfaceData); + ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL, + 0, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL, + 100, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER, + "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL, + 0, &size, NULL); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + static const char path[] = + "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}"; + LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size); + SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail = + (SP_DEVICE_INTERFACE_DETAIL_DATA_A *)buf; + DWORD expectedsize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR)*(1 + strlen(path)); + + detail->cbSize = 0; + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail, + size, &size, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER, + "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError()); + detail->cbSize = size; + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail, + size, &size, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER, + "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError()); + detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail, + size, &size, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER, + "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError()); + /* Windows 2000 and up check for the exact size. Win9x returns ERROR_INVALID_PARAMETER + * on every call (so doesn't get here) and NT4 doesn't have this function. + */ + detail->cbSize = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]); + ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail, + size, &size, NULL); + ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %d\n", + GetLastError()); + ok(!lstrcmpiA(path, detail->DevicePath), "Unexpected path %s\n", + detail->DevicePath); + /* Check SetupDiGetDeviceInterfaceDetailW */ + if (pSetupDiGetDeviceInterfaceDetailW) + { + ret = pSetupDiGetDeviceInterfaceDetailW(set, &interfaceData, NULL, 0, &size, NULL); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got error code: %d\n", GetLastError()); + ok(expectedsize == size, "SetupDiGetDeviceInterfaceDetailW returned wrong reqsize: expected %d, got %d\n", expectedsize, size); + } + else + skip("SetupDiGetDeviceInterfaceDetailW is not available\n"); + + HeapFree(GetProcessHeap(), 0, buf); + } + pSetupDiDestroyDeviceInfoList(set); + } +} + +static void testDevRegKey(void) +{ + static const WCHAR classKey[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\','C','l','a','s','s','\\', + '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-', + '1','1','d','b','-','b','7','0','4','-', + '0','0','1','1','9','5','5','c','2','b','d','b','}',0}; + BOOL ret; + GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, + 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + HDEVINFO set; + + if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList || + !pSetupDiCreateDeviceInfoA || !pSetupDiOpenDevRegKey || + !pSetupDiRegisterDeviceInfo || !pSetupDiCreateDevRegKeyW || + !pSetupDiCallClassInstaller) + { + skip("No SetupDiOpenDevRegKey\n"); + return; + } + set = pSetupDiCreateDeviceInfoList(&guid, NULL); + ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError()); + if (set) + { + SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } }; + HKEY key = INVALID_HANDLE_VALUE; + + ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid, + NULL, NULL, 0, &devInfo); + ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + key = pSetupDiOpenDevRegKey(NULL, NULL, 0, 0, 0, 0); + ok(key == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + key = pSetupDiOpenDevRegKey(set, NULL, 0, 0, 0, 0); + ok(key == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + key = pSetupDiOpenDevRegKey(set, &devInfo, 0, 0, 0, 0); + ok(key == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, 0, 0); + ok(key == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, + DIREG_BOTH, 0); + ok(key == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, + DIREG_DRV, 0); + ok(key == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_DEVINFO_NOT_REGISTERED, + "Expected ERROR_DEVINFO_NOT_REGISTERED, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL); + ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, + DIREG_DRV, 0); + /* The software key isn't created by default */ + todo_wine + ok(key == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_KEY_DOES_NOT_EXIST, + "Expected ERROR_KEY_DOES_NOT_EXIST_EXIST, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, + DIREG_DEV, 0); + todo_wine + ok(key == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_KEY_DOES_NOT_EXIST, + "Expected ERROR_KEY_DOES_NOT_EXIST_EXIST, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + key = pSetupDiCreateDevRegKeyW(set, &devInfo, DICS_FLAG_GLOBAL, 0, + DIREG_DRV, NULL, NULL); + ok(key != INVALID_HANDLE_VALUE, "SetupDiCreateDevRegKey failed: %08x\n", + GetLastError()); + RegCloseKey(key); + SetLastError(0xdeadbeef); + key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, + DIREG_DRV, 0); + todo_wine + ok(key == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, + DIREG_DRV, KEY_READ); + ok(key != INVALID_HANDLE_VALUE, "SetupDiOpenDevRegKey failed: %08x\n", + GetLastError()); + ret = pSetupDiCallClassInstaller(DIF_REMOVE, set, &devInfo); + pSetupDiDestroyDeviceInfoList(set); + } + devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, classKey); +} + +static void testRegisterAndGetDetail(void) +{ + HDEVINFO set; + BOOL ret; + GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, + 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } }; + SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData), { 0 } }; + DWORD dwSize = 0; + + SetLastError(0xdeadbeef); + set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_ALLCLASSES); + ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, 0, + DICD_GENERATE_ID, &devInfo); + ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, &interfaceData); + ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL); + ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError()); + + pSetupDiDestroyDeviceInfoList(set); + + SetLastError(0xdeadbeef); + set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE); + ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pSetupDiEnumDeviceInterfaces(set, NULL, &guid, 0, &interfaceData); + ok(ret, "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL, 0, &dwSize, NULL); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError()); + if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + static const char path[] = + "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}"; + PSP_DEVICE_INTERFACE_DETAIL_DATA_A detail = NULL; + + detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)HeapAlloc(GetProcessHeap(), 0, dwSize); + if (detail) + { + detail->cbSize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(char); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, + detail, dwSize, &dwSize, NULL); + ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %08x\n", GetLastError()); + ok(!lstrcmpiA(path, detail->DevicePath), "Unexpected path %s\n", + detail->DevicePath); + HeapFree(GetProcessHeap(), 0, detail); + } + } + + pSetupDiDestroyDeviceInfoList(set); +} + +static void testDeviceRegistryPropertyA() +{ + HDEVINFO set; + GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, + 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } }; + CHAR devName[] = "LEGACY_BOGUS"; + CHAR friendlyName[] = "Bogus"; + CHAR buf[6] = ""; + DWORD buflen = 6; + DWORD size; + DWORD regType; + BOOL ret; + + SetLastError(0xdeadbeef); + set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE); + ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n", + GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInfoA(set, devName, &guid, NULL, NULL, + DICD_GENERATE_ID, &devInfo); + ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, 0); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyA(set, NULL, -1, NULL, 0); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, 0); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY, + "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, 0); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, + (PBYTE)friendlyName, buflen); + ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyA(set, NULL, -1, NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, NULL, 0, NULL); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY, + "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, NULL, buflen, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, NULL, 0, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError()); + ok(buflen == size, "Unexpected size: %d\n", size); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, (PBYTE)buf, buflen, NULL); + ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError()); + ok(!lstrcmpiA(friendlyName, buf), "Unexpected property\n"); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, + ®Type, (PBYTE)buf, buflen, NULL); + ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError()); + ok(!lstrcmpiA(friendlyName, buf), "Unexpected value of property\n"); + ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, 0); + ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, (PBYTE)buf, buflen, &size); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + pSetupDiDestroyDeviceInfoList(set); +} + +static void testDeviceRegistryPropertyW() +{ + HDEVINFO set; + GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, + 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } }; + WCHAR devName[] = {'L','E','G','A','C','Y','_','B','O','G','U','S',0}; + WCHAR friendlyName[] = {'B','o','g','u','s',0}; + WCHAR buf[6] = {0}; + DWORD buflen = 6 * sizeof(WCHAR); + DWORD size; + DWORD regType; + BOOL ret; + + SetLastError(0xdeadbeef); + set = pSetupDiGetClassDevsW(&guid, NULL, 0, DIGCF_DEVICEINTERFACE); + if (set == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + skip("W-functions are not implemented\n"); + return; + } + ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsW failed: %08x\n", + GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInfoW(set, devName, &guid, NULL, NULL, + DICD_GENERATE_ID, &devInfo); + ok(ret, "SetupDiCreateDeviceInfoW failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, 0); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyW(set, NULL, -1, NULL, 0); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, 0); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY, + "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, 0); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, + (PBYTE)friendlyName, buflen); + ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyW(set, NULL, -1, NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, NULL, 0, NULL); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY, + "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, NULL, buflen, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, NULL, 0, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError()); + ok(buflen == size, "Unexpected size: %d\n", size); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, (PBYTE)buf, buflen, NULL); + ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError()); + ok(!lstrcmpiW(friendlyName, buf), "Unexpected property\n"); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, + ®Type, (PBYTE)buf, buflen, NULL); + ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError()); + ok(!lstrcmpiW(friendlyName, buf), "Unexpected value of property\n"); + ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType); + SetLastError(0xdeadbeef); + ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, 0); + ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, + NULL, (PBYTE)buf, buflen, &size); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + pSetupDiDestroyDeviceInfoList(set); +} + +START_TEST(devinst) +{ + init_function_pointers(); + + if (pSetupDiCreateDeviceInfoListExW && pSetupDiDestroyDeviceInfoList) + test_SetupDiCreateDeviceInfoListEx(); + else + skip("SetupDiCreateDeviceInfoListExW and/or SetupDiDestroyDeviceInfoList not available\n"); + + if (pSetupDiOpenClassRegKeyExA) + test_SetupDiOpenClassRegKeyExA(); + else + skip("SetupDiOpenClassRegKeyExA is not available\n"); + testInstallClass(); + testCreateDeviceInfo(); + testGetDeviceInstanceId(); + testRegisterDeviceInfo(); + testCreateDeviceInterface(); + testGetDeviceInterfaceDetail(); + testDevRegKey(); + testRegisterAndGetDetail(); + testDeviceRegistryPropertyA(); + testDeviceRegistryPropertyW(); +} diff --git a/rostests/winetests/setupapi/install.c b/rostests/winetests/setupapi/install.c index 14a506215bb..0044f019e4b 100644 --- a/rostests/winetests/setupapi/install.c +++ b/rostests/winetests/setupapi/install.c @@ -1,117 +1,396 @@ /* - * INF file parsing tests + * Unit test for setupapi.dll install functions * - * Copyright 2006 Hervé Poussineau + * Copyright 2007 Misha Koshelev * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include #include -#include +#include +#include +#include #include "windef.h" #include "winbase.h" -#include "wingdi.h" +#include "winnls.h" #include "winuser.h" #include "winreg.h" +#include "winsvc.h" #include "setupapi.h" #include "wine/test.h" -#define TMPFILE ".\\tmp.inf" +static const char inffile[] = "test.inf"; +static char CURR_DIR[MAX_PATH]; -#define STD_HEADER "[Version]\r\nSignature=\"$CHICAGO$\"\r\n" +/* Notes on InstallHinfSectionA/W: + * - InstallHinfSectionW on Win98 and InstallHinfSectionA on WinXP seem to be stubs - they do not do anything + * and simply return without displaying any error message or setting last error. We test whether + * InstallHinfSectionA sets last error, and if it doesn't we set it to NULL and use the W version if available. + * - These functions do not return a value and do not always set last error to ERROR_SUCCESS when installation still + * occurs (e.g., unquoted inf file with spaces, registry keys are written but last error is 6). Also, on Win98 last error + * is set to ERROR_SUCCESS even if install fails (e.g., quoted inf file with spaces, no registry keys set, MessageBox with + * "Installation Error" displayed). Thus, we must use functional tests (e.g., is registry key created) to determine whether + * or not installation occurred. + * - On installation problems, a MessageBox() is displayed and a Beep() is issued. The MessageBox() is disabled with a + * CBT hook. + */ -/* create a new file with specified contents and open it */ -static HINF test_file_contents( const char *data, UINT *err_line ) +static void (WINAPI *pInstallHinfSectionA)(HWND, HINSTANCE, LPCSTR, INT); +static void (WINAPI *pInstallHinfSectionW)(HWND, HINSTANCE, LPCWSTR, INT); + +/* + * Helpers + */ + +static void create_inf_file(LPCSTR filename, const char *data) { DWORD res; - HANDLE handle = CreateFileA( TMPFILE, GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 ); - if (handle == INVALID_HANDLE_VALUE) return 0; - if (!WriteFile( handle, data, strlen(data), &res, NULL )) trace( "write error\n" ); - CloseHandle( handle ); - return SetupOpenInfFileA( TMPFILE, 0, INF_STYLE_WIN4, err_line ); + HANDLE handle = CreateFile(filename, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + assert(handle != INVALID_HANDLE_VALUE); + assert(WriteFile(handle, data, strlen(data), &res, NULL)); + CloseHandle(handle); } -static void test_InstallHinfSectionA(void) +/* CBT hook to ensure a window (e.g., MessageBox) cannot be created */ +static HHOOK hhook; +static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) { - char buffer[MAX_INF_STRING_LENGTH]; - UINT err_line; - HINF hinf; - DWORD err; - DWORD len; + return nCode == HCBT_CREATEWND ? 1: CallNextHookEx(hhook, nCode, wParam, lParam); +} - SetLastError( 0xdeadbeef ); - hinf = test_file_contents( STD_HEADER - "[s]\r\nAddReg=s.Reg\r\n[s.Reg]\r\nHKCU,,Test,,none\r\n" - "[s.Win]\r\nAddReg=sWin.Reg\r\n[sWin.Reg]\r\nHKCU,,Test,,win\r\n" - "[s.NT]\r\nAddReg=sNT.Reg\r\n[sNT.Reg]\r\nHKCU,,Test,,nt\r\n" - , &err_line ); - ok( hinf != INVALID_HANDLE_VALUE, "open failed err %lx", GetLastError() ); - if ( hinf == INVALID_HANDLE_VALUE ) return; +/* + * Tests + */ - system( "rundll32.exe setupapi,InstallHinfSection s 128 " TMPFILE ); +static const char *cmdline_inf = "[Version]\n" + "Signature=\"$Chicago$\"\n" + "[DefaultInstall]\n" + "AddReg=Add.Settings\n" + "[Add.Settings]\n" + "HKCU,Software\\Wine\\setupapitest,,\n"; - len = sizeof( buffer ); - err = RegQueryValueExA( HKEY_CURRENT_USER, "Test", NULL, NULL, (LPBYTE)buffer, &len ); - ok( err == ERROR_SUCCESS, "error %lx", err); +static void run_cmdline(LPCSTR section, int mode, LPCSTR path) +{ + CHAR cmdline[MAX_PATH * 2]; - if (GetVersion() & 0x80000000) - ok( !strcmp( buffer, "win" ), "bad section %s/win\n", buffer ); + sprintf(cmdline, "%s %d %s", section, mode, path); + if (pInstallHinfSectionA) pInstallHinfSectionA(NULL, NULL, cmdline, 0); else - ok( !strcmp( buffer, "nt" ), "bad section %s/nt\n", buffer ); - - err = RegDeleteValue( HKEY_CURRENT_USER, "Test" ); - ok( err == ERROR_SUCCESS, "error %lx", err); + { + WCHAR cmdlinew[MAX_PATH * 2]; + MultiByteToWideChar(CP_ACP, 0, cmdline, -1, cmdlinew, MAX_PATH*2); + pInstallHinfSectionW(NULL, NULL, cmdlinew, 0); + } } -static void test_SetupInstallFromInfSectionA(void) +static void ok_registry(BOOL expectsuccess) { - char buffer[MAX_INF_STRING_LENGTH]; - UINT err_line; - HINF hinf; - DWORD err; - DWORD len; + LONG ret; - SetLastError( 0xdeadbeef ); - hinf = test_file_contents( STD_HEADER - "[s]\r\nAddReg=s.Reg\r\n[s.Reg]\r\nHKR,,Test,,none\r\n" - "[s.Win]\r\nAddReg=sWin.Reg\r\n[sWin.Reg]\r\nHKR,,Test,,win\r\n" - "[s.NT]\r\nAddReg=sNT.Reg\r\n[sNT.Reg]\r\nHKR,,Test,,nt\r\n" - , &err_line ); - ok( hinf != INVALID_HANDLE_VALUE, "open failed err %lx", GetLastError() ); - if (hinf == INVALID_HANDLE_VALUE) return; + /* Functional tests for success of install and clean up */ + ret = RegDeleteKey(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest"); + ok((expectsuccess && ret == ERROR_SUCCESS) || + (!expectsuccess && ret == ERROR_FILE_NOT_FOUND), + "Expected registry key Software\\Wine\\setupapitest to %s, RegDeleteKey returned %d\n", + expectsuccess ? "exist" : "not exist", + ret); +} - SetLastError( 0xdeadbeef ); - ok ( SetupInstallFromInfSectionA( NULL, hinf, "s", SPINST_REGISTRY, HKEY_CURRENT_USER, NULL, 0, NULL, NULL, NULL, NULL ), - "Error code set to %lx", GetLastError() ); +/* Test command line processing */ +static void test_cmdline(void) +{ + static const char infwithspaces[] = "test file.inf"; + char path[MAX_PATH]; - len = sizeof( buffer ); - err = RegQueryValueExA( HKEY_CURRENT_USER, "Test", NULL, NULL, (LPBYTE)buffer, &len ); - ok( err == ERROR_SUCCESS, "error %lx", err); - ok( !strcmp( buffer, "none" ), "bad value %s/none", buffer ); + create_inf_file(inffile, cmdline_inf); + sprintf(path, "%s\\%s", CURR_DIR, inffile); + run_cmdline("DefaultInstall", 128, path); + ok_registry(TRUE); + ok(DeleteFile(inffile), "Expected source inf to exist, last error was %d\n", GetLastError()); - err = RegDeleteValue( HKEY_CURRENT_USER, "Test" ); - ok( err == ERROR_SUCCESS, "error %lx", err); + /* Test handling of spaces in path, unquoted and quoted */ + create_inf_file(infwithspaces, cmdline_inf); + + sprintf(path, "%s\\%s", CURR_DIR, infwithspaces); + run_cmdline("DefaultInstall", 128, path); + ok_registry(TRUE); + + sprintf(path, "\"%s\\%s\"", CURR_DIR, infwithspaces); + run_cmdline("DefaultInstall", 128, path); + ok_registry(FALSE); + + ok(DeleteFile(infwithspaces), "Expected source inf to exist, last error was %d\n", GetLastError()); +} + +static void test_install_svc_from(void) +{ + char inf[2048]; + char path[MAX_PATH]; + HINF infhandle; + BOOL ret; + SC_HANDLE scm_handle, svc_handle; + + /* Bail out if we are on win98 */ + SetLastError(0xdeadbeef); + scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL); + + if (!scm_handle && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) + { + skip("OpenSCManagerA is not implemented, we are most likely on win9x\n"); + return; + } + CloseServiceHandle(scm_handle); + + /* Basic inf file to satisfy SetupOpenInfFileA */ + strcpy(inf, "[Version]\nSignature=\"$Chicago$\"\n"); + create_inf_file(inffile, inf); + sprintf(path, "%s\\%s", CURR_DIR, inffile); + infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); + + /* Nothing but the Version section */ + SetLastError(0xdeadbeef); + ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SECTION_NOT_FOUND, + "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError()); + SetupCloseInfFile(infhandle); + DeleteFile(inffile); + + /* Add the section */ + strcat(inf, "[Winetest.Services]\n"); + create_inf_file(inffile, inf); + infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); + SetLastError(0xdeadbeef); + ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SECTION_NOT_FOUND, + "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError()); + SetupCloseInfFile(infhandle); + DeleteFile(inffile); + + /* Add a reference */ + strcat(inf, "AddService=Winetest,,Winetest.Service\n"); + create_inf_file(inffile, inf); + infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); + SetLastError(0xdeadbeef); + ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT, + "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError()); + SetupCloseInfFile(infhandle); + DeleteFile(inffile); + + /* Add the section */ + strcat(inf, "[Winetest.Service]\n"); + create_inf_file(inffile, inf); + infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); + SetLastError(0xdeadbeef); + ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT, + "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError()); + SetupCloseInfFile(infhandle); + DeleteFile(inffile); + + /* Just the ServiceBinary */ + strcat(inf, "ServiceBinary=%12%\\winetest.sys\n"); + create_inf_file(inffile, inf); + infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); + SetLastError(0xdeadbeef); + ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT, + "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError()); + SetupCloseInfFile(infhandle); + DeleteFile(inffile); + + /* Add the ServiceType */ + strcat(inf, "ServiceType=1\n"); + create_inf_file(inffile, inf); + infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); + SetLastError(0xdeadbeef); + ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT, + "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError()); + SetupCloseInfFile(infhandle); + DeleteFile(inffile); + + /* Add the StartType */ + strcat(inf, "StartType=4\n"); + create_inf_file(inffile, inf); + infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); + SetLastError(0xdeadbeef); + ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT, + "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError()); + SetupCloseInfFile(infhandle); + DeleteFile(inffile); + + /* This should be it, the minimal entries to install a service */ + strcat(inf, "ErrorControl=1"); + create_inf_file(inffile, inf); + infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); + SetLastError(0xdeadbeef); + ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0); + ok(ret, "Expected success\n"); + ok(GetLastError() == ERROR_SUCCESS, + "Expected ERROR_SUCCESS, got %08x\n", GetLastError()); + SetupCloseInfFile(infhandle); + DeleteFile(inffile); + + scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL); + + /* Open the service to see if it's really there */ + svc_handle = OpenServiceA(scm_handle, "Winetest", DELETE); + ok(svc_handle != NULL, "Service was not created\n"); + + SetLastError(0xdeadbeef); + ret = DeleteService(svc_handle); + ok(ret, "Service could not be deleted : %d\n", GetLastError()); + + CloseServiceHandle(svc_handle); + CloseServiceHandle(scm_handle); + + /* TODO: Test the Flags */ +} + +static void test_driver_install(void) +{ + HANDLE handle; + SC_HANDLE scm_handle, svc_handle; + BOOL ret; + char path[MAX_PATH], windir[MAX_PATH], driver[MAX_PATH]; + DWORD attrs; + /* Minimal stuff needed */ + static const char *inf = + "[Version]\n" + "Signature=\"$Chicago$\"\n" + "[DestinationDirs]\n" + "Winetest.DriverFiles=12\n" + "[DefaultInstall]\n" + "CopyFiles=Winetest.DriverFiles\n" + "[DefaultInstall.Services]\n" + "AddService=Winetest,,Winetest.Service\n" + "[Winetest.Service]\n" + "ServiceBinary=%12%\\winetest.sys\n" + "ServiceType=1\n" + "StartType=4\n" + "ErrorControl=1\n" + "[Winetest.DriverFiles]\n" + "winetest.sys"; + + /* Bail out if we are on win98 */ + SetLastError(0xdeadbeef); + scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL); + + if (!scm_handle && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) + { + skip("OpenSCManagerA is not implemented, we are most likely on win9x\n"); + return; + } + CloseServiceHandle(scm_handle); + + /* Place where we expect the driver to be installed */ + GetWindowsDirectoryA(windir, MAX_PATH); + lstrcpyA(driver, windir); + lstrcatA(driver, "\\system32\\drivers\\winetest.sys"); + + /* Create a dummy driver file */ + handle = CreateFileA("winetest.sys", GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + CloseHandle(handle); + + create_inf_file(inffile, inf); + sprintf(path, "%s\\%s", CURR_DIR, inffile); + run_cmdline("DefaultInstall", 128, path); + + /* Driver should have been installed */ + attrs = GetFileAttributes(driver); + ok(attrs != INVALID_FILE_ATTRIBUTES, "Expected driver to exist\n"); + + scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL); + + /* Open the service to see if it's really there */ + svc_handle = OpenServiceA(scm_handle, "Winetest", DELETE); + ok(svc_handle != NULL, "Service was not created\n"); + + SetLastError(0xdeadbeef); + ret = DeleteService(svc_handle); + ok(ret, "Service could not be deleted : %d\n", GetLastError()); + + CloseServiceHandle(svc_handle); + CloseServiceHandle(scm_handle); + + /* File cleanup */ + DeleteFile(inffile); + DeleteFile("winetest.sys"); + DeleteFile(driver); } START_TEST(install) { - test_InstallHinfSectionA(); - test_SetupInstallFromInfSectionA(); - DeleteFileA( TMPFILE ); + HMODULE hsetupapi = GetModuleHandle("setupapi.dll"); + char temp_path[MAX_PATH], prev_path[MAX_PATH]; + DWORD len; + + GetCurrentDirectory(MAX_PATH, prev_path); + GetTempPath(MAX_PATH, temp_path); + SetCurrentDirectory(temp_path); + + strcpy(CURR_DIR, temp_path); + len = strlen(CURR_DIR); + if(len && (CURR_DIR[len - 1] == '\\')) + CURR_DIR[len - 1] = 0; + + pInstallHinfSectionA = (void *)GetProcAddress(hsetupapi, "InstallHinfSectionA"); + pInstallHinfSectionW = (void *)GetProcAddress(hsetupapi, "InstallHinfSectionW"); + if (pInstallHinfSectionA) + { + /* Check if pInstallHinfSectionA sets last error or is a stub (as on WinXP) */ + static const char *minimal_inf = "[Version]\nSignature=\"$Chicago$\"\n"; + char cmdline[MAX_PATH*2]; + create_inf_file(inffile, minimal_inf); + sprintf(cmdline, "DefaultInstall 128 %s\\%s", CURR_DIR, inffile); + SetLastError(0xdeadbeef); + pInstallHinfSectionA(NULL, NULL, cmdline, 0); + if (GetLastError() == 0xdeadbeef) + { + skip("InstallHinfSectionA is broken (stub)\n"); + pInstallHinfSectionA = NULL; + } + ok(DeleteFile(inffile), "Expected source inf to exist, last error was %d\n", GetLastError()); + } + if (!pInstallHinfSectionW && !pInstallHinfSectionA) + skip("InstallHinfSectionA and InstallHinfSectionW are not available\n"); + else + { + /* Set CBT hook to disallow MessageBox creation in current thread */ + hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId()); + assert(hhook != 0); + + test_cmdline(); + test_install_svc_from(); + test_driver_install(); + + UnhookWindowsHookEx(hhook); + } + + SetCurrentDirectory(prev_path); } diff --git a/rostests/winetests/setupapi/misc.c b/rostests/winetests/setupapi/misc.c new file mode 100644 index 00000000000..f8750b60154 --- /dev/null +++ b/rostests/winetests/setupapi/misc.c @@ -0,0 +1,595 @@ +/* + * Miscellaneous tests + * + * Copyright 2007 James Hawkins + * Copyright 2007 Hans Leidekker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winuser.h" +#include "winreg.h" +#include "setupapi.h" + +#include "wine/test.h" + +static CHAR CURR_DIR[MAX_PATH]; + +/* test: + * - fails if not administrator + * - what if it's not a .inf file? + * - copied to %windir%/Inf + * - SourceInfFileName should be a full path + * - SourceInfFileName should be <= MAX_PATH + * - copy styles + */ + +static BOOL (WINAPI *pSetupGetFileCompressionInfoExA)(PCSTR, PSTR, DWORD, PDWORD, PDWORD, PDWORD, PUINT); +static BOOL (WINAPI *pSetupCopyOEMInfA)(PCSTR, PCSTR, DWORD, DWORD, PSTR, DWORD, PDWORD, PSTR *); +static BOOL (WINAPI *pSetupQueryInfOriginalFileInformationA)(PSP_INF_INFORMATION, UINT, PSP_ALTPLATFORM_INFO, PSP_ORIGINAL_FILE_INFO_A); + +static void append_str(char **str, const char *data) +{ + sprintf(*str, data); + *str += strlen(*str); +} + +static void create_inf_file(LPCSTR filename) +{ + char data[1024]; + char *ptr = data; + DWORD dwNumberOfBytesWritten; + HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + append_str(&ptr, "[Version]\n"); + append_str(&ptr, "Signature=\"$Chicago$\"\n"); + append_str(&ptr, "AdvancedINF=2.5\n"); + append_str(&ptr, "[DefaultInstall]\n"); + append_str(&ptr, "RegisterOCXs=RegisterOCXsSection\n"); + append_str(&ptr, "[RegisterOCXsSection]\n"); + append_str(&ptr, "%%11%%\\ole32.dll\n"); + + WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL); + CloseHandle(hf); +} + +static void get_temp_filename(LPSTR path) +{ + CHAR temp[MAX_PATH]; + LPSTR ptr; + + GetTempFileName(CURR_DIR, "set", 0, temp); + ptr = strrchr(temp, '\\'); + + lstrcpy(path, ptr + 1); +} + +static BOOL file_exists(LPSTR path) +{ + return GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES; +} + +static BOOL check_format(LPSTR path, LPSTR inf) +{ + CHAR check[MAX_PATH]; + BOOL res; + + static const CHAR format[] = "\\INF\\oem"; + + GetWindowsDirectory(check, MAX_PATH); + lstrcat(check, format); + res = CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, check, -1, path, lstrlen(check)) == CSTR_EQUAL && + path[lstrlen(check)] != '\\'; + + return (!inf) ? res : res && (inf == path + lstrlen(check) - 3); +} + +static void test_original_file_name(LPCSTR original, LPCSTR dest) +{ + HINF hinf; + PSP_INF_INFORMATION pspii; + SP_ORIGINAL_FILE_INFO spofi; + BOOL res; + DWORD size; + + if (!pSetupQueryInfOriginalFileInformationA) + { + skip("SetupQueryInfOriginalFileInformationA is not available\n"); + return; + } + + hinf = SetupOpenInfFileA(dest, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != NULL, "SetupOpenInfFileA failed with error %d\n", GetLastError()); + + res = SetupGetInfInformation(hinf, INFINFO_INF_SPEC_IS_HINF, NULL, 0, &size); + ok(res, "SetupGetInfInformation failed with error %d\n", GetLastError()); + + pspii = HeapAlloc(GetProcessHeap(), 0, size); + + res = SetupGetInfInformation(hinf, INFINFO_INF_SPEC_IS_HINF, pspii, size, NULL); + ok(res, "SetupGetInfInformation failed with error %d\n", GetLastError()); + + spofi.cbSize = 0; + res = pSetupQueryInfOriginalFileInformationA(pspii, 0, NULL, &spofi); + ok(!res && GetLastError() == ERROR_INVALID_USER_BUFFER, + "SetupQueryInfOriginalFileInformationA should have failed with ERROR_INVALID_USER_BUFFER instead of %d\n", GetLastError()); + + spofi.cbSize = sizeof(spofi); + res = pSetupQueryInfOriginalFileInformationA(pspii, 0, NULL, &spofi); + ok(res, "SetupQueryInfOriginalFileInformationA failed with error %d\n", GetLastError()); + ok(!spofi.OriginalCatalogName[0], "spofi.OriginalCatalogName should have been \"\" instead of \"%s\"\n", spofi.OriginalCatalogName); + todo_wine + ok(!strcmp(original, spofi.OriginalInfName), "spofi.OriginalInfName of %s didn't match real original name %s\n", spofi.OriginalInfName, original); + + HeapFree(GetProcessHeap(), 0, pspii); + + SetupCloseInfFile(hinf); +} + +static void test_SetupCopyOEMInf(void) +{ + CHAR toolong[MAX_PATH * 2]; + CHAR path[MAX_PATH], dest[MAX_PATH]; + CHAR tmpfile[MAX_PATH], dest_save[MAX_PATH]; + LPSTR inf; + DWORD size; + BOOL res; + + /* try NULL SourceInfFileName */ + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(NULL, NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL); + ok(res == FALSE, "Expected FALSE, got %d\n", res); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* try empty SourceInfFileName */ + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA("", NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL); + ok(res == FALSE, "Expected FALSE, got %d\n", res); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + /* try a relative nonexistent SourceInfFileName */ + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA("nonexistent", NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL); + ok(res == FALSE, "Expected FALSE, got %d\n", res); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + /* try an absolute nonexistent SourceInfFileName */ + lstrcpy(path, CURR_DIR); + lstrcat(path, "\\nonexistent"); + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(path, NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL); + ok(res == FALSE, "Expected FALSE, got %d\n", res); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + /* try a long SourceInfFileName */ + memset(toolong, 'a', MAX_PATH * 2); + toolong[MAX_PATH * 2 - 1] = '\0'; + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(toolong, NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL); + ok(res == FALSE, "Expected FALSE, got %d\n", res); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + get_temp_filename(tmpfile); + create_inf_file(tmpfile); + + /* try a relative SourceInfFileName */ + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(tmpfile, NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL); + ok(res == FALSE, "Expected FALSE, got %d\n", res); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(file_exists(tmpfile), "Expected tmpfile to exist\n"); + + /* try SP_COPY_REPLACEONLY, dest does not exist */ + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, SP_COPY_REPLACEONLY, NULL, 0, NULL, NULL); + ok(res == FALSE, "Expected FALSE, got %d\n", res); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(file_exists(tmpfile), "Expected source inf to exist\n"); + + /* try an absolute SourceInfFileName, without DestinationInfFileName */ + lstrcpy(path, CURR_DIR); + lstrcat(path, "\\"); + lstrcat(path, tmpfile); + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, NULL, 0, NULL, NULL); + ok(res == TRUE, "Expected TRUE, got %d\n", res); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + ok(file_exists(path), "Expected source inf to exist\n"); + + /* try SP_COPY_REPLACEONLY, dest exists */ + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, SP_COPY_REPLACEONLY, NULL, 0, NULL, NULL); + ok(res == TRUE, "Expected TRUE, got %d\n", res); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + ok(file_exists(path), "Expected source inf to exist\n"); + + /* try SP_COPY_NOOVERWRITE */ + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL); + ok(res == FALSE, "Expected FALSE, got %d\n", res); + ok(GetLastError() == ERROR_FILE_EXISTS, + "Expected ERROR_FILE_EXISTS, got %d\n", GetLastError()); + + /* get the DestinationInfFileName */ + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, dest, MAX_PATH, NULL, NULL); + ok(res == TRUE, "Expected TRUE, got %d\n", res); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + ok(lstrlen(dest) != 0, "Expected a non-zero length string\n"); + ok(file_exists(dest), "Expected destination inf to exist\n"); + ok(check_format(dest, NULL), "Expected %%windir%%\\inf\\OEMx.inf, got %s\n", dest); + ok(file_exists(path), "Expected source inf to exist\n"); + + lstrcpy(dest_save, dest); + DeleteFile(dest_save); + + /* get the DestinationInfFileName, DestinationInfFileNameSize is too small + * - inf is still copied + */ + lstrcpy(dest, "aaa"); + size = 0; + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, dest, 5, &size, NULL); + ok(res == FALSE, "Expected FALSE, got %d\n", res); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + ok(file_exists(path), "Expected source inf to exist\n"); + ok(file_exists(dest_save), "Expected dest inf to exist\n"); + ok(!lstrcmp(dest, "aaa"), "Expected dest to be unchanged\n"); + ok(size == lstrlen(dest_save) + 1, "Expected size to be lstrlen(dest_save) + 1\n"); + + /* get the DestinationInfFileName and DestinationInfFileNameSize */ + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, dest, MAX_PATH, &size, NULL); + ok(res == TRUE, "Expected TRUE, got %d\n", res); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + ok(lstrlen(dest) + 1 == size, "Expected sizes to match, got (%d, %d)\n", lstrlen(dest), size); + ok(file_exists(dest), "Expected destination inf to exist\n"); + ok(check_format(dest, NULL), "Expected %%windir%%\\inf\\OEMx.inf, got %s\n", dest); + ok(file_exists(path), "Expected source inf to exist\n"); + ok(size == lstrlen(dest_save) + 1, "Expected size to be lstrlen(dest_save) + 1\n"); + + test_original_file_name(strrchr(path, '\\') + 1, dest); + + /* get the DestinationInfFileName, DestinationInfFileNameSize, and DestinationInfFileNameComponent */ + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, 0, dest, MAX_PATH, &size, &inf); + ok(res == TRUE, "Expected TRUE, got %d\n", res); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + ok(lstrlen(dest) + 1 == size, "Expected sizes to match, got (%d, %d)\n", lstrlen(dest), size); + ok(file_exists(dest), "Expected destination inf to exist\n"); + ok(check_format(dest, inf), "Expected %%windir%%\\inf\\OEMx.inf, got %s\n", dest); + ok(file_exists(path), "Expected source inf to exist\n"); + ok(size == lstrlen(dest_save) + 1, "Expected size to be lstrlen(dest_save) + 1\n"); + + /* try SP_COPY_DELETESOURCE */ + SetLastError(0xdeadbeef); + res = pSetupCopyOEMInfA(path, NULL, SPOST_NONE, SP_COPY_DELETESOURCE, NULL, 0, NULL, NULL); + ok(res == TRUE, "Expected TRUE, got %d\n", res); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + ok(!file_exists(path), "Expected source inf to not exist\n"); +} + +static void create_source_file(LPSTR filename, const BYTE *data, DWORD size) +{ + HANDLE handle; + DWORD written; + + handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + WriteFile(handle, data, size, &written, NULL); + CloseHandle(handle); +} + +static BOOL compare_file_data(LPSTR file, const BYTE *data, DWORD size) +{ + DWORD read; + HANDLE handle; + BOOL ret = FALSE; + LPBYTE buffer; + + handle = CreateFileA(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + buffer = HeapAlloc(GetProcessHeap(), 0, size); + if (buffer) + { + ReadFile(handle, buffer, size, &read, NULL); + if (read == size && !memcmp(data, buffer, size)) ret = TRUE; + HeapFree(GetProcessHeap(), 0, buffer); + } + CloseHandle(handle); + return ret; +} + +static const BYTE uncompressed[] = { + 'u','n','c','o','m','p','r','e','s','s','e','d','\r','\n' +}; +static const BYTE comp_lzx[] = { + 0x53, 0x5a, 0x44, 0x44, 0x88, 0xf0, 0x27, 0x33, 0x41, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x75, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x3f, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64 +}; +static const BYTE comp_zip[] = { + 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xae, 0x81, 0x36, 0x75, 0x11, + 0x2c, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x15, 0x00, 0x77, 0x69, + 0x6e, 0x65, 0x55, 0x54, 0x09, 0x00, 0x03, 0xd6, 0x0d, 0x10, 0x46, 0xfd, 0x0d, 0x10, 0x46, 0x55, + 0x78, 0x04, 0x00, 0xe8, 0x03, 0xe8, 0x03, 0x00, 0x00, 0x75, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x64, 0x50, 0x4b, 0x01, 0x02, 0x17, 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbd, 0xae, 0x81, 0x36, 0x75, 0x11, 0x2c, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x77, 0x69, 0x6e, 0x65, 0x55, 0x54, 0x05, 0x00, 0x03, 0xd6, 0x0d, 0x10, 0x46, + 0x55, 0x78, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x3f, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const BYTE comp_cab_lzx[] = { + 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x0f, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x36, 0x86, 0x72, 0x20, 0x00, 0x77, 0x69, 0x6e, 0x65, + 0x00, 0x19, 0xd0, 0x1a, 0xe3, 0x22, 0x00, 0x0e, 0x00, 0x5b, 0x80, 0x80, 0x8d, 0x00, 0x30, 0xe0, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x75, 0x6e, 0x63, + 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x0d, 0x0a +}; +static const BYTE comp_cab_zip[] = { + 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x36, 0x2f, 0xa5, 0x20, 0x00, 0x77, 0x69, 0x6e, 0x65, + 0x00, 0x7c, 0x80, 0x26, 0x2b, 0x12, 0x00, 0x0e, 0x00, 0x43, 0x4b, 0x2b, 0xcd, 0x4b, 0xce, 0xcf, + 0x2d, 0x28, 0x4a, 0x2d, 0x2e, 0x4e, 0x4d, 0xe1, 0xe5, 0x02, 0x00 +}; + +static void test_SetupGetFileCompressionInfo(void) +{ + DWORD ret, source_size, target_size; + char source[MAX_PATH], temp[MAX_PATH], *name; + UINT type; + + GetTempPathA(sizeof(temp), temp); + GetTempFileNameA(temp, "fci", 0, source); + + create_source_file(source, uncompressed, sizeof(uncompressed)); + + ret = SetupGetFileCompressionInfoA(NULL, NULL, NULL, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "SetupGetFileCompressionInfo failed unexpectedly\n"); + + ret = SetupGetFileCompressionInfoA(source, NULL, NULL, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "SetupGetFileCompressionInfo failed unexpectedly\n"); + + ret = SetupGetFileCompressionInfoA(source, &name, NULL, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "SetupGetFileCompressionInfo failed unexpectedly\n"); + + ret = SetupGetFileCompressionInfoA(source, &name, &source_size, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "SetupGetFileCompressionInfo failed unexpectedly\n"); + + ret = SetupGetFileCompressionInfoA(source, &name, &source_size, &target_size, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "SetupGetFileCompressionInfo failed unexpectedly\n"); + + name = NULL; + source_size = target_size = 0; + type = 5; + + ret = SetupGetFileCompressionInfoA(source, &name, &source_size, &target_size, &type); + ok(!ret, "SetupGetFileCompressionInfo failed unexpectedly\n"); + ok(name && !lstrcmpA(name, source), "got %s, expected %s\n", name, source); + ok(source_size == sizeof(uncompressed), "got %d\n", source_size); + ok(target_size == sizeof(uncompressed), "got %d\n", target_size); + ok(type == FILE_COMPRESSION_NONE, "got %d, expected FILE_COMPRESSION_NONE\n", type); + + DeleteFileA(source); +} + +static void test_SetupGetFileCompressionInfoEx(void) +{ + BOOL ret; + DWORD required_len, source_size, target_size; + char source[MAX_PATH], temp[MAX_PATH], name[MAX_PATH]; + UINT type; + + GetTempPathA(sizeof(temp), temp); + GetTempFileNameA(temp, "doc", 0, source); + + ret = pSetupGetFileCompressionInfoExA(NULL, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret, "SetupGetFileCompressionInfoEx succeeded unexpectedly\n"); + + ret = pSetupGetFileCompressionInfoExA(source, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret, "SetupGetFileCompressionInfoEx succeeded unexpectedly\n"); + + ret = pSetupGetFileCompressionInfoExA(source, NULL, 0, &required_len, NULL, NULL, NULL); + ok(!ret, "SetupGetFileCompressionInfoEx succeeded unexpectedly\n"); + ok(required_len == lstrlenA(source) + 1, "got %d, expected %d\n", required_len, lstrlenA(source) + 1); + + create_source_file(source, comp_lzx, sizeof(comp_lzx)); + + ret = pSetupGetFileCompressionInfoExA(source, name, sizeof(name), &required_len, &source_size, &target_size, &type); + ok(ret, "SetupGetFileCompressionInfoEx failed unexpectedly: %d\n", ret); + ok(!lstrcmpA(name, source), "got %s, expected %s\n", name, source); + ok(required_len == lstrlenA(source) + 1, "got %d, expected %d\n", required_len, lstrlenA(source) + 1); + ok(source_size == sizeof(comp_lzx), "got %d\n", source_size); + ok(target_size == sizeof(uncompressed), "got %d\n", target_size); + ok(type == FILE_COMPRESSION_WINLZA, "got %d, expected FILE_COMPRESSION_WINLZA\n", type); + DeleteFileA(source); + + create_source_file(source, comp_zip, sizeof(comp_zip)); + + ret = pSetupGetFileCompressionInfoExA(source, name, sizeof(name), &required_len, &source_size, &target_size, &type); + ok(ret, "SetupGetFileCompressionInfoEx failed unexpectedly: %d\n", ret); + ok(!lstrcmpA(name, source), "got %s, expected %s\n", name, source); + ok(required_len == lstrlenA(source) + 1, "got %d, expected %d\n", required_len, lstrlenA(source) + 1); + ok(source_size == sizeof(comp_zip), "got %d\n", source_size); + ok(target_size == sizeof(comp_zip), "got %d\n", target_size); + ok(type == FILE_COMPRESSION_NONE, "got %d, expected FILE_COMPRESSION_NONE\n", type); + DeleteFileA(source); + + create_source_file(source, comp_cab_lzx, sizeof(comp_cab_lzx)); + + ret = pSetupGetFileCompressionInfoExA(source, name, sizeof(name), &required_len, &source_size, &target_size, &type); + ok(ret, "SetupGetFileCompressionInfoEx failed unexpectedly: %d\n", ret); + ok(!lstrcmpA(name, source), "got %s, expected %s\n", name, source); + ok(required_len == lstrlenA(source) + 1, "got %d, expected %d\n", required_len, lstrlenA(source) + 1); + ok(source_size == sizeof(comp_cab_lzx), "got %d\n", source_size); + ok(target_size == sizeof(uncompressed), "got %d\n", target_size); + ok(type == FILE_COMPRESSION_MSZIP, "got %d, expected FILE_COMPRESSION_MSZIP\n", type); + DeleteFileA(source); + + create_source_file(source, comp_cab_zip, sizeof(comp_cab_zip)); + + ret = pSetupGetFileCompressionInfoExA(source, name, sizeof(name), &required_len, &source_size, &target_size, &type); + ok(ret, "SetupGetFileCompressionInfoEx failed unexpectedly: %d\n", ret); + ok(!lstrcmpA(name, source), "got %s, expected %s\n", name, source); + ok(required_len == lstrlenA(source) + 1, "got %d, expected %d\n", required_len, lstrlenA(source) + 1); + ok(source_size == sizeof(comp_cab_zip), "got %d\n", source_size); + ok(target_size == sizeof(uncompressed), "got %d\n", target_size); + ok(type == FILE_COMPRESSION_MSZIP, "got %d, expected FILE_COMPRESSION_MSZIP\n", type); + DeleteFileA(source); +} + +static void test_SetupDecompressOrCopyFile(void) +{ + DWORD ret; + char source[MAX_PATH], target[MAX_PATH], temp[MAX_PATH], *p; + UINT type; + + GetTempPathA(sizeof(temp), temp); + GetTempFileNameA(temp, "doc", 0, source); + GetTempFileNameA(temp, "doc", 0, target); + + /* parameter tests */ + + create_source_file(source, uncompressed, sizeof(uncompressed)); + + ret = SetupDecompressOrCopyFileA(NULL, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "SetupDecompressOrCopyFile failed unexpectedly\n"); + + type = FILE_COMPRESSION_NONE; + ret = SetupDecompressOrCopyFileA(NULL, target, &type); + ok(ret == ERROR_INVALID_PARAMETER, "SetupDecompressOrCopyFile failed unexpectedly\n"); + + ret = SetupDecompressOrCopyFileA(source, NULL, &type); + ok(ret == ERROR_INVALID_PARAMETER, "SetupDecompressOrCopyFile failed unexpectedly\n"); + + type = 5; /* try an invalid compression type */ + ret = SetupDecompressOrCopyFileA(source, target, &type); + ok(ret == ERROR_INVALID_PARAMETER, "SetupDecompressOrCopyFile failed unexpectedly\n"); + + DeleteFileA(target); + + /* no compression tests */ + + ret = SetupDecompressOrCopyFileA(source, target, NULL); + ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret); + ok(compare_file_data(target, uncompressed, sizeof(uncompressed)), "incorrect target file\n"); + + /* try overwriting existing file */ + ret = SetupDecompressOrCopyFileA(source, target, NULL); + ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret); + DeleteFileA(target); + + type = FILE_COMPRESSION_NONE; + ret = SetupDecompressOrCopyFileA(source, target, &type); + ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret); + ok(compare_file_data(target, uncompressed, sizeof(uncompressed)), "incorrect target file\n"); + DeleteFileA(target); + + type = FILE_COMPRESSION_WINLZA; + ret = SetupDecompressOrCopyFileA(source, target, &type); + ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret); + ok(compare_file_data(target, uncompressed, sizeof(uncompressed)), "incorrect target file\n"); + DeleteFileA(target); + + /* lz compression tests */ + + create_source_file(source, comp_lzx, sizeof(comp_lzx)); + + ret = SetupDecompressOrCopyFileA(source, target, NULL); + ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret); + DeleteFileA(target); + + /* zip compression tests */ + + create_source_file(source, comp_zip, sizeof(comp_zip)); + + ret = SetupDecompressOrCopyFileA(source, target, NULL); + ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret); + ok(compare_file_data(target, comp_zip, sizeof(comp_zip)), "incorrect target file\n"); + DeleteFileA(target); + + /* cabinet compression tests */ + + create_source_file(source, comp_cab_zip, sizeof(comp_cab_zip)); + + p = strrchr(target, '\\'); + lstrcpyA(p + 1, "wine"); + + ret = SetupDecompressOrCopyFileA(source, target, NULL); + ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret); + ok(compare_file_data(target, uncompressed, sizeof(uncompressed)), "incorrect target file\n"); + + /* try overwriting existing file */ + ret = SetupDecompressOrCopyFileA(source, target, NULL); + ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret); + + /* try zip compression */ + type = FILE_COMPRESSION_MSZIP; + ret = SetupDecompressOrCopyFileA(source, target, &type); + ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret); + ok(compare_file_data(target, uncompressed, sizeof(uncompressed)), "incorrect target file\n"); + + /* try no compression */ + type = FILE_COMPRESSION_NONE; + ret = SetupDecompressOrCopyFileA(source, target, &type); + ok(!ret, "SetupDecompressOrCopyFile failed unexpectedly: %d\n", ret); + ok(compare_file_data(target, comp_cab_zip, sizeof(comp_cab_zip)), "incorrect target file\n"); + + DeleteFileA(target); + DeleteFileA(source); +} + +START_TEST(misc) +{ + HMODULE hsetupapi = GetModuleHandle("setupapi.dll"); + + pSetupGetFileCompressionInfoExA = (void*)GetProcAddress(hsetupapi, "SetupGetFileCompressionInfoExA"); + pSetupCopyOEMInfA = (void*)GetProcAddress(hsetupapi, "SetupCopyOEMInfA"); + pSetupQueryInfOriginalFileInformationA = (void*)GetProcAddress(hsetupapi, "SetupQueryInfOriginalFileInformationA"); + + GetCurrentDirectoryA(MAX_PATH, CURR_DIR); + + if (pSetupCopyOEMInfA) + test_SetupCopyOEMInf(); + else + skip("SetupCopyOEMInfA is not available\n"); + + test_SetupGetFileCompressionInfo(); + + if (pSetupGetFileCompressionInfoExA) + test_SetupGetFileCompressionInfoEx(); + else + skip("SetupGetFileCompressionInfoExA is not available\n"); + + test_SetupDecompressOrCopyFile(); +} diff --git a/rostests/winetests/setupapi/parser.c b/rostests/winetests/setupapi/parser.c index 5556c82432c..6341222819e 100644 --- a/rostests/winetests/setupapi/parser.c +++ b/rostests/winetests/setupapi/parser.c @@ -30,7 +30,18 @@ #include "wine/test.h" -static const char tmpfile[] = ".\\tmp.inf"; +/* function pointers */ +static HMODULE hSetupAPI; +static LPCWSTR (WINAPI *pSetupGetField)(PINFCONTEXT,DWORD); + +static void init_function_pointers(void) +{ + hSetupAPI = GetModuleHandleA("setupapi.dll"); + + pSetupGetField = (void *)GetProcAddress(hSetupAPI, "pSetupGetField"); +} + +static const char tmpfilename[] = ".\\tmp.inf"; /* some large strings */ #define A255 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \ @@ -49,18 +60,19 @@ static const char tmpfile[] = ".\\tmp.inf"; #define STR_SECTION "[Strings]\nfoo=aaa\nbar=bbb\nloop=%loop2%\nloop2=%loop%\n" \ "per%%cent=abcd\nper=1\ncent=2\n22=foo\n" \ "big=" A400 "\n" \ + "mydrive=\"C:\\\"\n" \ "verybig=" A400 A400 A400 "\n" /* create a new file with specified contents and open it */ static HINF test_file_contents( const char *data, UINT *err_line ) { DWORD res; - HANDLE handle = CreateFileA( tmpfile, GENERIC_READ|GENERIC_WRITE, + HANDLE handle = CreateFileA( tmpfilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 ); if (handle == INVALID_HANDLE_VALUE) return 0; if (!WriteFile( handle, data, strlen(data), &res, NULL )) trace( "write error\n" ); CloseHandle( handle ); - return SetupOpenInfFileA( tmpfile, 0, INF_STYLE_WIN4, err_line ); + return SetupOpenInfFileA( tmpfilename, 0, INF_STYLE_WIN4, err_line ); } static const char *get_string_field( INFCONTEXT *context, DWORD index ) @@ -130,20 +142,20 @@ static void test_invalid_files(void) err_line = 0xdeadbeef; hinf = test_file_contents( invalid_files[i].data, &err_line ); err = GetLastError(); - trace( "hinf=%p err=%lx line=%d\n", hinf, err, err_line ); + trace( "hinf=%p err=0x%x line=%d\n", hinf, err, err_line ); if (invalid_files[i].error) /* should fail */ { ok( hinf == INVALID_HANDLE_VALUE, "file %u: Open succeeded\n", i ); if (invalid_files[i].todo) todo_wine { - ok( err == invalid_files[i].error, "file %u: Bad error %lx/%lx\n", + ok( err == invalid_files[i].error, "file %u: Bad error %u/%u\n", i, err, invalid_files[i].error ); ok( err_line == invalid_files[i].err_line, "file %u: Bad error line %d/%d\n", i, err_line, invalid_files[i].err_line ); } else { - ok( err == invalid_files[i].error, "file %u: Bad error %lx/%lx\n", + ok( err == invalid_files[i].error, "file %u: Bad error %u/%u\n", i, err, invalid_files[i].error ); ok( err_line == invalid_files[i].err_line, "file %u: Bad error line %d/%d\n", i, err_line, invalid_files[i].err_line ); @@ -152,9 +164,9 @@ static void test_invalid_files(void) else /* should succeed */ { ok( hinf != INVALID_HANDLE_VALUE, "file %u: Open failed\n", i ); - ok( err == 0, "file %u: Error code set to %lx\n", i, err ); + ok( err == 0, "file %u: Error code set to %u\n", i, err ); } - if (hinf != INVALID_HANDLE_VALUE) SetupCloseInfFile( hinf ); + SetupCloseInfFile( hinf ); } } @@ -210,23 +222,23 @@ static void test_section_names(void) { SetLastError( 0xdeadbeef ); hinf = test_file_contents( section_names[i].data, &err_line ); - ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %lx\n", i, GetLastError() ); + ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %u\n", i, GetLastError() ); if (hinf == INVALID_HANDLE_VALUE) continue; ret = SetupGetLineCountA( hinf, section_names[i].section ); err = GetLastError(); - trace( "hinf=%p ret=%ld err=%lx\n", hinf, ret, err ); + trace( "hinf=%p ret=%d err=0x%x\n", hinf, ret, err ); if (ret != -1) { ok( !section_names[i].error, "line %u: section name %s found\n", i, section_names[i].section ); - ok( !err, "line %u: bad error code %lx\n", i, err ); + ok( !err, "line %u: bad error code %u\n", i, err ); } else { ok( section_names[i].error, "line %u: section name %s not found\n", i, section_names[i].section ); - ok( err == section_names[i].error, "line %u: bad error %lx/%lx\n", + ok( err == section_names[i].error, "line %u: bad error %u/%u\n", i, err, section_names[i].error ); } SetupCloseInfFile( hinf ); @@ -273,6 +285,9 @@ static const struct { "ab=cd\",\"ef", "ab", { "cd,ef" } }, { "ab=cd\",ef", "ab", { "cd,ef" } }, { "ab=cd\",ef\\\nab", "ab", { "cd,ef\\" } }, + + /* single quotes (unhandled)*/ + { "HKLM,A,B,'C',D", NULL, { "HKLM", "A","B","'C'","D" } }, /* spaces */ { " a b = c , d \n", "a b", { "c", "d" } }, { " a b = c ,\" d\" \n", "a b", { "c", " d" } }, @@ -304,6 +319,16 @@ static const struct { "a=%big%%big%%big%%big%\n" STR_SECTION, "a", { A400 A400 A400 A400 } }, { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION, "a", { A400 A400 A400 A400 A400 A400 A400 A400 A400 } }, { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION, "a", { A4097 /*MAX_INF_STRING_LENGTH+1*/ } }, + + /* Prove expansion of system entries removes extra \'s and string + replacements doesn't */ + { "ab=\"%24%\"\n" STR_SECTION, "ab", { "C:\\" } }, + { "ab=\"%mydrive%\"\n" STR_SECTION, "ab", { "C:\\" } }, + { "ab=\"%24%\\fred\"\n" STR_SECTION, "ab", { "C:\\fred" } }, + { "ab=\"%mydrive%\\fred\"\n" STR_SECTION,"ab", { "C:\\\\fred" } }, + /* Confirm duplicate \'s kept */ + { "ab=\"%24%\\\\fred\"", "ab", { "C:\\\\fred" } }, + { "ab=C:\\\\FRED", "ab", { "C:\\\\FRED" } }, }; /* check the key of a certain line */ @@ -315,12 +340,12 @@ static const char *check_key( INFCONTEXT *context, const char *wanted ) if (!key) { ok( !wanted, "missing key %s\n", wanted ); - ok( err == 0 || err == ERROR_INVALID_PARAMETER, "last error set to %lx\n", err ); + ok( err == 0 || err == ERROR_INVALID_PARAMETER, "last error set to %u\n", err ); } else { ok( !strcmp( key, wanted ), "bad key %s/%s\n", key, wanted ); - ok( err == 0, "last error set to %lx\n", err ); + ok( err == 0, "last error set to %u\n", err ); } return key; } @@ -342,7 +367,7 @@ static void test_key_names(void) strcat( buffer, key_names[i].data ); SetLastError( 0xdeadbeef ); hinf = test_file_contents( buffer, &err_line ); - ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %lx\n", i, GetLastError() ); + ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %u\n", i, GetLastError() ); if (hinf == INVALID_HANDLE_VALUE) continue; ret = SetupFindFirstLineA( hinf, "Test", 0, &context ); @@ -357,7 +382,7 @@ static void test_key_names(void) err = GetLastError(); if (field) { - ok( err == 0, "line %u: bad error %lx\n", i, GetLastError() ); + ok( err == 0, "line %u: bad error %u\n", i, err ); if (key_names[i].fields[index]) ok( !strcmp( field, key_names[i].fields[index] ), "line %u: bad field %s/%s\n", i, field, key_names[i].fields[index] ); @@ -369,7 +394,7 @@ static void test_key_names(void) else { ok( err == 0 || err == ERROR_INVALID_PARAMETER, - "line %u: bad error %lx\n", i, GetLastError() ); + "line %u: bad error %u\n", i, err ); if (key_names[i].fields[index]) ok( 0, "line %u: missing field %s\n", i, key_names[i].fields[index] ); } @@ -387,18 +412,253 @@ static void test_key_names(void) } -static void test_SetupCloseInfFile(void) +static void test_close_inf_file(void) { - /* try to close with invalid handles */ - SetupCloseInfFile( NULL ); - SetupCloseInfFile( INVALID_HANDLE_VALUE ); + SetLastError(0xdeadbeef); + SetupCloseInfFile(NULL); + ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + SetupCloseInfFile(INVALID_HANDLE_VALUE); + ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %u\n", GetLastError()); + +} + +static const char *contents = "[Version]\n" + "Signature=\"$Windows NT$\"\n" + "FileVersion=5.1.1.2\n" + "[FileBranchInfo]\n" + "RTMQFE=\"%RTMGFE_NAME%\",SP1RTM,"A4097"\n" + "[Strings]\n" + "RTMQFE_NAME = \"RTMQFE\"\n"; + +static const WCHAR getfield_res[][20] = +{ + {'R','T','M','Q','F','E',0}, + {'%','R','T','M','G','F','E','_','N','A','M','E','%',0}, + {'S','P','1','R','T','M',0}, +}; + +static void test_pSetupGetField(void) +{ + UINT err; + BOOL ret; + HINF hinf; + LPCWSTR field; + INFCONTEXT context; + int i; + + hinf = test_file_contents( contents, &err ); + ok( hinf != NULL, "Expected valid INF file\n" ); + + ret = SetupFindFirstLine( hinf, "FileBranchInfo", NULL, &context ); + ok( ret, "Failed to find first line\n" ); + + /* native Windows crashes if a NULL context is sent in */ + + for ( i = 0; i < 3; i++ ) + { + field = pSetupGetField( &context, i ); + ok( field != NULL, "Failed to get field %i\n", i ); + ok( !lstrcmpW( getfield_res[i], field ), "Wrong string returned\n" ); + } + + field = pSetupGetField( &context, 3 ); + ok( field != NULL, "Failed to get field 3\n" ); + ok( lstrlenW( field ) == 511, "Expected 511, got %d\n", lstrlenW( field ) ); + + field = pSetupGetField( &context, 4 ); + ok( field == NULL, "Expected NULL, got %p\n", field ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() ); + + SetupCloseInfFile( hinf ); +} + +static void test_SetupGetIntField(void) +{ + static const struct + { + const char *key; + const char *fields; + DWORD index; + INT value; + DWORD err; + } keys[] = + { + /* key fields index expected int errorcode */ + { "Key=", "48", 1, 48, ERROR_SUCCESS }, + { "Key=", "48", 0, -1, ERROR_INVALID_DATA }, + { "123=", "48", 0, 123, ERROR_SUCCESS }, + { "Key=", "0x4", 1, 4, ERROR_SUCCESS }, + { "Key=", "Field1", 1, -1, ERROR_INVALID_DATA }, + { "Key=", "Field1,34", 2, 34, ERROR_SUCCESS }, + { "Key=", "Field1,,Field3", 2, 0, ERROR_SUCCESS }, + { "Key=", "Field1,", 2, 0, ERROR_SUCCESS } + }; + unsigned int i; + + for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) + { + HINF hinf; + char buffer[MAX_INF_STRING_LENGTH]; + INFCONTEXT context; + UINT err; + BOOL retb; + INT intfield; + + strcpy( buffer, STD_HEADER "[TestSection]\n" ); + strcat( buffer, keys[i].key ); + strcat( buffer, keys[i].fields ); + hinf = test_file_contents( buffer, &err); + ok( hinf != NULL, "Expected valid INF file\n" ); + + SetupFindFirstLineA( hinf, "TestSection", "Key", &context ); + SetLastError( 0xdeadbeef ); + intfield = -1; + retb = SetupGetIntField( &context, keys[i].index, &intfield ); + if ( keys[i].err == ERROR_SUCCESS ) + { + ok( retb, "Expected success\n" ); + ok( GetLastError() == ERROR_SUCCESS || + GetLastError() == 0xdeadbeef /* win9x, NT4 */, + "Expected ERROR_SUCCESS or 0xdeadbeef, got %u\n", GetLastError() ); + } + else + { + ok( !retb, "Expected failure\n" ); + ok( GetLastError() == keys[i].err, + "Expected %d, got %u\n", keys[i].err, GetLastError() ); + } + ok( intfield == keys[i].value, "Expected %d, got %d\n", keys[i].value, intfield ); + + SetupCloseInfFile( hinf ); + } +} + +static void test_GLE(void) +{ + static const char *inf = + "[Version]\n" + "Signature=\"$Windows NT$\"\n" + "[Sectionname]\n" + "Keyname1=Field1,Field2,Field3\n" + "\n" + "Keyname2=Field4,Field5\n"; + HINF hinf; + UINT err; + INFCONTEXT context; + BOOL retb; + LONG retl; + char buf[MAX_INF_STRING_LENGTH]; + int bufsize = MAX_INF_STRING_LENGTH; + DWORD retsize; + + hinf = test_file_contents( inf, &err ); + ok( hinf != NULL, "Expected valid INF file\n" ); + + SetLastError(0xdeadbeef); + retb = SetupFindFirstLineA( hinf, "ImNotThere", NULL, &context ); + ok(!retb, "Expected failure\n"); + ok(GetLastError() == ERROR_LINE_NOT_FOUND, + "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupFindFirstLineA( hinf, "ImNotThere", "ImNotThere", &context ); + ok(!retb, "Expected failure\n"); + ok(GetLastError() == ERROR_LINE_NOT_FOUND, + "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupFindFirstLineA( hinf, "Sectionname", NULL, &context ); + ok(retb, "Expected success\n"); + ok(GetLastError() == ERROR_SUCCESS, + "Expected ERROR_SUCCESS, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupFindFirstLineA( hinf, "Sectionname", "ImNotThere", &context ); + ok(!retb, "Expected failure\n"); + ok(GetLastError() == ERROR_LINE_NOT_FOUND, + "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupFindFirstLineA( hinf, "Sectionname", "Keyname1", &context ); + ok(retb, "Expected success\n"); + ok(GetLastError() == ERROR_SUCCESS, + "Expected ERROR_SUCCESS, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupFindNextMatchLineA( &context, "ImNotThere", &context ); + ok(!retb, "Expected failure\n"); + ok(GetLastError() == ERROR_LINE_NOT_FOUND, + "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupFindNextMatchLineA( &context, "Keyname2", &context ); + ok(retb, "Expected success\n"); + ok(GetLastError() == ERROR_SUCCESS, + "Expected ERROR_SUCCESS, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retl = SetupGetLineCountA( hinf, "ImNotThere"); + ok(retl == -1, "Expected -1, got %d\n", retl); + ok(GetLastError() == ERROR_SECTION_NOT_FOUND, + "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retl = SetupGetLineCountA( hinf, "Sectionname"); + ok(retl == 2, "Expected 2, got %d\n", retl); + ok(GetLastError() == ERROR_SUCCESS, + "Expected ERROR_SUCCESS, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupGetLineTextA( NULL, hinf, "ImNotThere", "ImNotThere", buf, bufsize, &retsize); + ok(!retb, "Expected failure\n"); + ok(GetLastError() == ERROR_LINE_NOT_FOUND, + "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupGetLineTextA( NULL, hinf, "Sectionname", "ImNotThere", buf, bufsize, &retsize); + ok(!retb, "Expected failure\n"); + ok(GetLastError() == ERROR_LINE_NOT_FOUND, + "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupGetLineTextA( NULL, hinf, "Sectionname", "Keyname1", buf, bufsize, &retsize); + ok(retb, "Expected success\n"); + ok(GetLastError() == ERROR_SUCCESS, + "Expected ERROR_SUCCESS, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupGetLineByIndexA( hinf, "ImNotThere", 1, &context ); + ok(!retb, "Expected failure\n"); + ok(GetLastError() == ERROR_LINE_NOT_FOUND, + "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupGetLineByIndexA( hinf, "Sectionname", 1, &context ); + ok(retb, "Expected success\n"); + ok(GetLastError() == ERROR_SUCCESS, + "Expected ERROR_SUCCESS, got %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + retb = SetupGetLineByIndexA( hinf, "Sectionname", 3, &context ); + ok(!retb, "Expected failure\n"); + ok(GetLastError() == ERROR_LINE_NOT_FOUND, + "Expected ERROR_LINE_NOT_FOUND, got %08x\n", GetLastError()); + + SetupCloseInfFile( hinf ); } START_TEST(parser) { + init_function_pointers(); test_invalid_files(); test_section_names(); test_key_names(); - test_SetupCloseInfFile(); - DeleteFileA( tmpfile ); + test_close_inf_file(); + test_pSetupGetField(); + test_SetupGetIntField(); + test_GLE(); + DeleteFileA( tmpfilename ); } diff --git a/rostests/winetests/setupapi/query.c b/rostests/winetests/setupapi/query.c index be7f154c174..87f167306ca 100644 --- a/rostests/winetests/setupapi/query.c +++ b/rostests/winetests/setupapi/query.c @@ -23,29 +23,9 @@ #include #include "wine/test.h" -/* function pointers */ -static HMODULE hSetupAPI; -static void (WINAPI *pSetupCloseInfFile)(HINF); -static BOOL (WINAPI *pSetupGetInfInformationA)(LPCVOID,DWORD,PSP_INF_INFORMATION,DWORD,PDWORD); -static HINF (WINAPI *pSetupOpenInfFileA)(PCSTR,PCSTR,DWORD,PUINT); -static BOOL (WINAPI *pSetupQueryInfFileInformationA)(PSP_INF_INFORMATION,UINT,PSTR,DWORD,PDWORD); - CHAR CURR_DIR[MAX_PATH]; CHAR WIN_DIR[MAX_PATH]; -static void init_function_pointers(void) -{ - hSetupAPI = LoadLibraryA("setupapi.dll"); - - if (hSetupAPI) - { - pSetupCloseInfFile = (void *)GetProcAddress(hSetupAPI, "SetupCloseInfFile"); - pSetupGetInfInformationA = (void *)GetProcAddress(hSetupAPI, "SetupGetInfInformationA"); - pSetupOpenInfFileA = (void *)GetProcAddress(hSetupAPI, "SetupOpenInfFileA"); - pSetupQueryInfFileInformationA = (void *)GetProcAddress(hSetupAPI, "SetupQueryInfFileInformationA"); - } -} - static void get_directories(void) { int len; @@ -80,6 +60,37 @@ static void create_inf_file(LPSTR filename) append_str(&ptr, "[Version]\n"); append_str(&ptr, "Signature=\"$Chicago$\"\n"); append_str(&ptr, "AdvancedINF=2.5\n"); + append_str(&ptr, "[SourceDisksNames]\n"); + append_str(&ptr, "2 = %%SrcDiskName%%, LANCOM\\LANtools\\lanconf.cab\n"); + append_str(&ptr, "[SourceDisksFiles]\n"); + append_str(&ptr, "lanconf.exe = 2\n"); + append_str(&ptr, "[DestinationDirs]\n"); + append_str(&ptr, "DefaultDestDir = 24, %%DefaultDest%%\n"); + append_str(&ptr, "[Strings]\n"); + append_str(&ptr, "LangDir = english\n"); + append_str(&ptr, "DefaultDest = LANCOM\n"); + append_str(&ptr, "SrcDiskName = \"LANCOM Software CD\"\n"); + + WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL); + CloseHandle(hf); +} + +static void create_inf_file2(LPSTR filename) +{ + char data[1024]; + char *ptr = data; + DWORD dwNumberOfBytesWritten; + HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + append_str(&ptr, "[SourceFileInfo]\n"); + append_str(&ptr, "sp1qfe\\bitsinst.exe=250B3702C7CCD7C2F9E4DAA1555C933E,000600060A28062C,27136,SP1QFE\n"); + append_str(&ptr, "sp1qfe\\bitsprx2.dll=4EBEA67F4BB4EB402E725CA7CA2857AE,000600060A280621,7680,SP1QFE\n"); + append_str(&ptr, "sp1qfe\\bitsprx3.dll=C788A1D9330DA011EF25E95D3BC7BDE5,000600060A280621,7168,SP1QFE\n"); + append_str(&ptr, "sp1qfe\\qmgr.dll=696AC82FB290A03F205901442E0E9589,000600060A280621,361984,SP1QFE\n"); + append_str(&ptr, "sp1qfe\\qmgrprxy.dll=8B5848144829E1BC985EA4C3D8CA7E3F,000600060A280621,17408,SP1QFE\n"); + append_str(&ptr, "sp1qfe\\winhttp.dll=3EC6F518114606CA59D4160322077437,000500010A280615,331776,SP1QFE\n"); + append_str(&ptr, "sp1qfe\\xpob2res.dll=DB83156B9F496F20D1EA70E4ABEC0166,000500010A280622,158720,SP1QFE\n"); WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL); CloseHandle(hf); @@ -91,14 +102,14 @@ static BOOL check_info_filename(PSP_INF_INFORMATION info, LPSTR test) DWORD size; BOOL ret = FALSE; - if (!pSetupQueryInfFileInformationA(info, 0, NULL, 0, &size)) + if (!SetupQueryInfFileInformationA(info, 0, NULL, 0, &size)) return FALSE; filename = HeapAlloc(GetProcessHeap(), 0, size); if (!filename) return FALSE; - pSetupQueryInfFileInformationA(info, 0, filename, size, &size); + SetupQueryInfFileInformationA(info, 0, filename, size, &size); if (!lstrcmpiA(test, filename)) ret = TRUE; @@ -107,12 +118,12 @@ static BOOL check_info_filename(PSP_INF_INFORMATION info, LPSTR test) return ret; } -static PSP_INF_INFORMATION alloc_inf_info(LPSTR filename, DWORD search, PDWORD size) +static PSP_INF_INFORMATION alloc_inf_info(LPCSTR filename, DWORD search, PDWORD size) { PSP_INF_INFORMATION info; BOOL ret; - ret = pSetupGetInfInformationA(filename, search, NULL, 0, size); + ret = SetupGetInfInformationA(filename, search, NULL, 0, size); if (!ret) return NULL; @@ -136,19 +147,19 @@ static void test_SetupGetInfInformation(void) /* try an invalid inf handle */ size = 0xdeadbeef; SetLastError(0xbeefcafe); - ret = pSetupGetInfInformationA(NULL, INFINFO_INF_SPEC_IS_HINF, NULL, 0, &size); + ret = SetupGetInfInformationA(NULL, INFINFO_INF_SPEC_IS_HINF, NULL, 0, &size); ok(ret == FALSE, "Expected SetupGetInfInformation to fail\n"); ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); ok(size == 0xdeadbeef, "Expected size to remain unchanged\n"); /* try an invalid inf filename */ size = 0xdeadbeef; SetLastError(0xbeefcafe); - ret = pSetupGetInfInformationA(NULL, INFINFO_INF_NAME_IS_ABSOLUTE, NULL, 0, &size); + ret = SetupGetInfInformationA(NULL, INFINFO_INF_NAME_IS_ABSOLUTE, NULL, 0, &size); ok(ret == FALSE, "Expected SetupGetInfInformation to fail\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); ok(size == 0xdeadbeef, "Expected size to remain unchanged\n"); create_inf_file(inf_filename); @@ -156,57 +167,69 @@ static void test_SetupGetInfInformation(void) /* try an invalid search flag */ size = 0xdeadbeef; SetLastError(0xbeefcafe); - ret = pSetupGetInfInformationA(inf_filename, -1, NULL, 0, &size); + ret = SetupGetInfInformationA(inf_filename, -1, NULL, 0, &size); ok(ret == FALSE, "Expected SetupGetInfInformation to fail\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); ok(size == 0xdeadbeef, "Expected size to remain unchanged\n"); /* try a nonexistent inf file */ size = 0xdeadbeef; SetLastError(0xbeefcafe); - ret = pSetupGetInfInformationA("idontexist", INFINFO_INF_NAME_IS_ABSOLUTE, NULL, 0, &size); + ret = SetupGetInfInformationA("idontexist", INFINFO_INF_NAME_IS_ABSOLUTE, NULL, 0, &size); ok(ret == FALSE, "Expected SetupGetInfInformation to fail\n"); ok(GetLastError() == ERROR_FILE_NOT_FOUND, - "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); ok(size == 0xdeadbeef, "Expected size to remain unchanged\n"); /* successfully open the inf file */ size = 0xdeadbeef; - ret = pSetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, NULL, 0, &size); + ret = SetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, NULL, 0, &size); ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n"); ok(size != 0xdeadbeef, "Expected a valid size on return\n"); - /* set ReturnBuffer to NULL and ReturnBufferSize to non-zero */ + /* set ReturnBuffer to NULL and ReturnBufferSize to non-zero value 'size' */ SetLastError(0xbeefcafe); - ret = pSetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, NULL, size, &size); + ret = SetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, NULL, size, &size); ok(ret == FALSE, "Expected SetupGetInfInformation to fail\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* set ReturnBuffer to NULL and ReturnBufferSize to non-zero value 'size-1' */ + ret = SetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, NULL, size-1, &size); + ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n"); + + /* some tests for behaviour with a NULL RequiredSize pointer */ + ret = SetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, NULL, 0, NULL); + ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n"); + ret = SetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, NULL, size - 1, NULL); + ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n"); + ret = SetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, NULL, size, NULL); + ok(ret == FALSE, "Expected SetupGetInfInformation to fail\n"); info = HeapAlloc(GetProcessHeap(), 0, size); /* try valid ReturnBuffer but too small size */ SetLastError(0xbeefcafe); - ret = pSetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, info, size - 1, &size); + ret = SetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, info, size - 1, &size); ok(ret == FALSE, "Expected SetupGetInfInformation to fail\n"); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); /* successfully get the inf information */ - ret = pSetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, info, size, &size); + ret = SetupGetInfInformationA(inf_filename, INFINFO_INF_NAME_IS_ABSOLUTE, info, size, &size); ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n"); ok(check_info_filename(info, inf_filename), "Expected returned filename to be equal\n"); HeapFree(GetProcessHeap(), 0, info); /* try the INFINFO_INF_SPEC_IS_HINF search flag */ - hinf = pSetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); + hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); info = alloc_inf_info(hinf, INFINFO_INF_SPEC_IS_HINF, &size); - ret = pSetupGetInfInformationA(hinf, INFINFO_INF_SPEC_IS_HINF, info, size, &size); + ret = SetupGetInfInformationA(hinf, INFINFO_INF_SPEC_IS_HINF, info, size, &size); ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n"); ok(check_info_filename(info, inf_filename), "Expected returned filename to be equal\n"); - pSetupCloseInfFile(hinf); + SetupCloseInfFile(hinf); lstrcpyA(inf_one, WIN_DIR); lstrcatA(inf_one, "\\inf\\"); @@ -222,7 +245,7 @@ static void test_SetupGetInfInformation(void) info = alloc_inf_info("test.inf", INFINFO_DEFAULT_SEARCH, &size); /* test the INFINFO_DEFAULT_SEARCH search flag */ - ret = pSetupGetInfInformationA("test.inf", INFINFO_DEFAULT_SEARCH, info, size, &size); + ret = SetupGetInfInformationA("test.inf", INFINFO_DEFAULT_SEARCH, info, size, &size); ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n"); ok(check_info_filename(info, inf_one), "Expected returned filename to be equal\n"); @@ -230,7 +253,7 @@ static void test_SetupGetInfInformation(void) info = alloc_inf_info("test.inf", INFINFO_REVERSE_DEFAULT_SEARCH, &size); /* test the INFINFO_REVERSE_DEFAULT_SEARCH search flag */ - ret = pSetupGetInfInformationA("test.inf", INFINFO_REVERSE_DEFAULT_SEARCH, info, size, &size); + ret = SetupGetInfInformationA("test.inf", INFINFO_REVERSE_DEFAULT_SEARCH, info, size, &size); ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n"); ok(check_info_filename(info, inf_two), "Expected returned filename to be equal\n"); @@ -239,10 +262,140 @@ static void test_SetupGetInfInformation(void) DeleteFileA(inf_two); } +static void test_SetupGetSourceFileLocation(void) +{ + char buffer[MAX_PATH] = "not empty", inf_filename[MAX_PATH]; + UINT source_id; + DWORD required, error; + HINF hinf; + BOOL ret; + + lstrcpyA(inf_filename, CURR_DIR); + lstrcatA(inf_filename, "\\"); + lstrcatA(inf_filename, "test.inf"); + + create_inf_file(inf_filename); + + hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "could not open inf file\n"); + + required = 0; + source_id = 0; + + ret = SetupGetSourceFileLocationA(hinf, NULL, "lanconf.exe", &source_id, buffer, sizeof(buffer), &required); + ok(ret, "SetupGetSourceFileLocation failed\n"); + + ok(required == 1, "unexpected required size: %d\n", required); + ok(source_id == 2, "unexpected source id: %d\n", source_id); + ok(!lstrcmpA("", buffer), "unexpected result string: %s\n", buffer); + + SetupCloseInfFile(hinf); + DeleteFileA(inf_filename); + + create_inf_file2(inf_filename); + + SetLastError(0xdeadbeef); + hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); + error = GetLastError(); + ok(hinf == INVALID_HANDLE_VALUE, "could open inf file\n"); + ok(error == ERROR_WRONG_INF_STYLE, "got wrong error: %d\n", error); + + hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_OLDNT, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "could not open inf file\n"); + + ret = SetupGetSourceFileLocationA(hinf, NULL, "", &source_id, buffer, sizeof(buffer), &required); + ok(!ret, "SetupGetSourceFileLocation succeeded\n"); + + SetupCloseInfFile(hinf); + DeleteFileA(inf_filename); +} + +static void test_SetupGetSourceInfo(void) +{ + char buffer[MAX_PATH], inf_filename[MAX_PATH]; + DWORD required; + HINF hinf; + BOOL ret; + + lstrcpyA(inf_filename, CURR_DIR); + lstrcatA(inf_filename, "\\"); + lstrcatA(inf_filename, "test.inf"); + + create_inf_file(inf_filename); + + hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "could not open inf file\n"); + + required = 0; + + ret = SetupGetSourceInfoA(hinf, 2, SRCINFO_PATH, buffer, sizeof(buffer), &required); + ok(ret, "SetupGetSourceInfoA failed\n"); + + ok(required == 1, "unexpected required size: %d\n", required); + ok(!lstrcmpA("", buffer), "unexpected result string: %s\n", buffer); + + required = 0; + buffer[0] = 0; + + ret = SetupGetSourceInfoA(hinf, 2, SRCINFO_TAGFILE, buffer, sizeof(buffer), &required); + ok(ret, "SetupGetSourceInfoA failed\n"); + + ok(required == 28, "unexpected required size: %d\n", required); + ok(!lstrcmpA("LANCOM\\LANtools\\lanconf.cab", buffer), "unexpected result string: %s\n", buffer); + + required = 0; + buffer[0] = 0; + + ret = SetupGetSourceInfoA(hinf, 2, SRCINFO_DESCRIPTION, buffer, sizeof(buffer), &required); + ok(ret, "SetupGetSourceInfoA failed\n"); + + ok(required == 19, "unexpected required size: %d\n", required); + ok(!lstrcmpA("LANCOM Software CD", buffer), "unexpected result string: %s\n", buffer); + + SetupCloseInfFile(hinf); + DeleteFileA(inf_filename); +} + +static void test_SetupGetTargetPath(void) +{ + char buffer[MAX_PATH], inf_filename[MAX_PATH]; + DWORD required; + HINF hinf; + INFCONTEXT ctx; + BOOL ret; + + lstrcpyA(inf_filename, CURR_DIR); + lstrcatA(inf_filename, "\\"); + lstrcatA(inf_filename, "test.inf"); + + create_inf_file(inf_filename); + + hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "could not open inf file\n"); + + ctx.Inf = hinf; + ctx.CurrentInf = hinf; + ctx.Section = 7; + ctx.Line = 0; + + required = 0; + + ret = SetupGetTargetPathA(hinf, &ctx, NULL, buffer, sizeof(buffer), &required); + ok(ret, "SetupGetTargetPathA failed\n"); + + ok(required == 10, "unexpected required size: %d\n", required); + ok(!lstrcmpiA("C:\\LANCOM", buffer), "unexpected result string: %s\n", buffer); + + SetupCloseInfFile(hinf); + DeleteFileA(inf_filename); +} + START_TEST(query) { - init_function_pointers(); get_directories(); test_SetupGetInfInformation(); + test_SetupGetSourceFileLocation(); + test_SetupGetSourceInfo(); + test_SetupGetTargetPath(); } diff --git a/rostests/winetests/setupapi/setupapi.rbuild b/rostests/winetests/setupapi/setupapi.rbuild index 9b4ab741170..11bc062bb00 100644 --- a/rostests/winetests/setupapi/setupapi.rbuild +++ b/rostests/winetests/setupapi/setupapi.rbuild @@ -1,3 +1,6 @@ + + + . @@ -5,10 +8,14 @@ kernel32 advapi32 setupapi + user32 devclass.c + devinst.c install.c + misc.c parser.c query.c stringtable.c testlist.c + diff --git a/rostests/winetests/setupapi/stringtable.c b/rostests/winetests/setupapi/stringtable.c index fab7a7f62d9..4eca3318553 100644 --- a/rostests/winetests/setupapi/stringtable.c +++ b/rostests/winetests/setupapi/stringtable.c @@ -17,7 +17,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -/* +/* * TODO: * Add test for StringTableStringFromIdEx */ @@ -33,6 +33,8 @@ #include "wine/test.h" +/* Flags for StringTableAddString and StringTableLookUpString */ +#define ST_CASE_SENSITIVE_COMPARE 0x00000001 static DWORD (WINAPI *pStringTableAddString)(HSTRING_TABLE, LPWSTR, DWORD); static VOID (WINAPI *pStringTableDestroy)(HSTRING_TABLE); @@ -54,9 +56,7 @@ HANDLE table, table2; /* Handles pointing to our tables */ static void load_it_up(void) { - hdll = LoadLibraryA("setupapi.dll"); - if (!hdll) - return; + hdll = GetModuleHandleA("setupapi.dll"); pStringTableInitialize = (void*)GetProcAddress(hdll, "StringTableInitialize"); if (!pStringTableInitialize) @@ -96,18 +96,18 @@ static void test_StringTableAddString(void) /* case insensitive */ hstring=pStringTableAddString(table,string,0); ok(hstring!=-1,"Failed to add string to String Table\n"); - + retval=pStringTableAddString(table,String,0); - ok(retval!=-1,"Failed to add String to String Table\n"); - ok(hstring==retval,"string handle %lx != String handle %lx in String Table\n", hstring, retval); - + ok(retval!=-1,"Failed to add String to String Table\n"); + ok(hstring==retval,"string handle %x != String handle %x in String Table\n", hstring, retval); + hfoo=pStringTableAddString(table,foo,0); - ok(hfoo!=-1,"Failed to add foo to String Table\n"); - ok(hfoo!=hstring,"foo and string share the same ID %lx in String Table\n", hfoo); - - /* case sensitive */ + ok(hfoo!=-1,"Failed to add foo to String Table\n"); + ok(hfoo!=hstring,"foo and string share the same ID %x in String Table\n", hfoo); + + /* case sensitive */ hString=pStringTableAddString(table,String,ST_CASE_SENSITIVE_COMPARE); - ok(hstring!=hString,"String handle and string share same ID %lx in Table\n", hstring); + ok(hstring!=hString,"String handle and string share same ID %x in Table\n", hstring); } static void test_StringTableDuplicate(void) @@ -117,41 +117,41 @@ static void test_StringTableDuplicate(void) } static void test_StringTableLookUpString(void) -{ +{ DWORD retval, retval2; - + /* case insensitive */ retval=pStringTableLookUpString(table,string,0); ok(retval!=-1,"Failed find string in String Table 1\n"); ok(retval==hstring, - "Lookup for string (%lx) does not match previous handle (%lx) in String Table 1\n", - retval, hstring); + "Lookup for string (%x) does not match previous handle (%x) in String Table 1\n", + retval, hstring); retval=pStringTableLookUpString(table2,string,0); ok(retval!=-1,"Failed find string in String Table 2\n"); - + retval=pStringTableLookUpString(table,String,0); ok(retval!=-1,"Failed find String in String Table 1\n"); retval=pStringTableLookUpString(table2,String,0); - ok(retval!=-1,"Failed find String in String Table 2\n"); - + ok(retval!=-1,"Failed find String in String Table 2\n"); + retval=pStringTableLookUpString(table,foo,0); - ok(retval!=-1,"Failed find foo in String Table 1\n"); + ok(retval!=-1,"Failed find foo in String Table 1\n"); ok(retval==hfoo, - "Lookup for foo (%lx) does not match previous handle (%lx) in String Table 1\n", - retval, hfoo); - + "Lookup for foo (%x) does not match previous handle (%x) in String Table 1\n", + retval, hfoo); + retval=pStringTableLookUpString(table2,foo,0); - ok(retval!=-1,"Failed find foo in String Table 2\n"); - + ok(retval!=-1,"Failed find foo in String Table 2\n"); + /* case sensitive */ retval=pStringTableLookUpString(table,string,ST_CASE_SENSITIVE_COMPARE); - retval2=pStringTableLookUpString(table,String,ST_CASE_SENSITIVE_COMPARE); + retval2=pStringTableLookUpString(table,String,ST_CASE_SENSITIVE_COMPARE); ok(retval!=retval2,"Lookup of string equals String in Table 1\n"); ok(retval2==hString, - "Lookup for String (%lx) does not match previous handle (%lx) in String Table 1\n", - retval, hString); + "Lookup for String (%x) does not match previous handle (%x) in String Table 1\n", + retval, hString); } static void test_StringTableStringFromId(void) @@ -162,7 +162,7 @@ static void test_StringTableStringFromId(void) /* correct */ string2=pStringTableStringFromId(table,pStringTableLookUpString(table,string,0)); ok(string2!=NULL,"Failed to look up string by ID from String Table\n"); - + result=lstrcmpiW(string, string2); ok(result==0,"StringID %p does not match requested StringID %p\n",string,string2); @@ -184,9 +184,7 @@ START_TEST(stringtable) test_StringTableLookUpString(); test_StringTableStringFromId(); - /* assume we can always distroy */ + /* assume we can always destroy */ pStringTableDestroy(table); pStringTableDestroy(table2); - - FreeLibrary(hdll); } diff --git a/rostests/winetests/setupapi/testlist.c b/rostests/winetests/setupapi/testlist.c index 77623f23a91..ae1785c428e 100644 --- a/rostests/winetests/setupapi/testlist.c +++ b/rostests/winetests/setupapi/testlist.c @@ -7,7 +7,9 @@ #include "wine/test.h" extern void func_devclass(void); +extern void func_devinst(void); extern void func_install(void); +extern void func_misc(void); extern void func_parser(void); extern void func_query(void); extern void func_stringtable(void); @@ -15,7 +17,9 @@ extern void func_stringtable(void); const struct test winetest_testlist[] = { { "devclass", func_devclass }, + { "devinst", func_devinst }, { "install", func_install }, + { "misc", func_misc }, { "parser", func_parser }, { "query", func_query }, { "stringtable", func_stringtable }, diff --git a/rostests/winetests/shlwapi/istream.c b/rostests/winetests/shlwapi/istream.c index 7172e31f764..ef7191ca4fb 100644 --- a/rostests/winetests/shlwapi/istream.c +++ b/rostests/winetests/shlwapi/istream.c @@ -76,35 +76,40 @@ static void test_IStream_invalid_operations(IStream * stream, DWORD mode) ret = stream->lpVtbl->Write(stream, NULL, 0, &count); if (mode == STGM_READ) - ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret); + ok(ret == STG_E_ACCESSDENIED /* XP */ || ret == S_OK /* 2000 */, + "expected STG_E_ACCESSDENIED or S_OK, got 0x%08x\n", ret); else ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); strcpy(data, "Hello"); ret = stream->lpVtbl->Write(stream, data, 5, NULL); if (mode == STGM_READ) - ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret); + ok(ret == STG_E_ACCESSDENIED /* XP */ || ret == S_OK /* 2000 */, + "expected STG_E_ACCESSDENIED or S_OK, got 0x%08x\n", ret); else ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); strcpy(data, "Hello"); ret = stream->lpVtbl->Write(stream, data, 0, NULL); if (mode == STGM_READ) - ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret); + ok(ret == STG_E_ACCESSDENIED /* XP */ || ret == S_OK /* 2000 */, + "expected STG_E_ACCESSDENIED or S_OK, got 0x%08x\n", ret); else ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); strcpy(data, "Hello"); ret = stream->lpVtbl->Write(stream, data, 0, &count); if (mode == STGM_READ) - ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret); + ok(ret == STG_E_ACCESSDENIED /* XP */ || ret == S_OK /* 2000 */, + "expected STG_E_ACCESSDENIED or S_OK, got 0x%08x\n", ret); else ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); strcpy(data, "Hello"); ret = stream->lpVtbl->Write(stream, data, 3, &count); if (mode == STGM_READ) - ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret); + ok(ret == STG_E_ACCESSDENIED /* XP */ || ret == S_OK /* 2000 */, + "expected STG_E_ACCESSDENIED or S_OK, got 0x%08x\n", ret); else ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); @@ -114,7 +119,8 @@ static void test_IStream_invalid_operations(IStream * stream, DWORD mode) ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); ret = IStream_Seek(stream, zero, 20, NULL); - ok(ret == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", ret); + ok(ret == E_INVALIDARG /* XP */ || ret == S_OK /* 2000 */, + "expected E_INVALIDARG or S_OK, got 0x%08x\n", ret); /* IStream::CopyTo */ @@ -166,7 +172,8 @@ static void test_IStream_invalid_operations(IStream * stream, DWORD mode) /* IStream::Stat */ ret = IStream_Stat(stream, NULL, 0); - ok(ret == STG_E_INVALIDPOINTER, "expected STG_E_INVALIDPOINTER, got 0x%08x\n", ret); + ok(ret == STG_E_INVALIDPOINTER /* XP */ || ret == E_NOTIMPL /* 2000 */, + "expected STG_E_INVALIDPOINTER or E_NOTIMPL, got 0x%08x\n", ret); /* IStream::Clone */ @@ -185,56 +192,52 @@ static void test_IStream_invalid_operations(IStream * stream, DWORD mode) } -static void test_SHCreateStreamOnFileA(DWORD mode) +static void test_SHCreateStreamOnFileA(DWORD mode, DWORD stgm) { IStream * stream; HRESULT ret; ULONG refcount; static const char * test_file = "c:\\test.txt"; - trace("SHCreateStreamOnFileA: testing mode %d\n", mode); + trace("SHCreateStreamOnFileA: testing mode %d, STGM flags %08x\n", mode, stgm); /* invalid arguments */ stream = NULL; - ret = (*pSHCreateStreamOnFileA)(NULL, mode, &stream); - todo_wine + ret = (*pSHCreateStreamOnFileA)(NULL, mode | stgm, &stream); ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); #if 0 /* This test crashes on WinXP SP2 */ - ret = (*pSHCreateStreamOnFileA)(test_file, mode, NULL); + ret = (*pSHCreateStreamOnFileA)(test_file, mode | stgm, NULL); ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); #endif stream = NULL; - ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CONVERT, &stream); + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CONVERT | stgm, &stream); ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); stream = NULL; - ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_DELETEONRELEASE, &stream); + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_DELETEONRELEASE | stgm, &stream); ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); stream = NULL; - ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_TRANSACTED, &stream); + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_TRANSACTED | stgm, &stream); ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); /* file does not exist */ stream = NULL; - ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_FAILIFTHERE, &stream); - todo_wine + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_FAILIFTHERE | stgm, &stream); ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); stream = NULL; - ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CREATE, &stream); - todo_wine + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CREATE | stgm, &stream); ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n"); if (stream) { @@ -249,10 +252,8 @@ static void test_SHCreateStreamOnFileA(DWORD mode) /* file exists */ stream = NULL; - ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_FAILIFTHERE, &stream); - todo_wine + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_FAILIFTHERE | stgm, &stream); ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n"); if (stream) { @@ -263,10 +264,8 @@ static void test_SHCreateStreamOnFileA(DWORD mode) } stream = NULL; - ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CREATE, &stream); - todo_wine + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CREATE | stgm, &stream); ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n"); if (stream) { @@ -280,57 +279,54 @@ static void test_SHCreateStreamOnFileA(DWORD mode) } -static void test_SHCreateStreamOnFileW(DWORD mode) +static void test_SHCreateStreamOnFileW(DWORD mode, DWORD stgm) { IStream * stream; HRESULT ret; ULONG refcount; static const WCHAR test_file[] = { 'c', ':', '\\', 't', 'e', 's', 't', '.', 't', 'x', 't', '\0' }; - trace("SHCreateStreamOnFileW: testing mode %d\n", mode); + trace("SHCreateStreamOnFileW: testing mode %d, STGM flags %08x\n", mode, stgm); /* invalid arguments */ stream = NULL; - ret = (*pSHCreateStreamOnFileW)(NULL, mode, &stream); + ret = (*pSHCreateStreamOnFileW)(NULL, mode | stgm, &stream); ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* XP */ ret == E_INVALIDARG /* Vista */, "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); #if 0 /* This test crashes on WinXP SP2 */ - ret = (*pSHCreateStreamOnFileW)(test_file, mode, NULL); + ret = (*pSHCreateStreamOnFileW)(test_file, mode | stgm, NULL); ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); #endif stream = NULL; - ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CONVERT, &stream); + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CONVERT | stgm, &stream); ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); stream = NULL; - ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_DELETEONRELEASE, &stream); + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_DELETEONRELEASE | stgm, &stream); ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); stream = NULL; - ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_TRANSACTED, &stream); + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_TRANSACTED | stgm, &stream); ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); /* file does not exist */ stream = NULL; - ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_FAILIFTHERE, &stream); - todo_wine + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_FAILIFTHERE | stgm, &stream); ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); stream = NULL; - ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CREATE, &stream); - todo_wine + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CREATE | stgm, &stream); ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n"); if (stream) { @@ -345,10 +341,8 @@ static void test_SHCreateStreamOnFileW(DWORD mode) /* file exists */ stream = NULL; - ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_FAILIFTHERE, &stream); - todo_wine + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_FAILIFTHERE | stgm, &stream); ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n"); if (stream) { @@ -359,10 +353,8 @@ static void test_SHCreateStreamOnFileW(DWORD mode) } stream = NULL; - ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CREATE, &stream); - todo_wine + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CREATE | stgm, &stream); ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n"); if (stream) { @@ -397,7 +389,6 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) stream = NULL; ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, template, &stream); - todo_wine ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); @@ -419,16 +410,13 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) return; } } else { - todo_wine ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); } ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); stream = NULL; ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, TRUE, NULL, &stream); - todo_wine ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); if (stream) { @@ -442,9 +430,7 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) stream = NULL; ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream); - todo_wine ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); if (stream) { @@ -458,9 +444,7 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) stream = NULL; ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream); - todo_wine ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); if (stream) { @@ -476,9 +460,7 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) stream = NULL; ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, FALSE, NULL, &stream); - todo_wine ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); if (stream) { @@ -490,15 +472,12 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) stream = NULL; ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, TRUE, NULL, &stream); - todo_wine ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); stream = NULL; ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream); - todo_wine ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); if (stream) { @@ -510,9 +489,7 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) stream = NULL; ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream); - todo_wine ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); - todo_wine ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); if (stream) { @@ -522,7 +499,6 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); } - todo_wine ok(DeleteFileW(test_file), "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", GetLastError()); } @@ -535,6 +511,14 @@ START_TEST(istream) STGM_READWRITE }; + static const DWORD stgm_sharing[] = { + 0, + STGM_SHARE_DENY_NONE, + STGM_SHARE_DENY_READ, + STGM_SHARE_DENY_WRITE, + STGM_SHARE_EXCLUSIVE + }; + static const DWORD stgm_flags[] = { 0, STGM_CONVERT, @@ -545,7 +529,7 @@ START_TEST(istream) STGM_TRANSACTED | STGM_CONVERT | STGM_DELETEONRELEASE }; - int i, j; + int i, j, k; hShlwapi = GetModuleHandleA("shlwapi.dll"); @@ -563,15 +547,17 @@ START_TEST(istream) skip("SHCreateStreamOnFileEx not found.\n"); for (i = 0; i != sizeof(stgm_access)/sizeof(stgm_access[0]); i++) { - if (pSHCreateStreamOnFileA) - test_SHCreateStreamOnFileA(stgm_access[i]); + for (j = 0; j != sizeof(stgm_sharing)/sizeof(stgm_sharing[0]); j ++) { + if (pSHCreateStreamOnFileA) + test_SHCreateStreamOnFileA(stgm_access[i], stgm_sharing[j]); - if (pSHCreateStreamOnFileW) - test_SHCreateStreamOnFileW(stgm_access[i]); + if (pSHCreateStreamOnFileW) + test_SHCreateStreamOnFileW(stgm_access[i], stgm_sharing[j]); - if (pSHCreateStreamOnFileEx) { - for (j = 0; j != sizeof(stgm_flags)/sizeof(stgm_flags[0]); j++) - test_SHCreateStreamOnFileEx(stgm_access[i], stgm_flags[j]); + if (pSHCreateStreamOnFileEx) { + for (k = 0; k != sizeof(stgm_flags)/sizeof(stgm_flags[0]); k++) + test_SHCreateStreamOnFileEx(stgm_access[i], stgm_sharing[j] | stgm_flags[k]); + } } } } diff --git a/rostests/winetests/shlwapi/shlwapi.rbuild b/rostests/winetests/shlwapi/shlwapi.rbuild index f6d735e0b63..29025301b71 100644 --- a/rostests/winetests/shlwapi/shlwapi.rbuild +++ b/rostests/winetests/shlwapi/shlwapi.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/shlwapi/url.c b/rostests/winetests/shlwapi/url.c index 2d63a216f61..cd7a5f20286 100644 --- a/rostests/winetests/shlwapi/url.c +++ b/rostests/winetests/shlwapi/url.c @@ -45,49 +45,61 @@ typedef struct _TEST_URL_CANONICALIZE { DWORD flags; HRESULT expectret; const char *expecturl; + BOOL todo; } TEST_URL_CANONICALIZE; static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = { - /*FIXME {"http://www.winehq.org/tests/../tests/../..", 0, S_OK, "http://www.winehq.org/"},*/ - {"http://www.winehq.org/tests/../tests", 0, S_OK, "http://www.winehq.org/tests"}, - {"http://www.winehq.org/tests\n", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests"}, - {"http://www.winehq.org/tests\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests"}, - {"http://www.winehq.org/tests\r", 0, S_OK, "http://www.winehq.org/tests"}, - {"http://www.winehq.org/tests\r", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests"}, - {"http://www.winehq.org/tests/../tests/", 0, S_OK, "http://www.winehq.org/tests/"}, - {"http://www.winehq.org/tests/../tests/..", 0, S_OK, "http://www.winehq.org/"}, - {"http://www.winehq.org/tests/../tests/../", 0, S_OK, "http://www.winehq.org/"}, - {"http://www.winehq.org/tests/..", 0, S_OK, "http://www.winehq.org/"}, - {"http://www.winehq.org/tests/../", 0, S_OK, "http://www.winehq.org/"}, - {"http://www.winehq.org/tests/..?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y"}, - {"http://www.winehq.org/tests/../?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y"}, - {"http://www.winehq.org/tests/..#example", 0, S_OK, "http://www.winehq.org/#example"}, - {"http://www.winehq.org/tests/../#example", 0, S_OK, "http://www.winehq.org/#example"}, - {"http://www.winehq.org/tests\\../#example", 0, S_OK, "http://www.winehq.org/#example"}, - {"http://www.winehq.org/tests/..\\#example", 0, S_OK, "http://www.winehq.org/#example"}, - {"http://www.winehq.org\\tests/../#example", 0, S_OK, "http://www.winehq.org/#example"}, - {"http://www.winehq.org/tests/../#example", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../#example"}, - {"http://www.winehq.org/tests/foo bar", URL_ESCAPE_SPACES_ONLY| URL_DONT_ESCAPE_EXTRA_INFO , S_OK, "http://www.winehq.org/tests/foo%20bar"}, - {"http://www.winehq.org/tests/foo%20bar", URL_UNESCAPE , S_OK, "http://www.winehq.org/tests/foo bar"}, - {"file:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar"}, - {"file:///c:/tests\\foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar"}, - {"file:///c:/tests/foo%20bar", 0, S_OK, "file:///c:/tests/foo%20bar"}, - {"file:///c:/tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"}, - {"file://c:/tests/../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"}, - {"file://c:/tests\\../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"}, - {"file://c:/tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"}, - {"file:///c://tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\\\tests\\foo bar"}, - {"file:///c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo bar"}, - {"file:///c:\\tests\\foo bar", URL_DONT_SIMPLIFY, S_OK, "file:///c:/tests/foo bar"}, - {"http://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/site/about"}, - {"file_://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "file_://www.winehq.org/site/about"}, - {"c:\\dir\\file", 0, S_OK, "file:///c:/dir/file"}, - {"file:///c:\\dir\\file", 0, S_OK, "file:///c:/dir/file"}, - {"c:dir\\file", 0, S_OK, "file:///c:dir/file"}, - {"c:\\tests\\foo bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"}, - {"c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo%20bar"}, - {"A", 0, S_OK, "A"}, - {"", 0, S_OK, ""} + {"http://www.winehq.org/tests/../tests/../..", 0, S_OK, "http://www.winehq.org/", TRUE}, + {"http://www.winehq.org/tests/../tests", 0, S_OK, "http://www.winehq.org/tests", FALSE}, + {"http://www.winehq.org/tests\n", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests", FALSE}, + {"http://www.winehq.org/tests\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests", FALSE}, + {"http://www.winehq.org/tests\r", 0, S_OK, "http://www.winehq.org/tests", FALSE}, + {"http://www.winehq.org/tests\r", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests", FALSE}, + {"http://www.winehq.org/tests/../tests/", 0, S_OK, "http://www.winehq.org/tests/", FALSE}, + {"http://www.winehq.org/tests/../tests/..", 0, S_OK, "http://www.winehq.org/", FALSE}, + {"http://www.winehq.org/tests/../tests/../", 0, S_OK, "http://www.winehq.org/", FALSE}, + {"http://www.winehq.org/tests/..", 0, S_OK, "http://www.winehq.org/", FALSE}, + {"http://www.winehq.org/tests/../", 0, S_OK, "http://www.winehq.org/", FALSE}, + {"http://www.winehq.org/tests/..?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y", FALSE}, + {"http://www.winehq.org/tests/../?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y", FALSE}, + {"http://www.winehq.org/tests/..#example", 0, S_OK, "http://www.winehq.org/#example", FALSE}, + {"http://www.winehq.org/tests/../#example", 0, S_OK, "http://www.winehq.org/#example", FALSE}, + {"http://www.winehq.org/tests\\../#example", 0, S_OK, "http://www.winehq.org/#example", FALSE}, + {"http://www.winehq.org/tests/..\\#example", 0, S_OK, "http://www.winehq.org/#example", FALSE}, + {"http://www.winehq.org\\tests/../#example", 0, S_OK, "http://www.winehq.org/#example", FALSE}, + {"http://www.winehq.org/tests/../#example", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../#example", FALSE}, + {"http://www.winehq.org/tests/foo bar", URL_ESCAPE_SPACES_ONLY| URL_DONT_ESCAPE_EXTRA_INFO , S_OK, "http://www.winehq.org/tests/foo%20bar", FALSE}, + {"http://www.winehq.org/tests/foo%20bar", URL_UNESCAPE , S_OK, "http://www.winehq.org/tests/foo bar", FALSE}, + {"file:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar", FALSE}, + {"file:///c:/tests\\foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar", FALSE}, + {"file:///c:/tests/foo%20bar", 0, S_OK, "file:///c:/tests/foo%20bar", FALSE}, + {"file:///c:/tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar", FALSE}, + {"file://c:/tests/../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar", FALSE}, + {"file://c:/tests\\../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar", FALSE}, + {"file://c:/tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar", FALSE}, + {"file:///c://tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\\\tests\\foo bar", FALSE}, + {"file:///c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo bar", FALSE}, + {"file:///c:\\tests\\foo bar", URL_DONT_SIMPLIFY, S_OK, "file:///c:/tests/foo bar", FALSE}, + {"http://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/site/about", FALSE}, + {"file_://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "file_://www.winehq.org/site/about", FALSE}, + {"c:\\dir\\file", 0, S_OK, "file:///c:/dir/file", FALSE}, + {"file:///c:\\dir\\file", 0, S_OK, "file:///c:/dir/file", FALSE}, + {"c:dir\\file", 0, S_OK, "file:///c:dir/file", FALSE}, + {"c:\\tests\\foo bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar", FALSE}, + {"c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo%20bar", FALSE}, + {"res:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "res:///c:/tests/foo bar", FALSE}, + {"res:///c:/tests\\foo%20bar", URL_UNESCAPE , S_OK, "res:///c:/tests\\foo bar", TRUE}, + {"res:///c:/tests/foo%20bar", 0, S_OK, "res:///c:/tests/foo%20bar", FALSE}, + {"res:///c:/tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "res:///c:/tests/foo%20bar", TRUE}, + {"res://c:/tests/../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "res://c:/tests/foo%20bar", TRUE}, + {"res://c:/tests\\../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "res://c:/tests/foo%20bar", TRUE}, + {"res://c:/tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "res://c:/tests/foo%20bar", TRUE}, + {"res:///c://tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "res:///c://tests/foo%20bar", TRUE}, + {"res:///c:\\tests\\foo bar", 0, S_OK, "res:///c:\\tests\\foo bar", TRUE}, + {"res:///c:\\tests\\foo bar", URL_DONT_SIMPLIFY, S_OK, "res:///c:\\tests\\foo bar", TRUE}, + {"A", 0, S_OK, "A", FALSE}, + {"/uri-res/N2R?urn:sha1:B3K", URL_DONT_ESCAPE_EXTRA_INFO | URL_WININET_COMPATIBILITY /*0x82000000*/, S_OK, "/uri-res/N2R?urn:sha1:B3K", TRUE} /*LimeWire online installer calls this*/, + {"", 0, S_OK, "", FALSE} }; /* ################ */ @@ -425,7 +437,7 @@ static void test_url_escape(const char *szUrl, DWORD dwFlags, HRESULT dwExpectRe } -static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl) +static void test_url_canonicalize(int index, const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl, BOOL todo) { CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH]; WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH]; @@ -436,15 +448,19 @@ static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwEx DWORD dwSize; dwSize = INTERNET_MAX_URL_LENGTH; - ok(UrlCanonicalizeA(szUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer\n"); - ok(UrlCanonicalizeA(szUrl, szReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeA didn't return 0x%08x\n", dwExpectReturn); - ok(strcmp(szReturnUrl,szExpectUrl)==0, "UrlCanonicalizeA dwFlags 0x%08x Expected \"%s\", but got \"%s\"\n", dwFlags, szExpectUrl, szReturnUrl); + ok(UrlCanonicalizeA(szUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer, index %d\n", index); + ok(UrlCanonicalizeA(szUrl, szReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeA didn't return 0x%08x, index %d\n", dwExpectReturn, index); + if (todo) + todo_wine + ok(strcmp(szReturnUrl,szExpectUrl)==0, "UrlCanonicalizeA dwFlags 0x%08x url '%s' Expected \"%s\", but got \"%s\", index %d\n", dwFlags, szUrl, szExpectUrl, szReturnUrl, index); + else + ok(strcmp(szReturnUrl,szExpectUrl)==0, "UrlCanonicalizeA dwFlags 0x%08x url '%s' Expected \"%s\", but got \"%s\", index %d\n", dwFlags, szUrl, szExpectUrl, szReturnUrl, index); dwSize = INTERNET_MAX_URL_LENGTH; - ok(UrlCanonicalizeW(wszUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer\n"); - ok(UrlCanonicalizeW(wszUrl, wszReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeW didn't return 0x%08x\n", dwExpectReturn); + ok(UrlCanonicalizeW(wszUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer, index %d\n", index); + ok(UrlCanonicalizeW(wszUrl, wszReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeW didn't return 0x%08x, index %d\n", dwExpectReturn, index); wszConvertedUrl = GetWideString(szReturnUrl); - ok(lstrcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCanonicalize!\n"); + ok(lstrcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCanonicalize, index %d!\n", index); FreeWideString(wszConvertedUrl); @@ -545,19 +561,10 @@ static void test_UrlCanonicalizeA(void) /* test url-modification */ for(i=0; i - + . 0x600 0x600 diff --git a/rostests/winetests/usp10/usp10.c b/rostests/winetests/usp10/usp10.c index b0b50286cf3..0812f1ab52c 100644 --- a/rostests/winetests/usp10/usp10.c +++ b/rostests/winetests/usp10/usp10.c @@ -23,24 +23,60 @@ * and filtering characters and bi-directional text with custom line breaks. */ -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include - +#include #include -#include -#include "usp10.h" -#include "wine/test.h" -#include "wine/windef.h" -BOOL WINAPI ShowWindow(HWND,int); +#include +#include +#include +#include +#include +#include +#include + +static void test_ScriptShape(HDC hdc) +{ + static const WCHAR test1[] = {'t', 'e', 's', 't',0}; + BOOL ret; + HRESULT hr; + SCRIPT_CACHE sc = NULL; + WORD glyphs[4]; + SCRIPT_VISATTR attrs[4]; + SCRIPT_ITEM items[2]; + int nb, widths[4]; + + hr = ScriptItemize(NULL, 4, 2, NULL, NULL, items, NULL); + ok(hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG not %08x\n", hr); + + hr = ScriptItemize(test1, 4, 2, NULL, NULL, NULL, NULL); + ok(hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG not %08x\n", hr); + + hr = ScriptItemize(test1, 4, 2, NULL, NULL, items, NULL); + ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr); + ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n"); + + hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, NULL, &nb); + ok(hr == E_INVALIDARG, "ScriptShape should return E_INVALIDARG not %08x\n", hr); + + hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, NULL); + ok(hr == E_INVALIDARG, "ScriptShape should return E_INVALIDARG not %08x\n", hr); + + hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb); + ok(!hr, "ScriptShape should return S_OK not %08x\n", hr); + ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n"); + + hr = ScriptPlace(hdc, &sc, glyphs, 4, NULL, &items[0].a, widths, NULL, NULL); + ok(hr == E_INVALIDARG, "ScriptPlace should return E_INVALIDARG not %08x\n", hr); + + hr = ScriptPlace(hdc, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, NULL); + ok(!hr, "ScriptPlace should return S_OK not %08x\n", hr); + ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n"); + + ret = ExtTextOutW(hdc, 1, 1, 0, NULL, glyphs, 4, widths); + ok(ret, "ExtTextOutW should return TRUE\n"); + + ScriptFreeCache(&sc); +} static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256]) { @@ -52,11 +88,11 @@ static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256 int cMaxItems; SCRIPT_ITEM pItem[255]; int pcItems; - WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; - WCHAR TestItem2[] = {'T', 'e', 's', 't', 'b', 0}; - WCHAR TestItem3[] = {'T', 'e', 's', 't', 'c',' ','1','2','3',' ',' ','e','n','d',0}; + WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; + WCHAR TestItem2[] = {'T', 'e', 's', 't', 'b', 0}; + WCHAR TestItem3[] = {'T', 'e', 's', 't', 'c',' ','1','2','3',' ',' ','e','n','d',0}; WCHAR TestItem4[] = {'T', 'e', 's', 't', 'c',' ',0x0684,0x0694,0x06a4,' ',' ','e','n','d',0}; - WCHAR TestItem5[] = {0x0684,'T','e','s','t','c',' ',0x0684,0x0694,0x06a4,' ',' ','e','n','d',0}; + WCHAR TestItem5[] = {0x0684,'T','e','s','t','c',' ',0x0684,0x0694,0x06a4,' ',' ','e','n','d',0}; SCRIPT_CACHE psc; int cChars; @@ -76,7 +112,7 @@ static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256 * by checking a known value in the table */ hr = ScriptGetProperties(&ppSp, &iMaxProps); trace("number of script properties %d\n", iMaxProps); - ok (iMaxProps > 0, "Number of scripts returned should not be 0\n"); + ok (iMaxProps > 0, "Number of scripts returned should not be 0\n"); if (iMaxProps > 0) ok( ppSp[5]->langid == 9, "Langid[5] not = to 9\n"); /* Check a known value to ensure */ /* ptrs work */ @@ -160,7 +196,7 @@ static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256 cMaxItems = 255; hr = ScriptItemize(TestItem2, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems); ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr); - /* This test is for the intertrim operation of ScriptItemize where only one SCRIPT_ITEM is * + /* This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is * * returned. */ ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars, "Start pos not = 0 (%d) or end pos not = %d (%d)\n", @@ -241,12 +277,12 @@ static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256 /* * This test is for when the first unicode character requires bidi support - */ + */ cInChars = (sizeof(TestItem5)-1)/sizeof(WCHAR); hr = ScriptItemize(TestItem5, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems); ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr); ok (pcItems == 4, "There should have been 4 items, found %d\n", pcItems); - ok (pItem[0].a.s.uBidiLevel == 1, "The first character should have been bidi=1 not %d\n", + ok (pItem[0].a.s.uBidiLevel == 1, "The first character should have been bidi=1 not %d\n", pItem[0].a.s.uBidiLevel); } @@ -257,7 +293,7 @@ static void test_ScriptGetCMap(HDC hdc, unsigned short pwOutGlyphs[256]) int cInChars; int cChars; unsigned short pwOutGlyphs3[256]; - WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; + WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; DWORD dwFlags; int cnt; @@ -287,6 +323,7 @@ static void test_ScriptGetCMap(HDC hdc, unsigned short pwOutGlyphs[256]) ok( hr == S_OK, "ScriptGetCMap(NULL,&psc,NULL,0,0,NULL), expected S_OK, " "got %08x\n", hr); ok( psc != NULL, "ScritpGetCMap expected psc to be not NULL\n"); + ScriptFreeCache( &psc); /* Set psc to NULL, to be able to check if a pointer is returned in psc */ psc = NULL; @@ -300,7 +337,7 @@ static void test_ScriptGetCMap(HDC hdc, unsigned short pwOutGlyphs[256]) for (cnt=0; cnt < cChars && pwOutGlyphs[cnt] == pwOutGlyphs3[cnt]; cnt++) {} ok (cnt == cInChars, "Translation not correct. WCHAR %d - %04x != %04x\n", cnt, pwOutGlyphs[cnt], pwOutGlyphs3[cnt]); - + hr = ScriptFreeCache( &psc); ok (!psc, "psc is not null after ScriptFreeCache\n"); @@ -344,10 +381,11 @@ static void test_ScriptGetFontProperties(HDC hdc) ok( hr == E_INVALIDARG, "(hdc,&psc,NULL), expected E_INVALIDARG, got %08x\n", hr); ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc); - /* Pass an uninitialized sfp */ + /* Pass an invalid sfp */ psc = NULL; + sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES) - 1; hr = ScriptGetFontProperties(hdc,&psc,&sfp); - ok( hr == E_INVALIDARG, "(hdc,&psc,&sfp) partly uninitialized, expected E_INVALIDARG, got %08x\n", hr); + ok( hr == E_INVALIDARG, "(hdc,&psc,&sfp) invalid, expected E_INVALIDARG, got %08x\n", hr); ok( psc != NULL, "Expected a pointer in psc, got NULL\n"); ScriptFreeCache(&psc); ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc); @@ -377,7 +415,7 @@ static void test_ScriptTextOut(HDC hdc) int cMaxItems; SCRIPT_ITEM pItem[255]; int pcItems; - WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; + WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; SCRIPT_CACHE psc; int cChars; @@ -460,7 +498,7 @@ static void test_ScriptTextOut(HDC hdc) hr = ScriptTextOut(hdc, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs, piAdvance, NULL, pGoffset); ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr); - ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n"); + ok (psc == NULL, "psc should be null\n"); /* Test Rect Rgn is acceptable */ rect.top = 10; @@ -470,7 +508,7 @@ static void test_ScriptTextOut(HDC hdc) hr = ScriptTextOut(hdc, &psc, 0, 0, 0, &rect, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs, piAdvance, NULL, pGoffset); ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr); - ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n"); + ok (psc == NULL, "psc should be null\n"); iCP = 1; hr = ScriptCPtoX(iCP, fTrailing, cChars, pcGlyphs, (const WORD *) &pwLogClust, @@ -488,6 +526,93 @@ static void test_ScriptTextOut(HDC hdc) } } +static void test_ScriptTextOut2(HDC hdc) +{ +/* Intent is to validate that the HDC passed into ScriptTextOut is + * used instead of the (possibly) invalid cached one + */ + HRESULT hr; + + HDC hdc1, hdc2; + int cInChars; + int cMaxItems; + SCRIPT_ITEM pItem[255]; + int pcItems; + WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; + + SCRIPT_CACHE psc; + int cChars; + int cMaxGlyphs; + unsigned short pwOutGlyphs1[256]; + WORD pwLogClust[256]; + SCRIPT_VISATTR psva[256]; + int pcGlyphs; + int piAdvance[256]; + GOFFSET pGoffset[256]; + ABC pABC[256]; + + /* Create an extra DC that will be used until the ScriptTextOut */ + hdc1 = CreateCompatibleDC(hdc); + ok (hdc1 != 0, "CreateCompatibleDC failed to create a DC\n"); + hdc2 = CreateCompatibleDC(hdc); + ok (hdc2 != 0, "CreateCompatibleDC failed to create a DC\n"); + + /* This is a valid test that will cause parsing to take place */ + cInChars = 5; + cMaxItems = 255; + hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems); + ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr); + /* This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is * + * returned. */ + ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n"); + if (pcItems > 0) + ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars, + "Start pos not = 0 (%d) or end pos not = %d (%d)\n", + pItem[0].iCharPos, cInChars, pItem[1].iCharPos); + + /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue + * ie. ScriptItemize has succeeded and that pItem has been set */ + cInChars = 5; + cMaxItems = 255; + if (hr == 0) { + psc = NULL; /* must be null on first call */ + cChars = cInChars; + cMaxGlyphs = cInChars; + cMaxGlyphs = 256; + hr = ScriptShape(hdc2, &psc, TestItem1, cChars, + cMaxGlyphs, &pItem[0].a, + pwOutGlyphs1, pwLogClust, psva, &pcGlyphs); + ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr); + ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n"); + ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs); + if (hr ==0) { + /* Note hdc is needed as glyph info is not yet in psc */ + hr = ScriptPlace(hdc2, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance, + pGoffset, pABC); + ok (hr == 0, "Should return 0 not (%08x)\n", hr); + + /* key part!!! cached dc is being deleted */ + hr = DeleteDC(hdc2); + ok(hr == 1, "DeleteDC should return 1 not %08x\n", hr); + + /* At this point the cached hdc (hdc2) has been destroyed, + * however, we are passing in a *real* hdc (the original hdc). + * The text should be written to that DC + */ + hr = ScriptTextOut(hdc1, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs, + piAdvance, NULL, pGoffset); + ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr); + ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n"); + + DeleteDC(hdc1); + + /* Clean up and go */ + ScriptFreeCache(&psc); + ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc); + } + } +} + static void test_ScriptXtoX(void) /**************************************************************************************** * This routine tests the ScriptXtoCP and ScriptCPtoX functions using static variables * @@ -572,7 +697,7 @@ static void test_ScriptXtoX(void) cGlyphs = 10; hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX); ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr); - ok(piX == 1171, "iCP=%d should return piX=1171 not %d\n", iCP, piX); + ok(piX == 1171, "iCP=%d should return piX=1171 not %d\n", iCP, piX); iCP=6; fTrailing = FALSE; cChars = 10; @@ -593,7 +718,7 @@ static void test_ScriptXtoX(void) cGlyphs = 10; hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX); ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr); - ok(piX == 1953, "iCP=%d should return piX=1953 not %d\n", iCP, piX); + ok(piX == 1953, "iCP=%d should return piX=1953 not %d\n", iCP, piX); } @@ -622,15 +747,16 @@ static void test_ScriptString(HDC hdc) const BYTE InClass = 0; SCRIPT_STRING_ANALYSIS ssa = NULL; - int X = 10; + int X = 10; int Y = 100; - UINT Options = 0; - const RECT rc = {0, 50, 100, 100}; + UINT Options = 0; + const RECT rc = {0, 50, 100, 100}; int MinSel = 0; int MaxSel = 0; BOOL Disabled = FALSE; const int *clip_len; - UINT *order, i; + int i; + UINT *order; Charset = -1; /* this flag indicates unicode input */ @@ -645,6 +771,7 @@ static void test_ScriptString(HDC hdc) ReqWidth, &Control, &State, Dx, &Tabdef, &InClass, &ssa); ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr); + ScriptStringFree(&ssa); /* test makes sure that a call with a valid pssa still works */ hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags, @@ -705,7 +832,7 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc) BOOL fTrailing; /* Test with hdc, this should be a valid test - * Here we generrate an SCRIPT_STRING_ANALYSIS that will be used as input to the + * Here we generate an SCRIPT_STRING_ANALYSIS that will be used as input to the * following character positions to X and X to character position functions. */ hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags, @@ -733,7 +860,7 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc) hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing); ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr); ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X); - ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", + ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", iTrailing, X); fTrailing = TRUE; hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X); @@ -747,7 +874,7 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc) * again works */ ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X); - ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", + ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", iTrailing, X); } /* @@ -762,13 +889,13 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc) hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing); ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr); ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X); - ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n", + ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n", iTrailing, X); /* * This test is to check that if the X position is just outside the trailing edge of the * character then iTrailing will indicate the leading edge, ie. FALSE, and Ch will indicate - * the next character, ie. Cp + 1 + * the next character, ie. Cp + 1 */ fTrailing = TRUE; Cp = 3; @@ -778,13 +905,13 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc) hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing); ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr); ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X); - ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", + ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", iTrailing, X); /* * This test is to check that if the X position is just outside the leading edge of the * character then iTrailing will indicate the trailing edge, ie. TRUE, and Ch will indicate - * the next character down , ie. Cp - 1 + * the next character down , ie. Cp - 1 */ fTrailing = FALSE; Cp = 3; @@ -794,11 +921,11 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc) hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing); ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr); ok(Cp - 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp - 1, Ch, X); - ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n", + ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n", iTrailing, X); /* - * Cleanup the the SSA for the next round of tests + * Cleanup the SSA for the next round of tests */ hr = ScriptStringFree(&ssa); ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr); @@ -814,11 +941,11 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc) /* * When ScriptStringCPtoX is called with a character position Cp that exceeds the - * string length, return E_INVALIDARG. This also invalidates the ssa so a + * string length, return E_INVALIDARG. This also invalidates the ssa so a * ScriptStringFree should also fail. */ fTrailing = FALSE; - Cp = String_len + 1; + Cp = String_len + 1; hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X); ok(hr == E_INVALIDARG, "ScriptStringCPtoX should return E_INVALIDARG not %08x\n", hr); @@ -826,7 +953,9 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc) /* * ScriptStringCPtoX should free ssa, hence ScriptStringFree should fail */ - ok(hr == E_INVALIDARG, "ScriptStringFree should return E_INVALIDARG not %08x\n", hr); + ok(hr == E_INVALIDARG || + hr == E_FAIL, /* win2k3 */ + "ScriptStringFree should return E_INVALIDARG or E_FAIL not %08x\n", hr); } } @@ -849,8 +978,9 @@ static void test_ScriptCacheGetHeight(HDC hdc) hr = ScriptCacheGetHeight(hdc, &sc, &height); ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); - ok(height > 0, "expected height > 0\n"); + + ScriptFreeCache(&sc); } static void test_ScriptGetGlyphABCWidth(HDC hdc) @@ -872,6 +1002,8 @@ static void test_ScriptGetGlyphABCWidth(HDC hdc) hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', &abc); ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); + + ScriptFreeCache(&sc); } static void test_ScriptLayout(void) @@ -1216,15 +1348,14 @@ START_TEST(usp10) * to set up for the tests. */ hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100, 0, 0, 0, NULL); - // FIXME do wine assert - //assert(hwnd != 0); + assert(hwnd != 0); ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); hdc = GetDC(hwnd); /* We now have a hdc */ ok( hdc != NULL, "HDC failed to be created %p\n", hdc); - memset(&lf, 0, sizeof(HFONT)); + memset(&lf, 0, sizeof(LOGFONTA)); lstrcpyA(lf.lfFaceName, "Symbol"); lf.lfHeight = 10; lf.lfWeight = 3; @@ -1236,9 +1367,11 @@ START_TEST(usp10) test_ScriptGetCMap(hdc, pwOutGlyphs); test_ScriptCacheGetHeight(hdc); test_ScriptGetGlyphABCWidth(hdc); + test_ScriptShape(hdc); test_ScriptGetFontProperties(hdc); test_ScriptTextOut(hdc); + test_ScriptTextOut2(hdc); test_ScriptXtoX(); test_ScriptString(hdc); test_ScriptStringXtoCP_CPtoX(hdc); diff --git a/rostests/winetests/usp10/usp10.rbuild b/rostests/winetests/usp10/usp10.rbuild index 9a9d7a8ac7d..d84af63d44c 100644 --- a/rostests/winetests/usp10/usp10.rbuild +++ b/rostests/winetests/usp10/usp10.rbuild @@ -1,3 +1,6 @@ + + + . @@ -9,3 +12,4 @@ usp10.c testlist.c + diff --git a/rostests/winetests/uxtheme/system.c b/rostests/winetests/uxtheme/system.c index b5f661975fb..ef9c08a2522 100644 --- a/rostests/winetests/uxtheme/system.c +++ b/rostests/winetests/uxtheme/system.c @@ -420,7 +420,9 @@ static void test_GetCurrentThemeName(void) if (bThemeActive) ok( hRes == E_POINTER || hRes == S_OK, "Expected E_POINTER or S_OK, got 0x%08x\n", hRes); else - ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); + ok( hRes == E_PROP_ID_UNSUPPORTED || + hRes == E_POINTER, /* win2k3 */ + "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); diff --git a/rostests/winetests/uxtheme/uxtheme.rbuild b/rostests/winetests/uxtheme/uxtheme.rbuild index 7e557299de6..dd6c47418fa 100644 --- a/rostests/winetests/uxtheme/uxtheme.rbuild +++ b/rostests/winetests/uxtheme/uxtheme.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/version/info.c b/rostests/winetests/version/info.c index 3bfc9fb5e40..9a6bcf4c932 100644 --- a/rostests/winetests/version/info.c +++ b/rostests/winetests/version/info.c @@ -31,18 +31,20 @@ ok( (ERROR_PATH_NOT_FOUND == GetLastError()) || \ (ERROR_RESOURCE_DATA_NOT_FOUND == GetLastError()) || \ (ERROR_FILE_NOT_FOUND == GetLastError()) || \ - (ERROR_BAD_PATHNAME == GetLastError()), \ + (ERROR_BAD_PATHNAME == GetLastError()) || \ + (ERROR_SUCCESS == GetLastError()), \ "Last error wrong! ERROR_RESOURCE_DATA_NOT_FOUND/ERROR_BAD_PATHNAME (98)/" \ - "ERROR_PATH_NOT_FOUND (NT4)/ERROR_FILE_NOT_FOUND (2k3)" \ - "expected, got %u\n", GetLastError()); + "ERROR_PATH_NOT_FOUND (NT4)/ERROR_FILE_NOT_FOUND (2k3) " \ + "ERROR_SUCCESS (2k) expected, got %u\n", GetLastError()); #define EXPECT_INVALID__NOT_FOUND \ ok( (ERROR_PATH_NOT_FOUND == GetLastError()) || \ (ERROR_RESOURCE_DATA_NOT_FOUND == GetLastError()) || \ (ERROR_FILE_NOT_FOUND == GetLastError()) || \ - (ERROR_INVALID_PARAMETER == GetLastError()), \ + (ERROR_INVALID_PARAMETER == GetLastError()) || \ + (ERROR_SUCCESS == GetLastError()), \ "Last error wrong! ERROR_RESOURCE_DATA_NOT_FOUND/ERROR_INVALID_PARAMETER (98)/" \ - "ERROR_PATH_NOT_FOUND (NT4)/ERROR_FILE_NOT_FOUND (2k3)" \ - "expected, got %u\n", GetLastError()); + "ERROR_PATH_NOT_FOUND (NT4)/ERROR_FILE_NOT_FOUND (2k3) " \ + "ERROR_SUCCESS (2k) expected, got %u\n", GetLastError()); static void create_file(const CHAR *name) { @@ -122,7 +124,8 @@ static void test_info_size(void) retval); ok( (ERROR_FILE_NOT_FOUND == GetLastError()) || (ERROR_RESOURCE_DATA_NOT_FOUND == GetLastError()) || - (MY_LAST_ERROR == GetLastError()), + (MY_LAST_ERROR == GetLastError()) || + (ERROR_SUCCESS == GetLastError()), /* win2k */ "Last error wrong! ERROR_FILE_NOT_FOUND/ERROR_RESOURCE_DATA_NOT_FOUND " "(XP)/0x%08x (NT4) expected, got %u\n", MY_LAST_ERROR, GetLastError()); @@ -174,7 +177,9 @@ static void test_info_size(void) retval = GetFileVersionInfoSizeA("test.txt", &hdl); ok(retval == 0, "Expected 0, got %d\n", retval); ok(hdl == 0, "Expected 0, got %d\n", hdl); - ok(GetLastError() == ERROR_RESOURCE_DATA_NOT_FOUND, + ok(GetLastError() == ERROR_RESOURCE_DATA_NOT_FOUND || + GetLastError() == ERROR_BAD_FORMAT || /* win9x */ + GetLastError() == ERROR_SUCCESS, /* win2k */ "Expected ERROR_RESOURCE_DATA_NOT_FOUND, got %d\n", GetLastError()); DeleteFileA("test.txt"); @@ -480,7 +485,9 @@ static void test_VerQueryValue(void) GetLastError() == 0xdeadbeef /* Win9x, NT4, W2K */, "VerQueryValue returned %u\n", GetLastError()); ok(p == (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p); - ok(len == 0, "expected 0 got %x\n", len); + ok(len == 0 || + len == 0xbeef, /* win9x */ + "expected 0 got %x\n", len); p = (char *)0xdeadbeef; len = 0xdeadbeef; @@ -547,7 +554,9 @@ todo_wine ok(len == 0, "VerQueryValue returned %u, expected 0\n", len); GetLastError() == 0xdeadbeef /* Win9x, NT4, W2K */, "VerQueryValue returned %u\n", GetLastError()); ok(p == (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p); - ok(len == 0, "expected 0 got %x\n", len); + ok(len == 0 || + len == 0xbeef, /* win9x */ + "expected 0 or 0xbeef, got %x\n", len); } HeapFree(GetProcessHeap(), 0, ver); diff --git a/rostests/winetests/version/version.rbuild b/rostests/winetests/version/version.rbuild index a90ee2eae51..119d262d8ab 100644 --- a/rostests/winetests/version/version.rbuild +++ b/rostests/winetests/version/version.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/wininet/ftp.c b/rostests/winetests/wininet/ftp.c index 985b23b74b8..992bce99feb 100644 --- a/rostests/winetests/wininet/ftp.c +++ b/rostests/winetests/wininet/ftp.c @@ -26,7 +26,6 @@ * Add W-function tests. * Add missing function tests: * FtpFindFirstFile - * FtpGetCurrentDirectory * FtpGetFileSize * FtpSetCurrentDirectory */ @@ -42,6 +41,10 @@ #include "wine/test.h" + +static BOOL (WINAPI *pFtpCommandA)(HINTERNET,BOOL,DWORD,LPCSTR,DWORD_PTR,HINTERNET*); + + static void test_getfile_no_open(void) { BOOL bRet; @@ -680,10 +683,16 @@ static void test_command(HINTERNET hFtp, HINTERNET hConnect) { TRUE, ERROR_SUCCESS, "PWD\r\n" } }; + if (!pFtpCommandA) + { + skip("FtpCommandA() is not available. Skipping the Ftp command tests\n"); + return; + } + for (i = 0; i < sizeof(command_test) / sizeof(command_test[0]); i++) { SetLastError(0xdeadbeef); - ret = FtpCommandA(hFtp, FALSE, FTP_TRANSFER_TYPE_ASCII, command_test[i].cmd, 0, NULL); + ret = pFtpCommandA(hFtp, FALSE, FTP_TRANSFER_TYPE_ASCII, command_test[i].cmd, 0, NULL); error = GetLastError(); ok(ret == command_test[i].ret, "%d: expected FtpCommandA to %s\n", i, command_test[i].ret ? "succeed" : "fail"); @@ -697,8 +706,14 @@ static void test_get_current_dir(HINTERNET hFtp, HINTERNET hConnect) DWORD dwCurrentDirectoryLen = MAX_PATH; CHAR lpszCurrentDirectory[MAX_PATH]; + if (!pFtpCommandA) + { + skip("FtpCommandA() is not available. Skipping the Ftp get_current_dir tests\n"); + return; + } + /* change directories to get a more interesting pwd */ - bRet = FtpCommandA(hFtp, FALSE, FTP_TRANSFER_TYPE_ASCII, "CWD pub/", 0, NULL); + bRet = pFtpCommandA(hFtp, FALSE, FTP_TRANSFER_TYPE_ASCII, "CWD pub/", 0, NULL); if(bRet == FALSE) { skip("Failed to change directories in test_get_current_dir(HINTERNET hFtp).\n"); @@ -771,8 +786,12 @@ static void test_get_current_dir(HINTERNET hFtp, HINTERNET hConnect) START_TEST(ftp) { + HMODULE hWininet; HANDLE hInternet, hFtp, hHttp; + hWininet = GetModuleHandleA("wininet.dll"); + pFtpCommandA = (void*)GetProcAddress(hWininet, "FtpCommandA"); + SetLastError(0xdeadbeef); hInternet = InternetOpen("winetest", 0, NULL, NULL, 0); ok(hInternet != NULL, "InternetOpen failed: %u\n", GetLastError()); diff --git a/rostests/winetests/wininet/http.c b/rostests/winetests/wininet/http.c index ec2df72d988..705fcac6020 100644 --- a/rostests/winetests/wininet/http.c +++ b/rostests/winetests/wininet/http.c @@ -192,6 +192,8 @@ static VOID WINAPI callback( trace("%04x:Callback %p 0x%lx INTERNET_STATUS_HANDLE_CREATED %p %d\n", GetCurrentThreadId(), hInternet, dwContext, *(HINTERNET *)lpvStatusInformation,dwStatusInformationLength); + CLEAR_NOTIFIED(INTERNET_STATUS_DETECTING_PROXY); + SET_EXPECT(INTERNET_STATUS_DETECTING_PROXY); break; case INTERNET_STATUS_HANDLE_CLOSING: ok(dwStatusInformationLength == sizeof(HINTERNET), @@ -218,6 +220,8 @@ static VOID WINAPI callback( GetCurrentThreadId(), hInternet, dwContext, (LPCSTR)lpvStatusInformation, dwStatusInformationLength); *(LPSTR)lpvStatusInformation = '\0'; + CLEAR_NOTIFIED(INTERNET_STATUS_DETECTING_PROXY); + SET_EXPECT(INTERNET_STATUS_DETECTING_PROXY); break; case INTERNET_STATUS_INTERMEDIATE_RESPONSE: trace("%04x:Callback %p 0x%lx INTERNET_STATUS_INTERMEDIATE_RESPONSE %p %d\n", @@ -233,6 +237,7 @@ static VOID WINAPI callback( static void InternetReadFile_test(int flags) { + BOOL res; DWORD rc; CHAR buffer[4000]; DWORD length; @@ -286,6 +291,11 @@ static void InternetReadFile_test(int flags) if (hor == 0x0) goto abort; + length = sizeof(buffer); + res = InternetQueryOptionA(hor, INTERNET_OPTION_URL, buffer, &length); + ok(res, "InternetQueryOptionA(INTERNET_OPTION_URL) failed: %u\n", GetLastError()); + ok(!strcmp(buffer, "http://www.winehq.org/about/"), "Wrong URL %s\n", buffer); + CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED); todo_wine { @@ -366,10 +376,10 @@ static void InternetReadFile_test(int flags) buffer[length]=0; trace("Option 0x16 -> %i %s\n",rc,buffer); - length = 4000; - rc = InternetQueryOptionA(hor,INTERNET_OPTION_URL,buffer,&length); - buffer[length]=0; - trace("Option 0x22 -> %i %s\n",rc,buffer); + length = sizeof(buffer); + res = InternetQueryOptionA(hor, INTERNET_OPTION_URL, buffer, &length); + ok(res, "InternetQueryOptionA(INTERNET_OPTION_URL) failed: %u\n", GetLastError()); + ok(!strcmp(buffer, "http://www.winehq.org/site/about"), "Wrong URL %s\n", buffer); length = 16; rc = HttpQueryInfoA(hor,HTTP_QUERY_CONTENT_LENGTH,&buffer,&length,0x0); @@ -653,6 +663,8 @@ static void InternetReadFileExA_test(int flags) if (GetLastError() == ERROR_IO_PENDING) { trace("InternetReadFileEx -> PENDING\n"); + ok(flags & INTERNET_FLAG_ASYNC, + "Should not get ERROR_IO_PENDING without INTERNET_FLAG_ASYNC\n"); CHECK_NOTIFIED(INTERNET_STATUS_RECEIVING_RESPONSE); WaitForSingleObject(hCompleteEvent, INFINITE); CHECK_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE); @@ -888,8 +900,8 @@ static void HttpSendRequestEx_test(void) BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS); BufferIn.Next = (LPINTERNET_BUFFERS)0xdeadcab; BufferIn.lpcszHeader = szContentType; - BufferIn.dwHeadersLength = sizeof(szContentType); - BufferIn.dwHeadersTotal = sizeof(szContentType); + BufferIn.dwHeadersLength = sizeof(szContentType)-1; + BufferIn.dwHeadersTotal = sizeof(szContentType)-1; BufferIn.lpvBuffer = szPostData; BufferIn.dwBufferLength = 3; BufferIn.dwBufferTotal = sizeof(szPostData)-1; @@ -929,9 +941,19 @@ static void InternetOpenRequest_test(void) session = InternetOpenA("Wine Regression Test", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); ok(session != NULL ,"Unable to open Internet session\n"); + connect = InternetConnectA(session, NULL, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, + INTERNET_SERVICE_HTTP, 0, 0); + ok(connect == NULL, "InternetConnectA should have failed\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "InternetConnectA with NULL server named should have failed with ERROR_INVALID_PARAMETER instead of %d\n", GetLastError()); + + connect = InternetConnectA(session, "", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, + INTERNET_SERVICE_HTTP, 0, 0); + ok(connect == NULL, "InternetConnectA should have failed\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "InternetConnectA with blank server named should have failed with ERROR_INVALID_PARAMETER instead of %d\n", GetLastError()); + connect = InternetConnectA(session, "winehq.org", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); - ok(connect != NULL, "Unable to connect to http://winehq.org\n"); + ok(connect != NULL, "Unable to connect to http://winehq.org with error %d\n", GetLastError()); request = HttpOpenRequestA(connect, NULL, "/", NULL, NULL, types, INTERNET_FLAG_NO_CACHE_WRITE, 0); if (!request && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED) @@ -957,6 +979,103 @@ done: ok(InternetCloseHandle(session), "Close session handle failed\n"); } +static void test_http_cache(void) +{ + HINTERNET session, connect, request; + char file_name[MAX_PATH], url[INTERNET_MAX_URL_LENGTH]; + DWORD size, file_size; + BYTE buf[100]; + HANDLE file; + BOOL ret; + + static const char *types[] = { "*", "", NULL }; + + session = InternetOpenA("Wine Regression Test", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + ok(session != NULL ,"Unable to open Internet session\n"); + + connect = InternetConnectA(session, "www.winehq.org", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, + INTERNET_SERVICE_HTTP, 0, 0); + ok(connect != NULL, "Unable to connect to http://winehq.org with error %d\n", GetLastError()); + + request = HttpOpenRequestA(connect, NULL, "/site/about", NULL, NULL, types, INTERNET_FLAG_NEED_FILE, 0); + if (!request && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED) + { + trace( "Network unreachable, skipping test\n" ); + + ok(InternetCloseHandle(connect), "Close connect handle failed\n"); + ok(InternetCloseHandle(session), "Close session handle failed\n"); + + return; + } + ok(request != NULL, "Failed to open request handle err %u\n", GetLastError()); + + size = sizeof(url); + ret = InternetQueryOptionA(request, INTERNET_OPTION_URL, url, &size); + ok(ret, "InternetQueryOptionA(INTERNET_OPTION_url) failed: %u\n", GetLastError()); + ok(!strcmp(url, "http://www.winehq.org/site/about"), "Wrong URL %s\n", url); + + size = sizeof(file_name); + ret = InternetQueryOptionA(request, INTERNET_OPTION_DATAFILE_NAME, file_name, &size); + ok(!ret, "InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) succeeded\n"); + ok(GetLastError() == ERROR_INTERNET_ITEM_NOT_FOUND, "GetLastError()=%u\n", GetLastError()); + ok(!size, "size = %d\n", size); + + ret = HttpSendRequest(request, NULL, 0, NULL, 0); + ok(ret, "HttpSendRequest failed: %u\n", GetLastError()); + + size = sizeof(file_name); + ret = InternetQueryOptionA(request, INTERNET_OPTION_DATAFILE_NAME, file_name, &size); + ok(ret, "InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed: %u\n", GetLastError()); + + file = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError()); + file_size = GetFileSize(file, NULL); + ok(file_size == 0, "file size=%d\n", file_size); + + ret = InternetReadFile(request, buf, sizeof(buf), &size); + ok(ret, "InternetReadFile failed: %u\n", GetLastError()); + ok(size == sizeof(buf), "size=%d\n", size); + + file_size = GetFileSize(file, NULL); + ok(file_size == sizeof(buf), "file size=%d\n", file_size); + CloseHandle(file); + + ok(InternetCloseHandle(request), "Close request handle failed\n"); + + file = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + ok(file == INVALID_HANDLE_VALUE, "CreateFile succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError()=%u, expected ERROR_FILE_NOT_FOUND\n", GetLastError()); + + request = HttpOpenRequestA(connect, NULL, "/", NULL, NULL, types, INTERNET_FLAG_NO_CACHE_WRITE, 0); + ok(request != NULL, "Failed to open request handle err %u\n", GetLastError()); + + ret = InternetQueryOptionA(request, INTERNET_OPTION_DATAFILE_NAME, file_name, &size); + ok(!ret, "InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) succeeded\n"); + ok(GetLastError() == ERROR_INTERNET_ITEM_NOT_FOUND, "GetLastError()=%u\n", GetLastError()); + ok(!size, "size = %d\n", size); + + ret = HttpSendRequest(request, NULL, 0, NULL, 0); + ok(ret, "HttpSendRequest failed: %u\n", GetLastError()); + + size = sizeof(file_name); + ret = InternetQueryOptionA(request, INTERNET_OPTION_DATAFILE_NAME, file_name, &size); + ok(!ret, "InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) succeeded\n"); + ok(GetLastError() == ERROR_INTERNET_ITEM_NOT_FOUND, "GetLastError()=%u\n", GetLastError()); + ok(!size, "size = %d\n", size); + + file = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + ok(file == INVALID_HANDLE_VALUE, "CreateFile succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError()=%u, expected ERROR_FILE_NOT_FOUND\n", GetLastError()); + + ok(InternetCloseHandle(request), "Close request handle failed\n"); + + ok(InternetCloseHandle(connect), "Close connect handle failed\n"); + ok(InternetCloseHandle(session), "Close session handle failed\n"); +} + static void HttpHeaders_test(void) { HINTERNET hSession; @@ -999,7 +1118,7 @@ static void HttpHeaders_test(void) ok(index == 1, "Index was not incremented\n"); ok(strcmp(buffer,"test1")==0, "incorrect string was returned(%s)\n",buffer); ok(len == 5, "Invalid length (exp. 5, got %d)\n", len); - ok(buffer[len] == 0, "Buffer not NULL-terminated\n"); /* len show only 5 characters but the buffer is NULL-terminated*/ + ok((len < sizeof(buffer)) && (buffer[len] == 0), "Buffer not NULL-terminated\n"); /* len show only 5 characters but the buffer is NULL-terminated*/ len = sizeof(buffer); strcpy(buffer,"Warning"); ok(HttpQueryInfo(hRequest,HTTP_QUERY_CUSTOM|HTTP_QUERY_FLAG_REQUEST_HEADERS, @@ -1192,18 +1311,21 @@ done: ok(InternetCloseHandle(hSession), "Close session handle failed\n"); } +static const char contmsg[] = +"HTTP/1.1 100 Continue\r\n"; + static const char okmsg[] = -"HTTP/1.0 200 OK\r\n" +"HTTP/1.1 200 OK\r\n" "Server: winetest\r\n" "\r\n"; static const char notokmsg[] = -"HTTP/1.0 400 Bad Request\r\n" +"HTTP/1.1 400 Bad Request\r\n" "Server: winetest\r\n" "\r\n"; static const char noauthmsg[] = -"HTTP/1.0 401 Unauthorized\r\n" +"HTTP/1.1 401 Unauthorized\r\n" "Server: winetest\r\n" "\r\n"; @@ -1275,8 +1397,13 @@ static DWORD CALLBACK server_thread(LPVOID param) if (strstr(buffer, "GET /test1")) { - send(c, okmsg, sizeof okmsg-1, 0); - send(c, page1, sizeof page1-1, 0); + if (!strstr(buffer, "Content-Length: 0")) + { + send(c, okmsg, sizeof okmsg-1, 0); + send(c, page1, sizeof page1-1, 0); + } + else + send(c, notokmsg, sizeof notokmsg-1, 0); } if (strstr(buffer, "/test2")) @@ -1306,7 +1433,7 @@ static DWORD CALLBACK server_thread(LPVOID param) send(c, notokmsg, sizeof notokmsg-1, 0); } - if (strstr(buffer, "/test5")) + if (strstr(buffer, "POST /test5")) { if (strstr(buffer, "Content-Length: 0")) { @@ -1317,7 +1444,15 @@ static DWORD CALLBACK server_thread(LPVOID param) send(c, notokmsg, sizeof notokmsg-1, 0); } - if (strstr(buffer, "/quit")) + if (strstr(buffer, "GET /test6")) + { + send(c, contmsg, sizeof contmsg-1, 0); + send(c, contmsg, sizeof contmsg-1, 0); + send(c, okmsg, sizeof okmsg-1, 0); + send(c, page1, sizeof page1-1, 0); + } + + if (strstr(buffer, "GET /quit")) { send(c, okmsg, sizeof okmsg-1, 0); send(c, page1, sizeof page1-1, 0); @@ -1333,19 +1468,19 @@ static DWORD CALLBACK server_thread(LPVOID param) return 0; } -static void test_basic_request(int port, const char *url) +static void test_basic_request(int port, const char *verb, const char *url) { HINTERNET hi, hc, hr; DWORD r, count; char buffer[0x100]; - hi = InternetOpen(NULL, 0, NULL, NULL, 0); + hi = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); ok(hi != NULL, "open failed\n"); hc = InternetConnect(hi, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); ok(hc != NULL, "connect failed\n"); - hr = HttpOpenRequest(hc, NULL, url, NULL, NULL, NULL, 0, 0); + hr = HttpOpenRequest(hc, verb, url, NULL, NULL, NULL, 0, 0); ok(hr != NULL, "HttpOpenRequest failed\n"); r = HttpSendRequest(hr, NULL, 0, NULL, 0); @@ -1492,7 +1627,10 @@ static void test_header_handling_order(int port) request = HttpOpenRequest(connect, NULL, "/test3", NULL, NULL, types, INTERNET_FLAG_KEEP_CONNECTION, 0); ok(request != NULL, "HttpOpenRequest failed\n"); - ret = HttpSendRequest(request, authorization, ~0UL, NULL, 0); + ret = HttpAddRequestHeaders(request, authorization, ~0UL, HTTP_ADDREQ_FLAG_ADD); + ok(ret, "HttpAddRequestHeaders failed\n"); + + ret = HttpSendRequest(request, NULL, 0, NULL, 0); ok(ret, "HttpSendRequest failed\n"); status = 0; @@ -1537,20 +1675,102 @@ static void test_http_connection(void) if (r != WAIT_OBJECT_0) return; - test_basic_request(si.port, "/test1"); + test_basic_request(si.port, "GET", "/test1"); test_proxy_indirect(si.port); test_proxy_direct(si.port); test_header_handling_order(si.port); - test_basic_request(si.port, "/test5"); + test_basic_request(si.port, "POST", "/test5"); + test_basic_request(si.port, "GET", "/test6"); /* send the basic request again to shutdown the server thread */ - test_basic_request(si.port, "/quit"); + test_basic_request(si.port, "GET", "/quit"); r = WaitForSingleObject(hThread, 3000); ok( r == WAIT_OBJECT_0, "thread wait failed\n"); CloseHandle(hThread); } +static void test_user_agent_header(void) +{ + HINTERNET ses, con, req; + DWORD size, err; + char buffer[64]; + BOOL ret; + + ses = InternetOpen("Gizmo5", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + ok(ses != NULL, "InternetOpen failed\n"); + + con = InternetConnect(ses, "www.winehq.org", 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + ok(con != NULL, "InternetConnect failed\n"); + + req = HttpOpenRequest(con, "GET", "/", "HTTP/1.0", NULL, NULL, 0, 0); + ok(req != NULL, "HttpOpenRequest failed\n"); + + size = sizeof(buffer); + ret = HttpQueryInfo(req, HTTP_QUERY_USER_AGENT | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, NULL); + err = GetLastError(); + ok(!ret, "HttpQueryInfo succeeded\n"); + ok(err == ERROR_HTTP_HEADER_NOT_FOUND, "expected ERROR_HTTP_HEADER_NOT_FOUND, got %u\n", err); + + ret = HttpAddRequestHeaders(req, "User-Agent: Gizmo Project\r\n", ~0UL, HTTP_ADDREQ_FLAG_ADD_IF_NEW); + ok(ret, "HttpAddRequestHeaders succeeded\n"); + + size = sizeof(buffer); + ret = HttpQueryInfo(req, HTTP_QUERY_USER_AGENT | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, NULL); + err = GetLastError(); + ok(ret, "HttpQueryInfo failed\n"); + ok(err == ERROR_HTTP_HEADER_NOT_FOUND, "expected ERROR_HTTP_HEADER_NOT_FOUND, got %u\n", err); + + InternetCloseHandle(req); + + req = HttpOpenRequest(con, "GET", "/", "HTTP/1.0", NULL, NULL, 0, 0); + ok(req != NULL, "HttpOpenRequest failed\n"); + + size = sizeof(buffer); + ret = HttpQueryInfo(req, HTTP_QUERY_ACCEPT | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, NULL); + err = GetLastError(); + ok(!ret, "HttpQueryInfo succeeded\n"); + ok(err == ERROR_HTTP_HEADER_NOT_FOUND, "expected ERROR_HTTP_HEADER_NOT_FOUND, got %u\n", err); + + ret = HttpAddRequestHeaders(req, "Accept: audio/*, image/*, text/*\r\nUser-Agent: Gizmo Project\r\n", ~0UL, HTTP_ADDREQ_FLAG_ADD_IF_NEW); + ok(ret, "HttpAddRequestHeaders failed\n"); + + buffer[0] = 0; + size = sizeof(buffer); + ret = HttpQueryInfo(req, HTTP_QUERY_ACCEPT | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, NULL); + ok(ret, "HttpQueryInfo failed: %u\n", GetLastError()); + ok(!strcmp(buffer, "audio/*, image/*, text/*"), "got '%s' expected 'audio/*, image/*, text/*'\n", buffer); + + InternetCloseHandle(req); + InternetCloseHandle(con); + InternetCloseHandle(ses); +} + +static void test_bogus_accept_types_array(void) +{ + HINTERNET ses, con, req; + static const char *types[] = { (const char *)6240, "*/*", "%p", "", "*/*", NULL }; + DWORD size; + char buffer[32]; + BOOL ret; + + ses = InternetOpen("MERONG(0.9/;p)", INTERNET_OPEN_TYPE_DIRECT, "", "", 0); + con = InternetConnect(ses, "www.winehq.org", 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + req = HttpOpenRequest(con, "POST", "/post/post_action.php", "HTTP/1.0", "", types, INTERNET_FLAG_FORMS_SUBMIT, 0); + + ok(req != NULL, "HttpOpenRequest failed: %u\n", GetLastError()); + + buffer[0] = 0; + size = sizeof(buffer); + ret = HttpQueryInfo(req, HTTP_QUERY_ACCEPT | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, NULL); + ok(ret, "HttpQueryInfo failed: %u\n", GetLastError()); + ok(!strcmp(buffer, "*/*, %p, */*"), "got '%s' expected '*/*, %%p, */*'\n", buffer); + + InternetCloseHandle(req); + InternetCloseHandle(con); + InternetCloseHandle(ses); +} + #define STATUS_STRING(status) \ memcpy(status_string[status], #status, sizeof(CHAR) * \ (strlen(#status) < MAX_STATUS_NAME ? \ @@ -1576,6 +1796,7 @@ static void init_status_tests(void) STATUS_STRING(INTERNET_STATUS_CONNECTION_CLOSED); STATUS_STRING(INTERNET_STATUS_HANDLE_CREATED); STATUS_STRING(INTERNET_STATUS_HANDLE_CLOSING); + STATUS_STRING(INTERNET_STATUS_DETECTING_PROXY); STATUS_STRING(INTERNET_STATUS_REQUEST_COMPLETE); STATUS_STRING(INTERNET_STATUS_REDIRECT); STATUS_STRING(INTERNET_STATUS_INTERMEDIATE_RESPONSE); @@ -1610,6 +1831,7 @@ START_TEST(http) InternetReadFileExA_test(INTERNET_FLAG_ASYNC); } InternetOpenRequest_test(); + test_http_cache(); InternetOpenUrlA_test(); if (!pInternetTimeFromSystemTimeA) skip("skipping the InternetTime tests\n"); @@ -1623,4 +1845,6 @@ START_TEST(http) HttpSendRequestEx_test(); HttpHeaders_test(); test_http_connection(); + test_user_agent_header(); + test_bogus_accept_types_array(); } diff --git a/rostests/winetests/wininet/internet.c b/rostests/winetests/wininet/internet.c index 8704f7dbd56..15495db514d 100644 --- a/rostests/winetests/wininet/internet.c +++ b/rostests/winetests/wininet/internet.c @@ -113,6 +113,10 @@ static void test_InternetCanonicalizeUrlA(void) "got %u and %u with size %u for '%s' (%d)\n", res, GetLastError(), dwSize, buffer, lstrlenA(buffer)); + res = InternetSetOptionA(NULL, 0xdeadbeef, buffer, sizeof(buffer)); + ok(!res, "InternetSetOptionA succeeded\n"); + ok(GetLastError() == ERROR_INTERNET_INVALID_OPTION, + "InternetSetOptionA failed %u, expected ERROR_INTERNET_INVALID_OPTION\n", GetLastError()); } /* ############################### */ @@ -285,7 +289,8 @@ static void test_null(void) sz = 0; r = InternetGetCookieW(NULL, NULL, NULL, &sz); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INTERNET_UNRECOGNIZED_SCHEME, + "wrong error %u\n", GetLastError()); ok( r == FALSE, "return wrong\n"); r = InternetGetCookieW(szServer, NULL, NULL, &sz); @@ -311,7 +316,7 @@ static void test_null(void) ok( r == TRUE, "return wrong\n"); /* sz == lstrlenW(buffer) only in XP SP1 */ - ok( sz == 1 + lstrlenW(buffer), "sz wrong\n"); + ok( sz == 1 + lstrlenW(buffer) || sz == lstrlenW(buffer), "sz wrong %d\n", sz); /* before XP SP2, buffer is "server; server" */ ok( !lstrcmpW(szExpect, buffer) || !lstrcmpW(szServer, buffer), "cookie data wrong\n"); @@ -321,6 +326,19 @@ static void test_null(void) ok(r == TRUE, "ret %d\n", r); } +static void test_version(void) +{ + INTERNET_VERSION_INFO version; + DWORD size; + BOOL res; + + size = sizeof(version); + res = InternetQueryOptionA(NULL, INTERNET_OPTION_VERSION, &version, &size); + ok(res, "Could not get version: %u\n", GetLastError()); + ok(version.dwMajorVersion == 1, "dwMajorVersion=%d, expected 1\n", version.dwMajorVersion); + ok(version.dwMinorVersion == 2, "dwMinorVersion=%d, expected 2\n", version.dwMinorVersion); +} + /* ############################### */ START_TEST(internet) @@ -328,5 +346,6 @@ START_TEST(internet) test_InternetCanonicalizeUrlA(); test_InternetQueryOptionA(); test_get_cookie(); + test_version(); test_null(); } diff --git a/rostests/winetests/wininet/testlist.c b/rostests/winetests/wininet/testlist.c index df55646f40a..218ba206137 100644 --- a/rostests/winetests/wininet/testlist.c +++ b/rostests/winetests/wininet/testlist.c @@ -11,6 +11,7 @@ extern void func_generated(void); extern void func_http(void); extern void func_internet(void); extern void func_url(void); +extern void func_urlcache(void); const struct test winetest_testlist[] = { @@ -19,5 +20,6 @@ const struct test winetest_testlist[] = { "http", func_http }, { "internet", func_internet }, { "url", func_url }, + { "urlcache", func_urlcache }, { 0, 0 } }; diff --git a/rostests/winetests/wininet/url.c b/rostests/winetests/wininet/url.c index dd71edb485e..ccc56076bad 100644 --- a/rostests/winetests/wininet/url.c +++ b/rostests/winetests/wininet/url.c @@ -452,7 +452,7 @@ static void InternetCreateUrlA_test(void) "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); ok(len == -1, "Expected len -1, got %d\n", len); - /* test valid lpUrlComponets, NULL lpdwUrlLength */ + /* test valid lpUrlComponents, NULL lpdwUrlLength */ fill_url_components(&urlComp); SetLastError(0xdeadbeef); ret = InternetCreateUrlA(&urlComp, 0, NULL, NULL); @@ -461,7 +461,7 @@ static void InternetCreateUrlA_test(void) "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); ok(len == -1, "Expected len -1, got %d\n", len); - /* test valid lpUrlComponets, empty szUrl + /* test valid lpUrlComponents, empty szUrl * lpdwUrlLength is size of buffer required on exit, including * the terminating null when GLE == ERROR_INSUFFICIENT_BUFFER */ @@ -481,7 +481,7 @@ static void InternetCreateUrlA_test(void) "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); ok(len == 51, "Expected len 51, got %d\n", len); - /* test valid lpUrlComponets, alloced szUrl, small size */ + /* test valid lpUrlComponents, alloc-ed szUrl, small size */ SetLastError(0xdeadbeef); szUrl = HeapAlloc(GetProcessHeap(), 0, len); len -= 2; @@ -491,7 +491,7 @@ static void InternetCreateUrlA_test(void) "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); ok(len == 51, "Expected len 51, got %d\n", len); - /* alloced szUrl, NULL lpszScheme + /* alloc-ed szUrl, NULL lpszScheme * shows that it uses nScheme instead */ SetLastError(0xdeadbeef); @@ -503,7 +503,7 @@ static void InternetCreateUrlA_test(void) ok(len == 50, "Expected len 50, got %d\n", len); ok(!strcmp(szUrl, CREATE_URL1), "Expected %s, got %s\n", CREATE_URL1, szUrl); - /* alloced szUrl, invalid nScheme + /* alloc-ed szUrl, invalid nScheme * any nScheme out of range seems ignored */ fill_url_components(&urlComp); @@ -516,7 +516,7 @@ static void InternetCreateUrlA_test(void) "Expected 0xdeadbeef, got %d\n", GetLastError()); ok(len == 50, "Expected len 50, got %d\n", len); - /* test valid lpUrlComponets, alloced szUrl */ + /* test valid lpUrlComponents, alloc-ed szUrl */ fill_url_components(&urlComp); SetLastError(0xdeadbeef); len = 51; diff --git a/rostests/winetests/wininet/urlcache.c b/rostests/winetests/wininet/urlcache.c new file mode 100644 index 00000000000..6570d5a9eba --- /dev/null +++ b/rostests/winetests/wininet/urlcache.c @@ -0,0 +1,172 @@ +/* + * URL Cache Tests + * + * Copyright 2008 Robert Shearman for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wininet.h" + +#include "wine/test.h" + +#define TEST_URL "http://urlcachetest.winehq.org/index.html" + +static char filenameA[MAX_PATH + 1]; + +static void check_cache_entry_infoA(const char *returnedfrom, LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo) +{ + ok(lpCacheEntryInfo->dwStructSize == sizeof(*lpCacheEntryInfo), "%s: dwStructSize was %d\n", returnedfrom, lpCacheEntryInfo->dwStructSize); + ok(!strcmp(lpCacheEntryInfo->lpszSourceUrlName, TEST_URL), "%s: lpszSourceUrlName should be %s instead of %s\n", returnedfrom, TEST_URL, lpCacheEntryInfo->lpszSourceUrlName); + ok(!strcmp(lpCacheEntryInfo->lpszLocalFileName, filenameA), "%s: lpszLocalFileName should be %s instead of %s\n", returnedfrom, filenameA, lpCacheEntryInfo->lpszLocalFileName); + ok(!strcmp(lpCacheEntryInfo->lpszFileExtension, "html"), "%s: lpszFileExtension should be html instead of %s\n", returnedfrom, lpCacheEntryInfo->lpszFileExtension); +} + +static void test_find_url_cache_entriesA(void) +{ + BOOL ret; + HANDLE hEnumHandle; + BOOL found = FALSE; + DWORD cbCacheEntryInfo; + DWORD cbCacheEntryInfoSaved; + LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo; + + cbCacheEntryInfo = 0; + hEnumHandle = FindFirstUrlCacheEntry(NULL, NULL, &cbCacheEntryInfo); + ok(!hEnumHandle, "FindFirstUrlCacheEntry should have failed\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "FindFirstUrlCacheEntry should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError()); + lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo * sizeof(char)); + cbCacheEntryInfoSaved = cbCacheEntryInfo; + hEnumHandle = FindFirstUrlCacheEntry(NULL, lpCacheEntryInfo, &cbCacheEntryInfo); + ok(hEnumHandle != NULL, "FindFirstUrlCacheEntry failed with error %d\n", GetLastError()); + while (TRUE) + { + if (!strcmp(lpCacheEntryInfo->lpszSourceUrlName, TEST_URL)) + { + found = TRUE; + break; + } + cbCacheEntryInfo = cbCacheEntryInfoSaved; + ret = FindNextUrlCacheEntry(hEnumHandle, lpCacheEntryInfo, &cbCacheEntryInfo); + if (!ret) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + lpCacheEntryInfo = HeapReAlloc(GetProcessHeap(), 0, lpCacheEntryInfo, cbCacheEntryInfo); + cbCacheEntryInfoSaved = cbCacheEntryInfo; + ret = FindNextUrlCacheEntry(hEnumHandle, lpCacheEntryInfo, &cbCacheEntryInfo); + } + } + ok(ret, "FindNextUrlCacheEntry failed with error %d\n", GetLastError()); + if (!ret) + break; + } + ok(found, "committed url cache entry not found during enumeration\n"); + + ret = FindCloseUrlCache(hEnumHandle); + ok(ret, "FindCloseUrlCache failed with error %d\n", GetLastError()); +} + +static void test_GetUrlCacheEntryInfoExA(void) +{ + BOOL ret; + DWORD cbCacheEntryInfo; + LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo; + + ret = GetUrlCacheEntryInfoEx(NULL, NULL, NULL, NULL, NULL, NULL, 0); + ok(!ret, "GetUrlCacheEntryInfoEx with NULL URL and NULL args should have failed\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetUrlCacheEntryInfoEx with NULL URL and NULL args should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError()); + + ret = GetUrlCacheEntryInfoEx(TEST_URL, NULL, NULL, NULL, NULL, NULL, 0); + ok(ret, "GetUrlCacheEntryInfoEx with NULL args failed with error %d\n", GetLastError()); + + cbCacheEntryInfo = 0; + ret = GetUrlCacheEntryInfoEx(TEST_URL, NULL, &cbCacheEntryInfo, NULL, NULL, NULL, 0); + ok(!ret, "GetUrlCacheEntryInfoEx with zero-length buffer should fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetUrlCacheEntryInfoEx should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError()); + + lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); + ret = GetUrlCacheEntryInfoEx(TEST_URL, lpCacheEntryInfo, &cbCacheEntryInfo, NULL, NULL, NULL, 0); + ok(ret, "GetUrlCacheEntryInfoEx failed with error %d\n", GetLastError()); + + check_cache_entry_infoA("GetUrlCacheEntryInfoEx", lpCacheEntryInfo); + + HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); +} + +static void test_urlcacheA(void) +{ + BOOL ret; + HANDLE hFile; + DWORD written; + BYTE zero_byte = 0; + LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo; + DWORD cbCacheEntryInfo; + static const FILETIME filetime_zero; + + ret = CreateUrlCacheEntry(TEST_URL, 0, "html", filenameA, 0); + ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError()); + + hFile = CreateFileA(filenameA, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA failed with error %d\n", GetLastError()); + + ret = WriteFile(hFile, &zero_byte, sizeof(zero_byte), &written, NULL); + ok(ret, "WriteFile failed with error %d\n", GetLastError()); + + CloseHandle(hFile); + + ret = CommitUrlCacheEntry(TEST_URL, filenameA, filetime_zero, filetime_zero, NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL); + ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError()); + + cbCacheEntryInfo = 0; + ret = RetrieveUrlCacheEntryFile(TEST_URL, NULL, &cbCacheEntryInfo, 0); + ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "RetrieveUrlCacheEntryFile should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError()); + + lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo); + ret = RetrieveUrlCacheEntryFile(TEST_URL, lpCacheEntryInfo, &cbCacheEntryInfo, 0); + ok(ret, "RetrieveUrlCacheEntryFile failed with error %d\n", GetLastError()); + + check_cache_entry_infoA("RetrieveUrlCacheEntryFile", lpCacheEntryInfo); + + HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); + + ret = UnlockUrlCacheEntryFile(TEST_URL, 0); + ok(ret, "UnlockUrlCacheEntryFile failed with error %d\n", GetLastError()); + + /* test Find*UrlCacheEntry functions */ + test_find_url_cache_entriesA(); + + test_GetUrlCacheEntryInfoExA(); + + ret = DeleteUrlCacheEntry(TEST_URL); + ok(ret, "DeleteUrlCacheEntry failed with error %d\n", GetLastError()); + + ret = DeleteFile(filenameA); + todo_wine + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, "local file should no longer exist\n"); +} + +START_TEST(urlcache) +{ + test_urlcacheA(); +} diff --git a/rostests/winetests/wininet/wininet.rbuild b/rostests/winetests/wininet/wininet.rbuild index 434d8454900..5c759d72084 100644 --- a/rostests/winetests/wininet/wininet.rbuild +++ b/rostests/winetests/wininet/wininet.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 @@ -15,6 +15,7 @@ http.c internet.c url.c + urlcache.c testlist.c