diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c index eeeaa32fc7a..3f89086f655 100644 --- a/dlls/kernel32/tests/pipe.c +++ b/dlls/kernel32/tests/pipe.c @@ -43,6 +43,72 @@ static void CALLBACK user_apc(ULONG_PTR param) user_apc_ran = TRUE; } + +enum rpcThreadOp +{ + RPC_READFILE +}; + +struct rpcThreadArgs +{ + ULONG_PTR returnValue; + DWORD lastError; + enum rpcThreadOp op; + ULONG_PTR args[5]; +}; + +static DWORD CALLBACK rpcThreadMain(LPVOID arg) +{ + struct rpcThreadArgs *rpcargs = (struct rpcThreadArgs *)arg; + trace("rpcThreadMain starting\n"); + SetLastError( rpcargs->lastError ); + + switch (rpcargs->op) + { + case RPC_READFILE: + rpcargs->returnValue = (ULONG_PTR)ReadFile( (HANDLE)rpcargs->args[0], /* hFile */ + (LPVOID)rpcargs->args[1], /* buffer */ + (DWORD)rpcargs->args[2], /* bytesToRead */ + (LPDWORD)rpcargs->args[3], /* bytesRead */ + (LPOVERLAPPED)rpcargs->args[4] ); /* overlapped */ + break; + + default: + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + rpcargs->returnValue = 0; + break; + } + + rpcargs->lastError = GetLastError(); + trace("rpcThreadMain returning\n"); + return 0; +} + +/* Runs ReadFile(...) from a different thread */ +static BOOL RpcReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead, LPOVERLAPPED overlapped) +{ + struct rpcThreadArgs rpcargs; + HANDLE thread; + DWORD threadId; + + rpcargs.returnValue = 0; + rpcargs.lastError = GetLastError(); + rpcargs.op = RPC_READFILE; + rpcargs.args[0] = (ULONG_PTR)hFile; + rpcargs.args[1] = (ULONG_PTR)buffer; + rpcargs.args[2] = (ULONG_PTR)bytesToRead; + rpcargs.args[3] = (ULONG_PTR)bytesRead; + rpcargs.args[4] = (ULONG_PTR)overlapped; + + thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId); + ok(thread != NULL, "CreateThread failed. %d\n", GetLastError()); + ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed with %d.\n", GetLastError()); + CloseHandle(thread); + + SetLastError(rpcargs.lastError); + return (BOOL)rpcargs.returnValue; +} + static void test_CreateNamedPipe(int pipemode) { HANDLE hnp; @@ -372,6 +438,99 @@ static void test_CreateNamedPipe(int pipemode) ok(readden == sizeof(obuf) - 4, "read got %d bytes 8\n", readden); ok(memcmp(obuf, ibuf, written) == 0, "content check 8\n"); + /* The following test shows that when doing a partial read of a message, the rest + * is still in the pipe, and can be received from a second thread. This shows + * especially that the content is _not_ stored in thread-local-storage until it is + * completely transmitted. The same method works even across multiple processes. */ + memset(ibuf, 0, sizeof(ibuf)); + ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile 9\n"); + ok(written == sizeof(obuf), "write file len 9\n"); + ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 9\n"); + ok(written == sizeof(obuf2), "write file len 9\n"); + SetLastError(0xdeadbeef); + todo_wine + ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 9\n"); + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); + ok(readden == 4, "read got %d bytes 9\n", readden); + SetLastError(0xdeadbeef); + ret = RpcReadFile(hFile, ibuf + 4, 4, &readden, NULL); + todo_wine + ok(!ret, "RpcReadFile 9\n"); + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); + ok(readden == 4, "read got %d bytes 9\n", readden); + ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 9\n"); + todo_wine + ok(readden == sizeof(obuf) - 8, "read got %d bytes 9\n", readden); + ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 9\n"); + if (readden <= sizeof(obuf) - 8) /* blocks forever if second part was already received */ + { + memset(ibuf, 0, sizeof(ibuf)); + SetLastError(0xdeadbeef); + ret = RpcReadFile(hFile, ibuf, 4, &readden, NULL); + ok(!ret, "RpcReadFile 9\n"); + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); + ok(readden == 4, "read got %d bytes 9\n", readden); + SetLastError(0xdeadbeef); + todo_wine + ok(!ReadFile(hFile, ibuf + 4, 4, &readden, NULL), "ReadFile 9\n"); + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); + ok(readden == 4, "read got %d bytes 9\n", readden); + ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 9\n"); + ok(readden == sizeof(obuf2) - 8, "read got %d bytes 9\n", readden); + ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 9\n"); + } + + /* Now the reverse direction */ + memset(ibuf, 0, sizeof(ibuf)); + ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 10\n"); + ok(written == sizeof(obuf2), "write file len 10\n"); + ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile 10\n"); + ok(written == sizeof(obuf), "write file len 10\n"); + SetLastError(0xdeadbeef); + todo_wine + ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 10\n"); + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); + ok(readden == 4, "read got %d bytes 10\n", readden); + SetLastError(0xdeadbeef); + ret = RpcReadFile(hnp, ibuf + 4, 4, &readden, NULL); + todo_wine + ok(!ret, "RpcReadFile 10\n"); + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); + ok(readden == 4, "read got %d bytes 10\n", readden); + ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 10\n"); + todo_wine + ok(readden == sizeof(obuf2) - 8, "read got %d bytes 10\n", readden); + ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 10\n"); + if (readden <= sizeof(obuf2) - 8) /* blocks forever if second part was already received */ + { + memset(ibuf, 0, sizeof(ibuf)); + SetLastError(0xdeadbeef); + ret = RpcReadFile(hnp, ibuf, 4, &readden, NULL); + ok(!ret, "RpcReadFile 10\n"); + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); + ok(readden == 4, "read got %d bytes 10\n", readden); + SetLastError(0xdeadbeef); + todo_wine + ok(!ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile 10\n"); + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); + ok(readden == 4, "read got %d bytes 10\n", readden); + ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 10\n"); + ok(readden == sizeof(obuf) - 8, "read got %d bytes 10\n", readden); + ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 10\n"); + } + } /* Picky conformance tests */