mirror of
https://github.com/reactos/reactos.git
synced 2025-02-25 01:39:30 +00:00
sync the setupapi test to wine 0.9.14 and remove some files commited to the wrong folder
svn path=/trunk/; revision=22054
This commit is contained in:
parent
a8373ada71
commit
0cdda064ca
33 changed files with 709 additions and 16424 deletions
|
@ -1,406 +0,0 @@
|
|||
/*
|
||||
* Unit test suite for memory allocation functions.
|
||||
*
|
||||
* Copyright 2002 Geoffrey Hausheer
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
|
||||
|
||||
/* The following functions don't have tests, because either I don't know how
|
||||
to test them, or they are WinNT only, or require multiple threads.
|
||||
Since the last two issues shouldn't really stop the tests from being
|
||||
written, assume for now that it is all due to the first case
|
||||
HeapCompact
|
||||
HeapLock
|
||||
HeapQueryInformation
|
||||
HeapSetInformation
|
||||
HeapUnlock
|
||||
HeapValidate
|
||||
HeapWalk
|
||||
*/
|
||||
/* In addition, these features aren't being tested
|
||||
HEAP_NO_SERIALIZE
|
||||
HEAP_GENERATE_EXCEPTIONS
|
||||
STATUS_ACCESS_VIOLATION (error code from HeapAlloc)
|
||||
*/
|
||||
|
||||
static void test_Heap(void)
|
||||
{
|
||||
SYSTEM_INFO sysInfo;
|
||||
ULONG memchunk;
|
||||
HANDLE heap;
|
||||
LPVOID mem1,mem1a,mem3;
|
||||
UCHAR *mem2,*mem2a;
|
||||
UINT error,i;
|
||||
DWORD dwSize;
|
||||
|
||||
/* Retrieve the page size for this system */
|
||||
sysInfo.dwPageSize=0;
|
||||
GetSystemInfo(&sysInfo);
|
||||
ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
|
||||
|
||||
/* Create a Heap with a minimum and maximum size */
|
||||
/* Note that Windows and Wine seem to behave a bit differently with respect
|
||||
to memory allocation. In Windows, you can't access all the memory
|
||||
specified in the heap (due to overhead), so choosing a reasonable maximum
|
||||
size for the heap was done mostly by trial-and-error on Win2k. It may need
|
||||
more tweaking for otherWindows variants.
|
||||
*/
|
||||
memchunk=10*sysInfo.dwPageSize;
|
||||
heap=HeapCreate(0,2*memchunk,5*memchunk);
|
||||
|
||||
/* Check that HeapCreate allocated the right amount of ram */
|
||||
todo_wine {
|
||||
/* Today HeapCreate seems to return a memory block larger than specified.
|
||||
MSDN says the maximum heap size should be dwMaximumSize rounded up to the
|
||||
nearest page boundary
|
||||
*/
|
||||
mem1=HeapAlloc(heap,0,5*memchunk+1);
|
||||
ok(mem1==NULL,"HeapCreate allocated more Ram than it should have\n");
|
||||
HeapFree(heap,0,mem1);
|
||||
}
|
||||
|
||||
/* Check that a normal alloc works */
|
||||
mem1=HeapAlloc(heap,0,memchunk);
|
||||
ok(mem1!=NULL,"HeapAlloc failed\n");
|
||||
if(mem1) {
|
||||
ok(HeapSize(heap,0,mem1)>=memchunk, "HeapAlloc should return a big enough memory block\n");
|
||||
}
|
||||
|
||||
/* Check that a 'zeroing' alloc works */
|
||||
mem2=HeapAlloc(heap,HEAP_ZERO_MEMORY,memchunk);
|
||||
ok(mem2!=NULL,"HeapAlloc failed\n");
|
||||
if(mem2) {
|
||||
ok(HeapSize(heap,0,mem2)>=memchunk,"HeapAlloc should return a big enough memory block\n");
|
||||
error=0;
|
||||
for(i=0;i<memchunk;i++) {
|
||||
if(mem2[i]!=0) {
|
||||
error=1;
|
||||
}
|
||||
}
|
||||
ok(!error,"HeapAlloc should have zeroed out it's allocated memory\n");
|
||||
}
|
||||
|
||||
/* Check that HeapAlloc returns NULL when requested way too much memory */
|
||||
mem3=HeapAlloc(heap,0,5*memchunk);
|
||||
ok(mem3==NULL,"HeapAlloc should return NULL\n");
|
||||
if(mem3) {
|
||||
ok(HeapFree(heap,0,mem3),"HeapFree didn't pass successfully\n");
|
||||
}
|
||||
|
||||
/* Check that HeapRealloc works */
|
||||
mem2a=HeapReAlloc(heap,HEAP_ZERO_MEMORY,mem2,memchunk+5*sysInfo.dwPageSize);
|
||||
ok(mem2a!=NULL,"HeapReAlloc failed\n");
|
||||
if(mem2a) {
|
||||
ok(HeapSize(heap,0,mem2a)>=memchunk+5*sysInfo.dwPageSize,"HeapReAlloc failed\n");
|
||||
error=0;
|
||||
for(i=0;i<5*sysInfo.dwPageSize;i++) {
|
||||
if(mem2a[memchunk+i]!=0) {
|
||||
error=1;
|
||||
}
|
||||
}
|
||||
ok(!error,"HeapReAlloc should have zeroed out it's allocated memory\n");
|
||||
}
|
||||
|
||||
/* Check that HeapRealloc honours HEAP_REALLOC_IN_PLACE_ONLY */
|
||||
error=0;
|
||||
mem1a=HeapReAlloc(heap,HEAP_REALLOC_IN_PLACE_ONLY,mem1,memchunk+sysInfo.dwPageSize);
|
||||
if(mem1a!=NULL) {
|
||||
if(mem1a!=mem1) {
|
||||
error=1;
|
||||
}
|
||||
}
|
||||
ok(mem1a==NULL || error==0,"HeapReAlloc didn't honour HEAP_REALLOC_IN_PLACE_ONLY\n");
|
||||
|
||||
/* Check that HeapFree works correctly */
|
||||
if(mem1a) {
|
||||
ok(HeapFree(heap,0,mem1a),"HeapFree failed\n");
|
||||
} else {
|
||||
ok(HeapFree(heap,0,mem1),"HeapFree failed\n");
|
||||
}
|
||||
if(mem2a) {
|
||||
ok(HeapFree(heap,0,mem2a),"HeapFree failed\n");
|
||||
} else {
|
||||
ok(HeapFree(heap,0,mem2),"HeapFree failed\n");
|
||||
}
|
||||
|
||||
/* 0-length buffer */
|
||||
mem1 = HeapAlloc(heap, 0, 0);
|
||||
ok(mem1 != NULL, "Reserved memory\n");
|
||||
|
||||
dwSize = HeapSize(heap, 0, mem1);
|
||||
/* should work with 0-length buffer */
|
||||
ok((dwSize >= 0) && (dwSize < 0xFFFFFFFF),
|
||||
"The size of the 0-length buffer\n");
|
||||
ok(HeapFree(heap, 0, mem1), "Freed the 0-length buffer\n");
|
||||
|
||||
/* Check that HeapDestry works */
|
||||
ok(HeapDestroy(heap),"HeapDestroy failed\n");
|
||||
}
|
||||
|
||||
/* The following functions don't have tests, because either I don't know how
|
||||
to test them, or they are WinNT only, or require multiple threads.
|
||||
Since the last two issues shouldn't really stop the tests from being
|
||||
written, assume for now that it is all due to the first case
|
||||
GlobalFlags
|
||||
GlobalMemoryStatus
|
||||
GlobalMemoryStatusEx
|
||||
*/
|
||||
/* In addition, these features aren't being tested
|
||||
GMEM_DISCADABLE
|
||||
GMEM_NOCOMPACT
|
||||
*/
|
||||
static void test_Global(void)
|
||||
{
|
||||
ULONG memchunk;
|
||||
HGLOBAL mem1,mem2,mem2a,mem2b;
|
||||
UCHAR *mem2ptr;
|
||||
UINT error,i;
|
||||
memchunk=100000;
|
||||
|
||||
SetLastError(NO_ERROR);
|
||||
/* Check that a normal alloc works */
|
||||
mem1=GlobalAlloc(0,memchunk);
|
||||
ok(mem1!=NULL,"GlobalAlloc failed\n");
|
||||
if(mem1) {
|
||||
ok(GlobalSize(mem1)>=memchunk, "GlobalAlloc should return a big enough memory block\n");
|
||||
}
|
||||
|
||||
/* Check that a 'zeroing' alloc works */
|
||||
mem2=GlobalAlloc(GMEM_ZEROINIT,memchunk);
|
||||
ok(mem2!=NULL,"GlobalAlloc failed: error=%ld\n",GetLastError());
|
||||
if(mem2) {
|
||||
ok(GlobalSize(mem2)>=memchunk,"GlobalAlloc should return a big enough memory block\n");
|
||||
mem2ptr=GlobalLock(mem2);
|
||||
ok(mem2ptr==mem2,"GlobalLock should have returned the same memory as was allocated\n");
|
||||
if(mem2ptr) {
|
||||
error=0;
|
||||
for(i=0;i<memchunk;i++) {
|
||||
if(mem2ptr[i]!=0) {
|
||||
error=1;
|
||||
}
|
||||
}
|
||||
ok(!error,"GlobalAlloc should have zeroed out it's allocated memory\n");
|
||||
}
|
||||
}
|
||||
/* Check that GlobalReAlloc works */
|
||||
/* Check that we can change GMEM_FIXED to GMEM_MOVEABLE */
|
||||
mem2a=GlobalReAlloc(mem2,0,GMEM_MODIFY | GMEM_MOVEABLE);
|
||||
if(mem2a!=NULL) {
|
||||
mem2=mem2a;
|
||||
mem2ptr=GlobalLock(mem2a);
|
||||
ok(mem2ptr!=NULL && !GlobalUnlock(mem2a)&&GetLastError()==NO_ERROR,
|
||||
"Converting from FIXED to MOVEABLE didn't REALLY work\n");
|
||||
}
|
||||
|
||||
/* Check that ReAllocing memory works as expected */
|
||||
mem2a=GlobalReAlloc(mem2,2*memchunk,GMEM_MOVEABLE | GMEM_ZEROINIT);
|
||||
ok(mem2a!=NULL,"GlobalReAlloc failed\n");
|
||||
if(mem2a) {
|
||||
ok(GlobalSize(mem2a)>=2*memchunk,"GlobalReAlloc failed\n");
|
||||
mem2ptr=GlobalLock(mem2a);
|
||||
ok(mem2ptr!=NULL,"GlobalLock Failed\n");
|
||||
if(mem2ptr) {
|
||||
error=0;
|
||||
for(i=0;i<memchunk;i++) {
|
||||
if(mem2ptr[memchunk+i]!=0) {
|
||||
error=1;
|
||||
}
|
||||
}
|
||||
ok(!error,"GlobalReAlloc should have zeroed out it's allocated memory\n");
|
||||
|
||||
/* Check that GlobalHandle works */
|
||||
mem2b=GlobalHandle(mem2ptr);
|
||||
ok(mem2b==mem2a,"GlobalHandle didn't return the correct memory handle\n");
|
||||
|
||||
/* Check that we can't discard locked memory */
|
||||
mem2b=GlobalDiscard(mem2a);
|
||||
if(mem2b==NULL) {
|
||||
ok(!GlobalUnlock(mem2a) && GetLastError()==NO_ERROR,"GlobalUnlock Failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(mem1) {
|
||||
ok(GlobalFree(mem1)==NULL,"GlobalFree failed\n");
|
||||
}
|
||||
if(mem2a) {
|
||||
ok(GlobalFree(mem2a)==NULL,"GlobalFree failed\n");
|
||||
} else {
|
||||
ok(GlobalFree(mem2)==NULL,"GlobalFree failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The following functions don't have tests, because either I don't know how
|
||||
to test them, or they are WinNT only, or require multiple threads.
|
||||
Since the last two issues shouldn't really stop the tests from being
|
||||
written, assume for now that it is all due to the first case
|
||||
LocalDiscard
|
||||
LocalFlags
|
||||
*/
|
||||
/* In addition, these features aren't being tested
|
||||
LMEM_DISCADABLE
|
||||
LMEM_NOCOMPACT
|
||||
*/
|
||||
static void test_Local(void)
|
||||
{
|
||||
ULONG memchunk;
|
||||
HLOCAL mem1,mem2,mem2a,mem2b;
|
||||
UCHAR *mem2ptr;
|
||||
UINT error,i;
|
||||
memchunk=100000;
|
||||
|
||||
/* Check that a normal alloc works */
|
||||
mem1=LocalAlloc(0,memchunk);
|
||||
ok(mem1!=NULL,"LocalAlloc failed: error=%ld\n",GetLastError());
|
||||
if(mem1) {
|
||||
ok(LocalSize(mem1)>=memchunk, "LocalAlloc should return a big enough memory block\n");
|
||||
}
|
||||
|
||||
/* Check that a 'zeroing' and lock alloc works */
|
||||
mem2=LocalAlloc(LMEM_ZEROINIT|LMEM_MOVEABLE,memchunk);
|
||||
ok(mem2!=NULL,"LocalAlloc failed: error=%ld\n",GetLastError());
|
||||
if(mem2) {
|
||||
ok(LocalSize(mem2)>=memchunk,"LocalAlloc should return a big enough memory block\n");
|
||||
mem2ptr=LocalLock(mem2);
|
||||
ok(mem2ptr!=NULL,"LocalLock: error=%ld\n",GetLastError());
|
||||
if(mem2ptr) {
|
||||
error=0;
|
||||
for(i=0;i<memchunk;i++) {
|
||||
if(mem2ptr[i]!=0) {
|
||||
error=1;
|
||||
}
|
||||
}
|
||||
ok(!error,"LocalAlloc should have zeroed out it's allocated memory\n");
|
||||
SetLastError(0);
|
||||
error=LocalUnlock(mem2);
|
||||
ok(error==0 && GetLastError()==NO_ERROR,
|
||||
"LocalUnlock Failed: rc=%d err=%ld\n",error,GetLastError());
|
||||
}
|
||||
}
|
||||
mem2a=LocalFree(mem2);
|
||||
ok(mem2a==NULL, "LocalFree failed: %p\n",mem2a);
|
||||
|
||||
/* Reallocate mem2 as moveable memory */
|
||||
mem2=LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT,memchunk);
|
||||
ok(mem2!=NULL, "LocalAlloc failed to create moveable memory, error=%ld\n",GetLastError());
|
||||
|
||||
/* Check that ReAllocing memory works as expected */
|
||||
mem2a=LocalReAlloc(mem2,2*memchunk,LMEM_MOVEABLE | LMEM_ZEROINIT);
|
||||
ok(mem2a!=NULL,"LocalReAlloc failed, error=%ld\n",GetLastError());
|
||||
if(mem2a) {
|
||||
ok(LocalSize(mem2a)>=2*memchunk,"LocalReAlloc failed\n");
|
||||
mem2ptr=LocalLock(mem2a);
|
||||
ok(mem2ptr!=NULL,"LocalLock Failed\n");
|
||||
if(mem2ptr) {
|
||||
error=0;
|
||||
for(i=0;i<memchunk;i++) {
|
||||
if(mem2ptr[memchunk+i]!=0) {
|
||||
error=1;
|
||||
}
|
||||
}
|
||||
ok(!error,"LocalReAlloc should have zeroed out it's allocated memory\n");
|
||||
/* Check that LocalHandle works */
|
||||
mem2b=LocalHandle(mem2ptr);
|
||||
ok(mem2b==mem2a,"LocalHandle didn't return the correct memory handle\n");
|
||||
/* Check that we can't discard locked memory */
|
||||
mem2b=LocalDiscard(mem2a);
|
||||
ok(mem2b==NULL,"Discarded memory we shouldn't have\n");
|
||||
SetLastError(NO_ERROR);
|
||||
ok(!LocalUnlock(mem2a) && GetLastError()==NO_ERROR, "LocalUnlock Failed\n");
|
||||
}
|
||||
}
|
||||
if(mem1) {
|
||||
ok(LocalFree(mem1)==NULL,"LocalFree failed\n");
|
||||
}
|
||||
if(mem2a) {
|
||||
ok(LocalFree(mem2a)==NULL,"LocalFree failed\n");
|
||||
} else {
|
||||
ok(LocalFree(mem2)==NULL,"LocalFree failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* The Virtual* routines are not tested as thoroughly,
|
||||
since I don't really understand how to use them correctly :)
|
||||
The following routines are not tested at all
|
||||
VirtualAllocEx
|
||||
VirtualFreeEx
|
||||
VirtualLock
|
||||
VirtualProtect
|
||||
VirtualProtectEx
|
||||
VirtualQuery
|
||||
VirtualQueryEx
|
||||
VirtualUnlock
|
||||
And the only features (flags) being tested are
|
||||
MEM_COMMIT
|
||||
MEM_RELEASE
|
||||
PAGE_READWRITE
|
||||
Testing the rest requires using exceptions, which I really don't
|
||||
understand well
|
||||
*/
|
||||
static void test_Virtual(void)
|
||||
{
|
||||
SYSTEM_INFO sysInfo;
|
||||
ULONG memchunk;
|
||||
UCHAR *mem1;
|
||||
UINT error,i;
|
||||
|
||||
/* Retrieve the page size for this system */
|
||||
sysInfo.dwPageSize=0;
|
||||
GetSystemInfo(&sysInfo);
|
||||
ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
|
||||
|
||||
/* Choose a reasonable allocation size */
|
||||
memchunk=10*sysInfo.dwPageSize;
|
||||
|
||||
/* Check that a normal alloc works */
|
||||
mem1=VirtualAlloc(NULL,memchunk,MEM_COMMIT,PAGE_READWRITE);
|
||||
ok(mem1!=NULL,"VirtualAlloc failed\n");
|
||||
if(mem1) {
|
||||
/* check that memory is initialized to 0 */
|
||||
error=0;
|
||||
for(i=0;i<memchunk;i++) {
|
||||
if(mem1[i]!=0) {
|
||||
error=1;
|
||||
}
|
||||
}
|
||||
ok(!error,"VirtualAlloc did not initialize memory to '0's\n");
|
||||
/* Check that we can read/write to memory */
|
||||
error=0;
|
||||
for(i=0;i<memchunk;i+=100) {
|
||||
mem1[i]='a';
|
||||
if(mem1[i]!='a') {
|
||||
error=1;
|
||||
}
|
||||
}
|
||||
ok(!error,"Virtual memory was not writable\n");
|
||||
}
|
||||
ok(VirtualFree(mem1,0,MEM_RELEASE),"VirtualFree failed\n");
|
||||
}
|
||||
START_TEST(alloc)
|
||||
{
|
||||
test_Heap();
|
||||
test_Global();
|
||||
test_Local();
|
||||
test_Virtual();
|
||||
}
|
|
@ -1,624 +0,0 @@
|
|||
/*
|
||||
* Unit tests for atom functions
|
||||
*
|
||||
* Copyright (c) 2002 Alexandre Julliard
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "winuser.h"
|
||||
|
||||
#define DOUBLE(x) (WCHAR)((x<<8)|(x))
|
||||
|
||||
static const WCHAR foobarW[] = {'f','o','o','b','a','r',0};
|
||||
static const WCHAR FOOBARW[] = {'F','O','O','B','A','R',0};
|
||||
static const WCHAR _foobarW[] = {'_','f','o','o','b','a','r',0};
|
||||
|
||||
static void do_initA(char* tmp, const char* pattern, int len)
|
||||
{
|
||||
const char* p = pattern;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
*tmp++ = *p++;
|
||||
if (!*p) p = pattern;
|
||||
}
|
||||
*tmp = '\0';
|
||||
}
|
||||
|
||||
static void do_initW(WCHAR* tmp, const char* pattern, int len)
|
||||
{
|
||||
const char* p = pattern;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
*tmp++ = *p++;
|
||||
if (!*p) p = pattern;
|
||||
}
|
||||
*tmp = '\0';
|
||||
}
|
||||
|
||||
static void print_integral( WCHAR* buffer, int atom )
|
||||
{
|
||||
BOOL first = TRUE;
|
||||
|
||||
#define X(v) { if (atom >= v) {*buffer++ = '0' + atom / v; first = FALSE; } else if (!first || v == 1) *buffer++ = '0'; atom %= v; }
|
||||
*buffer++ = '#';
|
||||
X(10000);
|
||||
X(1000);
|
||||
X(100);
|
||||
X(10);
|
||||
X(1);
|
||||
*buffer = '\0';
|
||||
#undef X
|
||||
}
|
||||
|
||||
static BOOL unicode_OS;
|
||||
|
||||
static void test_add_atom(void)
|
||||
{
|
||||
ATOM atom, w_atom;
|
||||
int i;
|
||||
|
||||
SetLastError( 0xdeadbeef );
|
||||
atom = GlobalAddAtomA( "foobar" );
|
||||
ok( atom >= 0xc000, "bad atom id %x\n", atom );
|
||||
ok( GetLastError() == 0xdeadbeef, "GlobalAddAtomA set last error\n" );
|
||||
|
||||
/* Verify that it can be found (or not) appropriately */
|
||||
ok( GlobalFindAtomA( "foobar" ) == atom, "could not find atom foobar\n" );
|
||||
ok( GlobalFindAtomA( "FOOBAR" ) == atom, "could not find atom FOOBAR\n" );
|
||||
ok( !GlobalFindAtomA( "_foobar" ), "found _foobar\n" );
|
||||
|
||||
/* Add the same atom, specifying string as unicode; should
|
||||
* find the first one, not add a new one */
|
||||
SetLastError( 0xdeadbeef );
|
||||
w_atom = GlobalAddAtomW( foobarW );
|
||||
if (w_atom && GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
|
||||
unicode_OS = TRUE;
|
||||
else
|
||||
trace("WARNING: Unicode atom APIs are not supported on this platform\n");
|
||||
|
||||
if (unicode_OS)
|
||||
{
|
||||
ok( w_atom == atom, "Unicode atom does not match ASCII\n" );
|
||||
ok( GetLastError() == 0xdeadbeef, "GlobalAddAtomW set last error\n" );
|
||||
}
|
||||
|
||||
/* Verify that it can be found (or not) appropriately via unicode name */
|
||||
if (unicode_OS)
|
||||
{
|
||||
ok( GlobalFindAtomW( foobarW ) == atom, "could not find atom foobar\n" );
|
||||
ok( GlobalFindAtomW( FOOBARW ) == atom, "could not find atom FOOBAR\n" );
|
||||
ok( !GlobalFindAtomW( _foobarW ), "found _foobar\n" );
|
||||
}
|
||||
|
||||
/* Test integer atoms
|
||||
* (0x0001 .. 0xbfff) should be valid;
|
||||
* (0xc000 .. 0xffff) should be invalid */
|
||||
|
||||
SetLastError( 0xdeadbeef );
|
||||
ok( GlobalAddAtomA(0) == 0 && GetLastError() == 0xdeadbeef, "succeeded to add atom 0\n" );
|
||||
if (unicode_OS)
|
||||
{
|
||||
SetLastError( 0xdeadbeef );
|
||||
ok( GlobalAddAtomW(0) == 0 && GetLastError() == 0xdeadbeef, "succeeded to add atom 0\n" );
|
||||
}
|
||||
|
||||
SetLastError( 0xdeadbeef );
|
||||
for (i = 1; i <= 0xbfff; i++)
|
||||
{
|
||||
SetLastError( 0xdeadbeef );
|
||||
ok( GlobalAddAtomA((LPCSTR)i) == i && GetLastError() == 0xdeadbeef,
|
||||
"failed to add atom %x\n", i );
|
||||
if (unicode_OS)
|
||||
{
|
||||
SetLastError( 0xdeadbeef );
|
||||
ok( GlobalAddAtomW((LPCWSTR)i) == i && GetLastError() == 0xdeadbeef,
|
||||
"failed to add atom %x\n", i );
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0xc000; i <= 0xffff; i++)
|
||||
{
|
||||
ok( !GlobalAddAtomA((LPCSTR)i), "succeeded adding %x\n", i );
|
||||
if (unicode_OS)
|
||||
ok( !GlobalAddAtomW((LPCWSTR)i), "succeeded adding %x\n", i );
|
||||
}
|
||||
}
|
||||
|
||||
static void test_get_atom_name(void)
|
||||
{
|
||||
char buf[10];
|
||||
WCHAR bufW[10];
|
||||
int i;
|
||||
UINT len;
|
||||
static const WCHAR resultW[] = {'f','o','o','b','a','r',0,'.','.','.'};
|
||||
char in[257], out[257];
|
||||
WCHAR inW[257], outW[257];
|
||||
|
||||
ATOM atom = GlobalAddAtomA( "foobar" );
|
||||
|
||||
/* Get the name of the atom we added above */
|
||||
memset( buf, '.', sizeof(buf) );
|
||||
len = GlobalGetAtomNameA( atom, buf, 10 );
|
||||
ok( len == strlen("foobar"), "bad length %d\n", len );
|
||||
ok( !memcmp( buf, "foobar\0...", 10 ), "bad buffer contents\n" );
|
||||
|
||||
/* Repeat, unicode-style */
|
||||
if (unicode_OS)
|
||||
{
|
||||
for (i = 0; i < 10; i++) bufW[i] = '.';
|
||||
SetLastError( 0xdeadbeef );
|
||||
len = GlobalGetAtomNameW( atom, bufW, 10 );
|
||||
ok( len && GetLastError() == 0xdeadbeef, "GlobalGetAtomNameW failed\n" );
|
||||
ok( len == lstrlenW(foobarW), "bad length %d\n", len );
|
||||
ok( !memcmp( bufW, resultW, 10*sizeof(WCHAR) ), "bad buffer contents\n" );
|
||||
}
|
||||
|
||||
/* Check error code returns */
|
||||
memset(buf, '.', 10);
|
||||
ok( !GlobalGetAtomNameA( atom, buf, 0 ), "succeeded\n" );
|
||||
ok( !memcmp( buf, "..........", 10 ), "should not touch buffer\n" );
|
||||
|
||||
if (unicode_OS)
|
||||
{
|
||||
static const WCHAR sampleW[10] = {'.','.','.','.','.','.','.','.','.','.'};
|
||||
|
||||
for (i = 0; i < 10; i++) bufW[i] = '.';
|
||||
ok( !GlobalGetAtomNameW( atom, bufW, 0 ), "succeeded\n" );
|
||||
ok( !memcmp( bufW, sampleW, 10 * sizeof(WCHAR) ), "should not touch buffer\n" );
|
||||
}
|
||||
|
||||
/* Test integer atoms */
|
||||
for (i = 0; i <= 0xbfff; i++)
|
||||
{
|
||||
memset( buf, 'a', 10 );
|
||||
len = GlobalGetAtomNameA( (ATOM)i, buf, 10 );
|
||||
if (i)
|
||||
{
|
||||
char res[20];
|
||||
ok( (len > 1) && (len < 7), "bad length %d\n", len );
|
||||
sprintf( res, "#%d", i );
|
||||
memset( res + strlen(res) + 1, 'a', 10 );
|
||||
ok( !memcmp( res, buf, 10 ), "bad buffer contents %s\n", buf );
|
||||
}
|
||||
else
|
||||
ok( !len, "bad length %d\n", len );
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
len = GlobalGetAtomNameA( (ATOM)i, buf, 2);
|
||||
if (!len) /* the NT way */
|
||||
{
|
||||
ok(GetLastError() == (i ? ERROR_MORE_DATA : ERROR_INVALID_PARAMETER) ||
|
||||
GetLastError() == 0xdeadbeef, /* the Win 9x way */
|
||||
"wrong error conditions %lu for %u\n", GetLastError(), i);
|
||||
}
|
||||
else /* the Win 9x way */
|
||||
{
|
||||
ok(GetLastError() == 0xdeadbeef,
|
||||
"wrong error conditions %lu for %u\n", GetLastError(), i);
|
||||
}
|
||||
}
|
||||
|
||||
memset( buf, '.', sizeof(buf) );
|
||||
len = GlobalGetAtomNameA( atom, buf, 6 );
|
||||
ok( len == 0, "bad length %d\n", len );
|
||||
ok( !memcmp( buf, "fooba\0....", 10 ), "bad buffer contents\n");
|
||||
if (unicode_OS)
|
||||
{
|
||||
static const WCHAR resW[] = {'f','o','o','b','a','r','.','.','.','.'};
|
||||
for (len = 0; len < 10; len++) bufW[len] = '.';
|
||||
SetLastError(0xdeadbeef);
|
||||
len = GlobalGetAtomNameW( atom, bufW, 6 );
|
||||
ok( len && GetLastError() == 0xdeadbeef, "GlobalGetAtomNameW failed\n" );
|
||||
ok( len == lstrlenW(foobarW), "bad length %d\n", len );
|
||||
ok( !memcmp( bufW, resW, 10*sizeof(WCHAR) ), "bad buffer contents\n" );
|
||||
}
|
||||
|
||||
/* test string limits & overflow */
|
||||
do_initA(in, "abcdefghij", 255);
|
||||
atom = GlobalAddAtomA(in);
|
||||
ok(atom, "couldn't add atom for %s\n", in);
|
||||
len = GlobalGetAtomNameA(atom, out, sizeof(out));
|
||||
ok(len == 255, "length mismatch (%u instead of 255)\n", len);
|
||||
for (i = 0; i < 255; i++)
|
||||
{
|
||||
ok(out[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, out[i], "abcdefghij"[i % 10]);
|
||||
}
|
||||
ok(out[255] == '\0', "wrong end of string\n");
|
||||
memset(out, '.', sizeof(out));
|
||||
SetLastError(0xdeadbeef);
|
||||
len = GlobalGetAtomNameA(atom, out, 10);
|
||||
if (!len) /* the NT way */
|
||||
{
|
||||
ok(GetLastError() == ERROR_MORE_DATA, "wrong error code (%lu instead of %u)\n", GetLastError(), ERROR_MORE_DATA);
|
||||
}
|
||||
else /* the Win9x way */
|
||||
{
|
||||
ok(GetLastError() == 0xdeadbeef, "wrong error code (%lu instead of %u)\n", GetLastError(), 0xdeadbeef);
|
||||
}
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
ok(out[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, out[i], "abcdefghij"[i % 10]);
|
||||
}
|
||||
ok(out[9] == '\0', "wrong end of string\n");
|
||||
ok(out[10] == '.', "wrote after end of buf\n");
|
||||
do_initA(in, "abcdefghij", 256);
|
||||
atom = GlobalAddAtomA(in);
|
||||
ok(!atom, "succeeded\n");
|
||||
if (unicode_OS)
|
||||
{
|
||||
/* test integral atoms */
|
||||
for (i = 0; i <= 0xbfff; i++)
|
||||
{
|
||||
memset(outW, 'a', sizeof(outW));
|
||||
len = GlobalGetAtomNameW( (ATOM)i, outW, 10 );
|
||||
if (i)
|
||||
{
|
||||
WCHAR res[20];
|
||||
|
||||
ok( (len > 1) && (len < 7), "bad length %d\n", len );
|
||||
print_integral( res, i );
|
||||
memset( res + lstrlenW(res) + 1, 'a', 10 * sizeof(WCHAR));
|
||||
ok( !memcmp( res, outW, 10 * sizeof(WCHAR) ), "bad buffer contents for %d\n", i );
|
||||
}
|
||||
else
|
||||
ok( !len, "bad length %d\n", len );
|
||||
|
||||
memset(outW, '.', sizeof(outW));
|
||||
SetLastError(0xdeadbeef);
|
||||
len = GlobalGetAtomNameW( (ATOM)i, outW, 1);
|
||||
if (i)
|
||||
{
|
||||
/* len == 0 with ERROR_MORE_DATA is on NT3.51 */
|
||||
ok(len == 1 || (len == 0 && GetLastError() == ERROR_MORE_DATA),
|
||||
"0x%04x: got %u with %ld (excepted '1' or '0' with " \
|
||||
"ERROR_MORE_DATA)\n", i, len, GetLastError());
|
||||
ok(outW[1] == DOUBLE('.'), "buffer overwrite\n");
|
||||
}
|
||||
else ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "0 badly handled\n");
|
||||
}
|
||||
|
||||
do_initW(inW, "abcdefghij", 255);
|
||||
atom = GlobalAddAtomW(inW);
|
||||
ok(atom, "couldn't add atom for %s\n", in);
|
||||
len = GlobalGetAtomNameW(atom, outW, sizeof(outW));
|
||||
ok(len == 255, "length mismatch (%u instead of 255)\n", len);
|
||||
for (i = 0; i < 255; i++)
|
||||
{
|
||||
ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
|
||||
}
|
||||
ok(outW[255] == '\0', "wrong end of string\n");
|
||||
memset(outW, '.', sizeof(outW));
|
||||
len = GlobalGetAtomNameW(atom, outW, 10);
|
||||
ok(len == 10, "succeeded\n");
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
|
||||
}
|
||||
ok(outW[10] == DOUBLE('.'), "wrote after end of buf\n");
|
||||
do_initW(inW, "abcdefghij", 256);
|
||||
atom = GlobalAddAtomW(inW);
|
||||
ok(!atom, "succeeded\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error code\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void test_error_handling(void)
|
||||
{
|
||||
char buffer[260];
|
||||
WCHAR bufferW[260];
|
||||
int i;
|
||||
|
||||
memset( buffer, 'a', 256 );
|
||||
buffer[256] = 0;
|
||||
ok( !GlobalAddAtomA(buffer), "add succeeded\n" );
|
||||
ok( !GlobalFindAtomA(buffer), "find succeeded\n" );
|
||||
|
||||
if (unicode_OS)
|
||||
{
|
||||
for (i = 0; i < 256; i++) bufferW[i] = 'b';
|
||||
bufferW[256] = 0;
|
||||
ok( !GlobalAddAtomW(bufferW), "add succeeded\n" );
|
||||
ok( !GlobalFindAtomW(bufferW), "find succeeded\n" );
|
||||
}
|
||||
}
|
||||
|
||||
static void test_local_add_atom(void)
|
||||
{
|
||||
ATOM atom, w_atom;
|
||||
int i;
|
||||
|
||||
SetLastError( 0xdeadbeef );
|
||||
atom = AddAtomA( "foobar" );
|
||||
ok( atom >= 0xc000, "bad atom id %x\n", atom );
|
||||
ok( GetLastError() == 0xdeadbeef, "AddAtomA set last error\n" );
|
||||
|
||||
/* Verify that it can be found (or not) appropriately */
|
||||
ok( FindAtomA( "foobar" ) == atom, "could not find atom foobar\n" );
|
||||
ok( FindAtomA( "FOOBAR" ) == atom, "could not find atom FOOBAR\n" );
|
||||
ok( !FindAtomA( "_foobar" ), "found _foobar\n" );
|
||||
|
||||
/* Add the same atom, specifying string as unicode; should
|
||||
* find the first one, not add a new one */
|
||||
SetLastError( 0xdeadbeef );
|
||||
w_atom = AddAtomW( foobarW );
|
||||
if (w_atom && GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
|
||||
unicode_OS = TRUE;
|
||||
else
|
||||
trace("WARNING: Unicode atom APIs are not supported on this platform\n");
|
||||
|
||||
if (unicode_OS)
|
||||
{
|
||||
ok( w_atom == atom, "Unicode atom does not match ASCII\n" );
|
||||
ok( GetLastError() == 0xdeadbeef, "AddAtomW set last error\n" );
|
||||
}
|
||||
|
||||
/* Verify that it can be found (or not) appropriately via unicode name */
|
||||
if (unicode_OS)
|
||||
{
|
||||
ok( FindAtomW( foobarW ) == atom, "could not find atom foobar\n" );
|
||||
ok( FindAtomW( FOOBARW ) == atom, "could not find atom FOOBAR\n" );
|
||||
ok( !FindAtomW( _foobarW ), "found _foobar\n" );
|
||||
}
|
||||
|
||||
/* Test integer atoms
|
||||
* (0x0001 .. 0xbfff) should be valid;
|
||||
* (0xc000 .. 0xffff) should be invalid */
|
||||
|
||||
SetLastError( 0xdeadbeef );
|
||||
ok( AddAtomA(0) == 0 && GetLastError() == 0xdeadbeef, "succeeded to add atom 0\n" );
|
||||
if (unicode_OS)
|
||||
{
|
||||
SetLastError( 0xdeadbeef );
|
||||
ok( AddAtomW(0) == 0 && GetLastError() == 0xdeadbeef, "succeeded to add atom 0\n" );
|
||||
}
|
||||
|
||||
SetLastError( 0xdeadbeef );
|
||||
for (i = 1; i <= 0xbfff; i++)
|
||||
{
|
||||
SetLastError( 0xdeadbeef );
|
||||
ok( AddAtomA((LPCSTR)i) == i && GetLastError() == 0xdeadbeef,
|
||||
"failed to add atom %x\n", i );
|
||||
if (unicode_OS)
|
||||
{
|
||||
SetLastError( 0xdeadbeef );
|
||||
ok( AddAtomW((LPCWSTR)i) == i && GetLastError() == 0xdeadbeef,
|
||||
"failed to add atom %x\n", i );
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0xc000; i <= 0xffff; i++)
|
||||
{
|
||||
ok( !AddAtomA((LPCSTR)i), "succeeded adding %x\n", i );
|
||||
if (unicode_OS)
|
||||
ok( !AddAtomW((LPCWSTR)i), "succeeded adding %x\n", i );
|
||||
}
|
||||
}
|
||||
|
||||
static void test_local_get_atom_name(void)
|
||||
{
|
||||
char buf[10], in[257], out[257];
|
||||
WCHAR bufW[10], inW[257], outW[257];
|
||||
int i;
|
||||
UINT len;
|
||||
static const WCHAR resultW[] = {'f','o','o','b','a','r',0,'.','.','.'};
|
||||
|
||||
ATOM atom = AddAtomA( "foobar" );
|
||||
|
||||
/* Get the name of the atom we added above */
|
||||
memset( buf, '.', sizeof(buf) );
|
||||
len = GetAtomNameA( atom, buf, 10 );
|
||||
ok( len == strlen("foobar"), "bad length %d\n", len );
|
||||
ok( !memcmp( buf, "foobar\0...", 10 ), "bad buffer contents\n" );
|
||||
|
||||
/* Repeat, unicode-style */
|
||||
if (unicode_OS)
|
||||
{
|
||||
for (i = 0; i < 10; i++) bufW[i] = '.';
|
||||
SetLastError( 0xdeadbeef );
|
||||
len = GetAtomNameW( atom, bufW, 10 );
|
||||
ok( len && GetLastError() == 0xdeadbeef, "GetAtomNameW failed\n" );
|
||||
ok( len == lstrlenW(foobarW), "bad length %d\n", len );
|
||||
ok( !memcmp( bufW, resultW, 10*sizeof(WCHAR) ), "bad buffer contents\n" );
|
||||
}
|
||||
|
||||
/* Get the name of the atom we added above */
|
||||
memset( buf, '.', sizeof(buf) );
|
||||
len = GetAtomNameA( atom, buf, 6 );
|
||||
ok( len == 5, "bad length %d\n", len );
|
||||
ok( !memcmp( buf, "fooba\0....", 10 ), "bad buffer contents\n" );
|
||||
|
||||
/* Repeat, unicode-style */
|
||||
if (unicode_OS)
|
||||
{
|
||||
WCHAR resW[] = {'f','o','o','b','a','\0','.','.','.','.'};
|
||||
for (i = 0; i < 10; i++) bufW[i] = '.';
|
||||
SetLastError( 0xdeadbeef );
|
||||
len = GetAtomNameW( atom, bufW, 6 );
|
||||
ok( len && GetLastError() == 0xdeadbeef, "GlobalGetAtomNameW failed\n" );
|
||||
ok( len == 5, "bad length %d\n", len );
|
||||
ok( !memcmp( bufW, resW, 10*sizeof(WCHAR) ), "bad buffer contents\n" );
|
||||
}
|
||||
|
||||
/* Check error code returns */
|
||||
memset(buf, '.', 10);
|
||||
ok( !GetAtomNameA( atom, buf, 0 ), "succeeded\n" );
|
||||
ok( !memcmp( buf, "..........", 10 ), "should not touch buffer\n" );
|
||||
|
||||
if (unicode_OS)
|
||||
{
|
||||
static const WCHAR sampleW[10] = {'.','.','.','.','.','.','.','.','.','.'};
|
||||
|
||||
for (i = 0; i < 10; i++) bufW[i] = '.';
|
||||
ok( !GetAtomNameW( atom, bufW, 0 ), "succeeded\n" );
|
||||
ok( !memcmp( bufW, sampleW, 10 * sizeof(WCHAR) ), "should not touch buffer\n" );
|
||||
}
|
||||
|
||||
/* Test integer atoms */
|
||||
for (i = 0; i <= 0xbfff; i++)
|
||||
{
|
||||
memset( buf, 'a', 10 );
|
||||
len = GetAtomNameA( (ATOM)i, buf, 10 );
|
||||
if (i)
|
||||
{
|
||||
char res[20];
|
||||
ok( (len > 1) && (len < 7), "bad length %d for %s\n", len, buf );
|
||||
sprintf( res, "#%d", i );
|
||||
memset( res + strlen(res) + 1, 'a', 10 );
|
||||
ok( !memcmp( res, buf, 10 ), "bad buffer contents %s\n", buf );
|
||||
}
|
||||
else
|
||||
ok( !len, "bad length %d\n", len );
|
||||
|
||||
len = GetAtomNameA( (ATOM)i, buf, 1);
|
||||
ok(!len, "succeed with %u for %u\n", len, i);
|
||||
|
||||
/* ERROR_MORE_DATA is on nt3.51 sp5 */
|
||||
if (i)
|
||||
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER ||
|
||||
GetLastError() == ERROR_MORE_DATA ||
|
||||
GetLastError() == 0xdeadbeef, /* the Win 9x way */
|
||||
"wrong error conditions %lu for %u\n", GetLastError(), i);
|
||||
else
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER ||
|
||||
GetLastError() == ERROR_MORE_DATA ||
|
||||
GetLastError() == 0xdeadbeef, /* the Win 9x way */
|
||||
"wrong error conditions %lu for %u\n", GetLastError(), i);
|
||||
}
|
||||
/* test string limits & overflow */
|
||||
do_initA(in, "abcdefghij", 255);
|
||||
atom = AddAtomA(in);
|
||||
ok(atom, "couldn't add atom for %s\n", in);
|
||||
len = GetAtomNameA(atom, out, sizeof(out));
|
||||
ok(len == 255, "length mismatch (%u instead of 255)\n", len);
|
||||
for (i = 0; i < 255; i++)
|
||||
{
|
||||
ok(out[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, out[i], "abcdefghij"[i % 10]);
|
||||
}
|
||||
ok(out[255] == '\0', "wrong end of string\n");
|
||||
memset(out, '.', sizeof(out));
|
||||
len = GetAtomNameA(atom, out, 10);
|
||||
ok(len == 9, "succeeded %d\n", len);
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
ok(out[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, out[i], "abcdefghij"[i % 10]);
|
||||
}
|
||||
ok(out[9] == '\0', "wrong end of string\n");
|
||||
ok(out[10] == '.', "buffer overwrite\n");
|
||||
do_initA(in, "abcdefghij", 256);
|
||||
atom = AddAtomA(in);
|
||||
ok(!atom, "succeeded\n");
|
||||
|
||||
/* ERROR_MORE_DATA is on nt3.51 sp5 */
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER ||
|
||||
GetLastError() == ERROR_MORE_DATA ||
|
||||
GetLastError() == 0xdeadbeef, /* the Win 9x way */
|
||||
"wrong error code (%lu)\n", GetLastError());
|
||||
|
||||
if (unicode_OS)
|
||||
{
|
||||
/* test integral atoms */
|
||||
for (i = 0; i <= 0xbfff; i++)
|
||||
{
|
||||
memset(outW, 'a', sizeof(outW));
|
||||
len = GetAtomNameW( (ATOM)i, outW, 10 );
|
||||
if (i)
|
||||
{
|
||||
WCHAR res[20];
|
||||
|
||||
ok( (len > 1) && (len < 7), "bad length %d\n", len );
|
||||
print_integral( res, i );
|
||||
memset( res + lstrlenW(res) + 1, 'a', 10 * sizeof(WCHAR));
|
||||
ok( !memcmp( res, outW, 10 * sizeof(WCHAR) ), "bad buffer contents for %d\n", i );
|
||||
}
|
||||
else
|
||||
ok( !len, "bad length %d\n", len );
|
||||
|
||||
len = GetAtomNameW( (ATOM)i, outW, 1);
|
||||
ok(!len, "succeed with %u for %u\n", len, i);
|
||||
|
||||
/* ERROR_MORE_DATA is on nt3.51 sp5 */
|
||||
ok(GetLastError() == ERROR_MORE_DATA ||
|
||||
GetLastError() == (i ? ERROR_INSUFFICIENT_BUFFER : ERROR_INVALID_PARAMETER),
|
||||
"wrong error conditions %lu for %u\n", GetLastError(), i);
|
||||
}
|
||||
do_initW(inW, "abcdefghij", 255);
|
||||
atom = AddAtomW(inW);
|
||||
ok(atom, "couldn't add atom for %s\n", in);
|
||||
len = GetAtomNameW(atom, outW, sizeof(outW));
|
||||
ok(len == 255, "length mismatch (%u instead of 255)\n", len);
|
||||
for (i = 0; i < 255; i++)
|
||||
{
|
||||
ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
|
||||
}
|
||||
ok(outW[255] == '\0', "wrong end of string\n");
|
||||
memset(outW, '.', sizeof(outW));
|
||||
len = GetAtomNameW(atom, outW, 10);
|
||||
ok(len == 9, "succeeded %d\n", len);
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
|
||||
}
|
||||
ok(outW[9] == '\0', "wrong end of string\n");
|
||||
ok(outW[10] == DOUBLE('.'), "buffer overwrite\n");
|
||||
do_initW(inW, "abcdefghij", 256);
|
||||
atom = AddAtomW(inW);
|
||||
ok(!atom, "succeeded\n");
|
||||
|
||||
/* ERROR_MORE_DATA is on nt3.51 sp5 */
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER ||
|
||||
GetLastError() == ERROR_MORE_DATA,
|
||||
"wrong error code (%lu)\n", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
static void test_local_error_handling(void)
|
||||
{
|
||||
char buffer[260];
|
||||
WCHAR bufferW[260];
|
||||
int i;
|
||||
|
||||
memset( buffer, 'a', 256 );
|
||||
buffer[256] = 0;
|
||||
ok( !AddAtomA(buffer), "add succeeded\n" );
|
||||
ok( !FindAtomA(buffer), "find succeeded\n" );
|
||||
|
||||
if (unicode_OS)
|
||||
{
|
||||
for (i = 0; i < 256; i++) bufferW[i] = 'b';
|
||||
bufferW[256] = 0;
|
||||
ok( !AddAtomW(bufferW), "add succeeded\n" );
|
||||
ok( !FindAtomW(bufferW), "find succeeded\n" );
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(atom)
|
||||
{
|
||||
test_add_atom();
|
||||
test_get_atom_name();
|
||||
test_error_handling();
|
||||
test_local_add_atom();
|
||||
test_local_get_atom_name();
|
||||
test_local_error_handling();
|
||||
}
|
|
@ -1,713 +0,0 @@
|
|||
/*
|
||||
* Tests for file change notification functions
|
||||
*
|
||||
* Copyright (c) 2004 Hans Leidekker
|
||||
* Copyright 2006 Mike McCormack 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
|
||||
*/
|
||||
|
||||
/* TODO: - security attribute changes
|
||||
* - compound filter and multiple notifications
|
||||
* - subtree notifications
|
||||
* - non-documented flags FILE_NOTIFY_CHANGE_LAST_ACCESS and
|
||||
* FILE_NOTIFY_CHANGE_CREATION
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "wine/test.h"
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winternl.h>
|
||||
|
||||
static DWORD CALLBACK NotificationThread(LPVOID arg)
|
||||
{
|
||||
HANDLE change = (HANDLE) arg;
|
||||
BOOL ret = FALSE;
|
||||
DWORD status;
|
||||
|
||||
status = WaitForSingleObject(change, 100);
|
||||
|
||||
if (status == WAIT_OBJECT_0 ) {
|
||||
ret = FindNextChangeNotification(change);
|
||||
}
|
||||
|
||||
ret = FindCloseChangeNotification(change);
|
||||
ok( ret, "FindCloseChangeNotification error: %ld\n",
|
||||
GetLastError());
|
||||
|
||||
ExitThread((DWORD)ret);
|
||||
}
|
||||
|
||||
static HANDLE StartNotificationThread(LPCSTR path, BOOL subtree, DWORD flags)
|
||||
{
|
||||
HANDLE change, thread;
|
||||
DWORD threadId;
|
||||
|
||||
change = FindFirstChangeNotificationA(path, subtree, flags);
|
||||
ok(change != INVALID_HANDLE_VALUE, "FindFirstChangeNotification error: %ld\n", GetLastError());
|
||||
|
||||
thread = CreateThread(NULL, 0, NotificationThread, (LPVOID)change,
|
||||
0, &threadId);
|
||||
ok(thread != INVALID_HANDLE_VALUE, "CreateThread error: %ld\n", GetLastError());
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
static DWORD FinishNotificationThread(HANDLE thread)
|
||||
{
|
||||
DWORD status, exitcode;
|
||||
|
||||
status = WaitForSingleObject(thread, 5000);
|
||||
ok(status == WAIT_OBJECT_0, "WaitForSingleObject status %ld error %ld\n", status, GetLastError());
|
||||
|
||||
ok(GetExitCodeThread(thread, &exitcode), "Could not retrieve thread exit code\n");
|
||||
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
static void test_FindFirstChangeNotification(void)
|
||||
{
|
||||
HANDLE change, file, thread;
|
||||
DWORD attributes, count;
|
||||
BOOL ret;
|
||||
|
||||
char workdir[MAX_PATH], dirname1[MAX_PATH], dirname2[MAX_PATH];
|
||||
char filename1[MAX_PATH], filename2[MAX_PATH];
|
||||
static const char prefix[] = "FCN";
|
||||
char buffer[2048];
|
||||
|
||||
/* pathetic checks */
|
||||
|
||||
change = FindFirstChangeNotificationA("not-a-file", FALSE, FILE_NOTIFY_CHANGE_FILE_NAME);
|
||||
ok(change == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND,
|
||||
"FindFirstChangeNotification error: %ld\n", GetLastError());
|
||||
|
||||
if (0) /* This documents win2k behavior. It crashes on win98. */
|
||||
{
|
||||
change = FindFirstChangeNotificationA(NULL, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME);
|
||||
ok(change == NULL && GetLastError() == ERROR_PATH_NOT_FOUND,
|
||||
"FindFirstChangeNotification error: %ld\n", GetLastError());
|
||||
}
|
||||
|
||||
ret = FindNextChangeNotification(NULL);
|
||||
ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FindNextChangeNotification error: %ld\n",
|
||||
GetLastError());
|
||||
|
||||
ret = FindCloseChangeNotification(NULL);
|
||||
ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FindCloseChangeNotification error: %ld\n",
|
||||
GetLastError());
|
||||
|
||||
ret = GetTempPathA(MAX_PATH, workdir);
|
||||
ok(ret, "GetTempPathA error: %ld\n", GetLastError());
|
||||
|
||||
lstrcatA(workdir, "testFileChangeNotification");
|
||||
|
||||
ret = CreateDirectoryA(workdir, NULL);
|
||||
ok(ret, "CreateDirectoryA error: %ld\n", GetLastError());
|
||||
|
||||
ret = GetTempFileNameA(workdir, prefix, 0, filename1);
|
||||
ok(ret, "GetTempFileNameA error: %ld\n", GetLastError());
|
||||
|
||||
file = CreateFileA(filename1, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %ld\n", GetLastError());
|
||||
ret = CloseHandle(file);
|
||||
ok( ret, "CloseHandle error: %ld\n", GetLastError());
|
||||
|
||||
/* Try to register notification for a file. win98 and win2k behave differently here */
|
||||
change = FindFirstChangeNotificationA(filename1, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME);
|
||||
ok(change == INVALID_HANDLE_VALUE && (GetLastError() == ERROR_DIRECTORY ||
|
||||
GetLastError() == ERROR_FILE_NOT_FOUND),
|
||||
"FindFirstChangeNotification error: %ld\n", GetLastError());
|
||||
|
||||
lstrcpyA(dirname1, filename1);
|
||||
lstrcatA(dirname1, "dir");
|
||||
|
||||
lstrcpyA(dirname2, dirname1);
|
||||
lstrcatA(dirname2, "new");
|
||||
|
||||
ret = CreateDirectoryA(dirname1, NULL);
|
||||
ok(ret, "CreateDirectoryA error: %ld\n", GetLastError());
|
||||
|
||||
/* What if we move the directory we registered notification for? */
|
||||
thread = StartNotificationThread(dirname1, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME);
|
||||
ret = MoveFileA(dirname1, dirname2);
|
||||
ok(ret, "MoveFileA error: %ld\n", GetLastError());
|
||||
ok(FinishNotificationThread(thread), "Missed notification\n");
|
||||
|
||||
/* What if we remove the directory we registered notification for? */
|
||||
thread = StartNotificationThread(dirname2, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME);
|
||||
ret = RemoveDirectoryA(dirname2);
|
||||
ok(ret, "RemoveDirectoryA error: %ld\n", GetLastError());
|
||||
|
||||
/* win98 and win2k behave differently here */
|
||||
ret = FinishNotificationThread(thread);
|
||||
ok(ret || !ret, "You'll never read this\n");
|
||||
|
||||
/* functional checks */
|
||||
|
||||
/* Create a directory */
|
||||
thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME);
|
||||
ret = CreateDirectoryA(dirname1, NULL);
|
||||
ok(ret, "CreateDirectoryA error: %ld\n", GetLastError());
|
||||
ok(FinishNotificationThread(thread), "Missed notification\n");
|
||||
|
||||
/* Rename a directory */
|
||||
thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME);
|
||||
ret = MoveFileA(dirname1, dirname2);
|
||||
ok(ret, "MoveFileA error: %ld\n", GetLastError());
|
||||
ok(FinishNotificationThread(thread), "Missed notification\n");
|
||||
|
||||
/* Delete a directory */
|
||||
thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME);
|
||||
ret = RemoveDirectoryA(dirname2);
|
||||
ok(ret, "RemoveDirectoryA error: %ld\n", GetLastError());
|
||||
ok(FinishNotificationThread(thread), "Missed notification\n");
|
||||
|
||||
lstrcpyA(filename2, filename1);
|
||||
lstrcatA(filename2, "new");
|
||||
|
||||
/* Rename a file */
|
||||
thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME);
|
||||
ret = MoveFileA(filename1, filename2);
|
||||
ok(ret, "MoveFileA error: %ld\n", GetLastError());
|
||||
ok(FinishNotificationThread(thread), "Missed notification\n");
|
||||
|
||||
/* Delete a file */
|
||||
thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME);
|
||||
ret = DeleteFileA(filename2);
|
||||
ok(ret, "DeleteFileA error: %ld\n", GetLastError());
|
||||
ok(FinishNotificationThread(thread), "Missed notification\n");
|
||||
|
||||
/* Create a file */
|
||||
thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME);
|
||||
file = CreateFileA(filename2, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %ld\n", GetLastError());
|
||||
ret = CloseHandle(file);
|
||||
ok( ret, "CloseHandle error: %ld\n", GetLastError());
|
||||
ok(FinishNotificationThread(thread), "Missed notification\n");
|
||||
|
||||
attributes = GetFileAttributesA(filename2);
|
||||
ok(attributes != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA error: %ld\n", GetLastError());
|
||||
attributes &= FILE_ATTRIBUTE_READONLY;
|
||||
|
||||
/* Change file attributes */
|
||||
thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_ATTRIBUTES);
|
||||
ret = SetFileAttributesA(filename2, attributes);
|
||||
ok(ret, "SetFileAttributesA error: %ld\n", GetLastError());
|
||||
ok(FinishNotificationThread(thread), "Missed notification\n");
|
||||
|
||||
/* Change last write time by writing to a file */
|
||||
thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
|
||||
file = CreateFileA(filename2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %ld\n", GetLastError());
|
||||
ret = WriteFile(file, buffer, sizeof(buffer), &count, NULL);
|
||||
ok(ret && count == sizeof(buffer), "WriteFile error: %ld\n", GetLastError());
|
||||
ret = CloseHandle(file);
|
||||
ok( ret, "CloseHandle error: %ld\n", GetLastError());
|
||||
ok(FinishNotificationThread(thread), "Missed notification\n");
|
||||
|
||||
/* Change file size by truncating a file */
|
||||
thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_SIZE);
|
||||
file = CreateFileA(filename2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %ld\n", GetLastError());
|
||||
ret = WriteFile(file, buffer, sizeof(buffer) / 2, &count, NULL);
|
||||
ok(ret && count == sizeof(buffer) / 2, "WriteFileA error: %ld\n", GetLastError());
|
||||
ret = CloseHandle(file);
|
||||
ok( ret, "CloseHandle error: %ld\n", GetLastError());
|
||||
ok(FinishNotificationThread(thread), "Missed notification\n");
|
||||
|
||||
/* clean up */
|
||||
|
||||
ret = DeleteFileA(filename2);
|
||||
ok(ret, "DeleteFileA error: %ld\n", GetLastError());
|
||||
|
||||
ret = RemoveDirectoryA(workdir);
|
||||
ok(ret, "RemoveDirectoryA error: %ld\n", GetLastError());
|
||||
}
|
||||
|
||||
/* this test concentrates more on the wait behaviour of the handle */
|
||||
static void test_ffcn(void)
|
||||
{
|
||||
DWORD filter;
|
||||
HANDLE handle;
|
||||
LONG r;
|
||||
WCHAR path[MAX_PATH], subdir[MAX_PATH];
|
||||
static const WCHAR szBoo[] = { '\\','b','o','o',0 };
|
||||
static const WCHAR szHoo[] = { '\\','h','o','o',0 };
|
||||
|
||||
r = GetTempPathW( MAX_PATH, path );
|
||||
ok( r != 0, "temp path failed\n");
|
||||
if (!r)
|
||||
return;
|
||||
|
||||
lstrcatW( path, szBoo );
|
||||
lstrcpyW( subdir, path );
|
||||
lstrcatW( subdir, szHoo );
|
||||
|
||||
RemoveDirectoryW( subdir );
|
||||
RemoveDirectoryW( path );
|
||||
|
||||
r = CreateDirectoryW(path, NULL);
|
||||
ok( r == TRUE, "failed to create directory\n");
|
||||
|
||||
filter = FILE_NOTIFY_CHANGE_FILE_NAME;
|
||||
filter |= FILE_NOTIFY_CHANGE_DIR_NAME;
|
||||
|
||||
handle = FindFirstChangeNotificationW( path, 1, filter);
|
||||
ok( handle != INVALID_HANDLE_VALUE, "invalid handle\n");
|
||||
|
||||
r = WaitForSingleObject( handle, 0 );
|
||||
ok( r == STATUS_TIMEOUT, "should time out\n");
|
||||
|
||||
r = CreateDirectoryW( subdir, NULL );
|
||||
ok( r == TRUE, "failed to create subdir\n");
|
||||
|
||||
r = WaitForSingleObject( handle, 0 );
|
||||
ok( r == WAIT_OBJECT_0, "should be ready\n");
|
||||
|
||||
r = WaitForSingleObject( handle, 0 );
|
||||
ok( r == WAIT_OBJECT_0, "should be ready\n");
|
||||
|
||||
r = FindNextChangeNotification(handle);
|
||||
ok( r == TRUE, "find next failed\n");
|
||||
|
||||
r = WaitForSingleObject( handle, 0 );
|
||||
ok( r == STATUS_TIMEOUT, "should time out\n");
|
||||
|
||||
r = RemoveDirectoryW( subdir );
|
||||
ok( r == TRUE, "failed to remove subdir\n");
|
||||
|
||||
r = WaitForSingleObject( handle, 0 );
|
||||
ok( r == WAIT_OBJECT_0, "should be ready\n");
|
||||
|
||||
r = WaitForSingleObject( handle, 0 );
|
||||
ok( r == WAIT_OBJECT_0, "should be ready\n");
|
||||
|
||||
r = FindNextChangeNotification(handle);
|
||||
ok( r == TRUE, "find next failed\n");
|
||||
|
||||
r = FindNextChangeNotification(handle);
|
||||
ok( r == TRUE, "find next failed\n");
|
||||
|
||||
r = FindCloseChangeNotification(handle);
|
||||
ok( r == TRUE, "should succeed\n");
|
||||
|
||||
r = RemoveDirectoryW( path );
|
||||
ok( r == TRUE, "failed to remove dir\n");
|
||||
}
|
||||
|
||||
typedef BOOL (WINAPI *fnReadDirectoryChangesW)(HANDLE,LPVOID,DWORD,BOOL,DWORD,
|
||||
LPDWORD,LPOVERLAPPED,LPOVERLAPPED_COMPLETION_ROUTINE);
|
||||
fnReadDirectoryChangesW pReadDirectoryChangesW;
|
||||
|
||||
static void test_readdirectorychanges(void)
|
||||
{
|
||||
HANDLE hdir;
|
||||
char buffer[0x1000];
|
||||
DWORD fflags, filter = 0, r, dwCount;
|
||||
OVERLAPPED ov;
|
||||
WCHAR path[MAX_PATH], subdir[MAX_PATH], subsubdir[MAX_PATH];
|
||||
static const WCHAR szBoo[] = { '\\','b','o','o',0 };
|
||||
static const WCHAR szHoo[] = { '\\','h','o','o',0 };
|
||||
static const WCHAR szGa[] = { '\\','h','o','o','\\','g','a',0 };
|
||||
PFILE_NOTIFY_INFORMATION pfni;
|
||||
|
||||
if (!pReadDirectoryChangesW)
|
||||
return;
|
||||
|
||||
r = GetTempPathW( MAX_PATH, path );
|
||||
ok( r != 0, "temp path failed\n");
|
||||
if (!r)
|
||||
return;
|
||||
|
||||
lstrcatW( path, szBoo );
|
||||
lstrcpyW( subdir, path );
|
||||
lstrcatW( subdir, szHoo );
|
||||
|
||||
lstrcpyW( subsubdir, path );
|
||||
lstrcatW( subsubdir, szGa );
|
||||
|
||||
RemoveDirectoryW( subsubdir );
|
||||
RemoveDirectoryW( subdir );
|
||||
RemoveDirectoryW( path );
|
||||
|
||||
r = CreateDirectoryW(path, NULL);
|
||||
ok( r == TRUE, "failed to create directory\n");
|
||||
|
||||
SetLastError(0xd0b00b00);
|
||||
r = pReadDirectoryChangesW(NULL,NULL,0,FALSE,0,NULL,NULL,NULL);
|
||||
ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
|
||||
ok(r==FALSE, "should return false\n");
|
||||
|
||||
fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
|
||||
hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE|FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, fflags, NULL);
|
||||
ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n");
|
||||
|
||||
ov.hEvent = CreateEvent( NULL, 1, 0, NULL );
|
||||
|
||||
SetLastError(0xd0b00b00);
|
||||
r = pReadDirectoryChangesW(hdir,NULL,0,FALSE,0,NULL,NULL,NULL);
|
||||
ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
|
||||
ok(r==FALSE, "should return false\n");
|
||||
|
||||
SetLastError(0xd0b00b00);
|
||||
r = pReadDirectoryChangesW(hdir,NULL,0,FALSE,0,NULL,&ov,NULL);
|
||||
ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
|
||||
ok(r==FALSE, "should return false\n");
|
||||
|
||||
filter = FILE_NOTIFY_CHANGE_FILE_NAME;
|
||||
filter |= FILE_NOTIFY_CHANGE_DIR_NAME;
|
||||
filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
|
||||
filter |= FILE_NOTIFY_CHANGE_SIZE;
|
||||
filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
|
||||
filter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
|
||||
filter |= FILE_NOTIFY_CHANGE_CREATION;
|
||||
filter |= FILE_NOTIFY_CHANGE_SECURITY;
|
||||
|
||||
SetLastError(0xd0b00b00);
|
||||
ov.Internal = 0;
|
||||
ov.InternalHigh = 0;
|
||||
memset( buffer, 0, sizeof buffer );
|
||||
|
||||
r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,-1,NULL,&ov,NULL);
|
||||
ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
|
||||
ok(r==FALSE, "should return false\n");
|
||||
|
||||
r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,&ov,NULL);
|
||||
ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
|
||||
ok(r==FALSE, "should return false\n");
|
||||
|
||||
r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,TRUE,filter,NULL,&ov,NULL);
|
||||
ok(r==TRUE, "should return true\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 10 );
|
||||
ok( r == STATUS_TIMEOUT, "should timeout\n" );
|
||||
|
||||
r = CreateDirectoryW( subdir, NULL );
|
||||
ok( r == TRUE, "failed to create directory\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 1000 );
|
||||
ok( r == WAIT_OBJECT_0, "event should be ready\n" );
|
||||
|
||||
ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n");
|
||||
ok( ov.InternalHigh == 0x12, "ov.InternalHigh wrong\n");
|
||||
|
||||
pfni = (PFILE_NOTIFY_INFORMATION) buffer;
|
||||
ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
|
||||
ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" );
|
||||
ok( pfni->FileNameLength == 6, "len wrong\n" );
|
||||
ok( !memcmp(pfni->FileName,&szHoo[1],6), "name wrong\n" );
|
||||
|
||||
ResetEvent(ov.hEvent);
|
||||
SetLastError(0xd0b00b00);
|
||||
r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,NULL,NULL);
|
||||
ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
|
||||
ok(r==FALSE, "should return false\n");
|
||||
|
||||
r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,&ov,NULL);
|
||||
ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
|
||||
ok(r==FALSE, "should return false\n");
|
||||
|
||||
filter = FILE_NOTIFY_CHANGE_SIZE;
|
||||
|
||||
SetEvent(ov.hEvent);
|
||||
ov.Internal = 1;
|
||||
ov.InternalHigh = 1;
|
||||
S(U(ov)).Offset = 0;
|
||||
S(U(ov)).OffsetHigh = 0;
|
||||
memset( buffer, 0, sizeof buffer );
|
||||
r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL);
|
||||
ok(r==TRUE, "should return true\n");
|
||||
|
||||
ok( ov.Internal == STATUS_PENDING, "ov.Internal wrong\n");
|
||||
ok( ov.InternalHigh == 1, "ov.InternalHigh wrong\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 0 );
|
||||
ok( r == STATUS_TIMEOUT, "should timeout\n" );
|
||||
|
||||
r = RemoveDirectoryW( subdir );
|
||||
ok( r == TRUE, "failed to remove directory\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 1000 );
|
||||
ok( r == WAIT_OBJECT_0, "should be ready\n" );
|
||||
|
||||
ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n");
|
||||
ok( ov.InternalHigh == 0x12, "ov.InternalHigh wrong\n");
|
||||
|
||||
r = GetOverlappedResult( hdir, &ov, &dwCount, TRUE );
|
||||
ok( r == TRUE, "getoverlappedresult failed\n");
|
||||
ok( dwCount == 0x12, "count wrong\n");
|
||||
|
||||
pfni = (PFILE_NOTIFY_INFORMATION) buffer;
|
||||
ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
|
||||
ok( pfni->Action == FILE_ACTION_REMOVED, "action wrong\n" );
|
||||
ok( pfni->FileNameLength == 6, "len wrong\n" );
|
||||
ok( !memcmp(pfni->FileName,&szHoo[1],6), "name wrong\n" );
|
||||
|
||||
/* what happens if the buffer is too small? */
|
||||
r = pReadDirectoryChangesW(hdir,buffer,0x10,FALSE,filter,NULL,&ov,NULL);
|
||||
ok(r==TRUE, "should return true\n");
|
||||
|
||||
r = CreateDirectoryW( subdir, NULL );
|
||||
ok( r == TRUE, "failed to create directory\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 1000 );
|
||||
ok( r == WAIT_OBJECT_0, "should be ready\n" );
|
||||
|
||||
ok( ov.Internal == STATUS_NOTIFY_ENUM_DIR, "ov.Internal wrong\n");
|
||||
ok( ov.InternalHigh == 0, "ov.InternalHigh wrong\n");
|
||||
|
||||
/* test the recursive watch */
|
||||
r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL);
|
||||
ok(r==TRUE, "should return true\n");
|
||||
|
||||
r = CreateDirectoryW( subsubdir, NULL );
|
||||
ok( r == TRUE, "failed to create directory\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 1000 );
|
||||
ok( r == WAIT_OBJECT_0, "should be ready\n" );
|
||||
|
||||
ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n");
|
||||
ok( ov.InternalHigh == 0x18, "ov.InternalHigh wrong\n");
|
||||
|
||||
pfni = (PFILE_NOTIFY_INFORMATION) buffer;
|
||||
ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
|
||||
ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" );
|
||||
ok( pfni->FileNameLength == 0x0c, "len wrong\n" );
|
||||
ok( !memcmp(pfni->FileName,&szGa[1],6), "name wrong\n" );
|
||||
|
||||
r = RemoveDirectoryW( subsubdir );
|
||||
ok( r == TRUE, "failed to remove directory\n");
|
||||
|
||||
ov.Internal = 1;
|
||||
ov.InternalHigh = 1;
|
||||
r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL);
|
||||
ok(r==TRUE, "should return true\n");
|
||||
|
||||
r = RemoveDirectoryW( subdir );
|
||||
ok( r == TRUE, "failed to remove directory\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 1000 );
|
||||
ok( r == WAIT_OBJECT_0, "should be ready\n" );
|
||||
|
||||
pfni = (PFILE_NOTIFY_INFORMATION) buffer;
|
||||
ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
|
||||
ok( pfni->Action == FILE_ACTION_REMOVED, "action wrong\n" );
|
||||
ok( pfni->FileNameLength == 0x0c, "len wrong\n" );
|
||||
ok( !memcmp(pfni->FileName,&szGa[1],6), "name wrong\n" );
|
||||
|
||||
ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n");
|
||||
ok( ov.InternalHigh == 0x18, "ov.InternalHigh wrong\n");
|
||||
|
||||
CloseHandle(hdir);
|
||||
|
||||
r = RemoveDirectoryW( path );
|
||||
ok( r == TRUE, "failed to remove directory\n");
|
||||
}
|
||||
|
||||
/* show the behaviour when a null buffer is passed */
|
||||
static void test_readdirectorychanges_null(void)
|
||||
{
|
||||
NTSTATUS r;
|
||||
HANDLE hdir;
|
||||
char buffer[0x1000];
|
||||
DWORD fflags, filter = 0;
|
||||
OVERLAPPED ov;
|
||||
WCHAR path[MAX_PATH], subdir[MAX_PATH];
|
||||
static const WCHAR szBoo[] = { '\\','b','o','o',0 };
|
||||
static const WCHAR szHoo[] = { '\\','h','o','o',0 };
|
||||
PFILE_NOTIFY_INFORMATION pfni;
|
||||
|
||||
if (!pReadDirectoryChangesW)
|
||||
return;
|
||||
|
||||
r = GetTempPathW( MAX_PATH, path );
|
||||
ok( r != 0, "temp path failed\n");
|
||||
if (!r)
|
||||
return;
|
||||
|
||||
lstrcatW( path, szBoo );
|
||||
lstrcpyW( subdir, path );
|
||||
lstrcatW( subdir, szHoo );
|
||||
|
||||
RemoveDirectoryW( subdir );
|
||||
RemoveDirectoryW( path );
|
||||
|
||||
r = CreateDirectoryW(path, NULL);
|
||||
ok( r == TRUE, "failed to create directory\n");
|
||||
|
||||
fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
|
||||
hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE|FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, fflags, NULL);
|
||||
ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n");
|
||||
|
||||
ov.hEvent = CreateEvent( NULL, 1, 0, NULL );
|
||||
|
||||
filter = FILE_NOTIFY_CHANGE_FILE_NAME;
|
||||
filter |= FILE_NOTIFY_CHANGE_DIR_NAME;
|
||||
|
||||
SetLastError(0xd0b00b00);
|
||||
ov.Internal = 0;
|
||||
ov.InternalHigh = 0;
|
||||
memset( buffer, 0, sizeof buffer );
|
||||
|
||||
r = pReadDirectoryChangesW(hdir,NULL,0,FALSE,filter,NULL,&ov,NULL);
|
||||
ok(r==TRUE, "should return true\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 0 );
|
||||
ok( r == STATUS_TIMEOUT, "should timeout\n" );
|
||||
|
||||
r = CreateDirectoryW( subdir, NULL );
|
||||
ok( r == TRUE, "failed to create directory\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 0 );
|
||||
ok( r == WAIT_OBJECT_0, "event should be ready\n" );
|
||||
|
||||
ok( ov.Internal == STATUS_NOTIFY_ENUM_DIR, "ov.Internal wrong\n");
|
||||
ok( ov.InternalHigh == 0, "ov.InternalHigh wrong\n");
|
||||
|
||||
ov.Internal = 0;
|
||||
ov.InternalHigh = 0;
|
||||
S(U(ov)).Offset = 0;
|
||||
S(U(ov)).OffsetHigh = 0;
|
||||
memset( buffer, 0, sizeof buffer );
|
||||
|
||||
r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL);
|
||||
ok(r==TRUE, "should return true\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 0 );
|
||||
ok( r == STATUS_TIMEOUT, "should timeout\n" );
|
||||
|
||||
r = RemoveDirectoryW( subdir );
|
||||
ok( r == TRUE, "failed to remove directory\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 1000 );
|
||||
ok( r == WAIT_OBJECT_0, "should be ready\n" );
|
||||
|
||||
ok( ov.Internal == STATUS_NOTIFY_ENUM_DIR, "ov.Internal wrong\n");
|
||||
ok( ov.InternalHigh == 0, "ov.InternalHigh wrong\n");
|
||||
|
||||
pfni = (PFILE_NOTIFY_INFORMATION) buffer;
|
||||
ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
|
||||
|
||||
CloseHandle(hdir);
|
||||
|
||||
r = RemoveDirectoryW( path );
|
||||
ok( r == TRUE, "failed to remove directory\n");
|
||||
}
|
||||
|
||||
static void test_readdirectorychanges_filedir(void)
|
||||
{
|
||||
NTSTATUS r;
|
||||
HANDLE hdir, hfile;
|
||||
char buffer[0x1000];
|
||||
DWORD fflags, filter = 0;
|
||||
OVERLAPPED ov;
|
||||
WCHAR path[MAX_PATH], subdir[MAX_PATH], file[MAX_PATH];
|
||||
static const WCHAR szBoo[] = { '\\','b','o','o',0 };
|
||||
static const WCHAR szHoo[] = { '\\','h','o','o',0 };
|
||||
static const WCHAR szFoo[] = { '\\','f','o','o',0 };
|
||||
PFILE_NOTIFY_INFORMATION pfni;
|
||||
|
||||
r = GetTempPathW( MAX_PATH, path );
|
||||
ok( r != 0, "temp path failed\n");
|
||||
if (!r)
|
||||
return;
|
||||
|
||||
lstrcatW( path, szBoo );
|
||||
lstrcpyW( subdir, path );
|
||||
lstrcatW( subdir, szHoo );
|
||||
|
||||
lstrcpyW( file, path );
|
||||
lstrcatW( file, szFoo );
|
||||
|
||||
DeleteFileW( file );
|
||||
RemoveDirectoryW( subdir );
|
||||
RemoveDirectoryW( path );
|
||||
|
||||
r = CreateDirectoryW(path, NULL);
|
||||
ok( r == TRUE, "failed to create directory\n");
|
||||
|
||||
fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
|
||||
hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE|FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, fflags, NULL);
|
||||
ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n");
|
||||
|
||||
ov.hEvent = CreateEvent( NULL, 0, 0, NULL );
|
||||
|
||||
filter = FILE_NOTIFY_CHANGE_FILE_NAME;
|
||||
|
||||
r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,TRUE,filter,NULL,&ov,NULL);
|
||||
ok(r==TRUE, "should return true\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 10 );
|
||||
ok( r == WAIT_TIMEOUT, "should timeout\n" );
|
||||
|
||||
r = CreateDirectoryW( subdir, NULL );
|
||||
ok( r == TRUE, "failed to create directory\n");
|
||||
|
||||
hfile = CreateFileW( file, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
|
||||
ok( hfile != INVALID_HANDLE_VALUE, "failed to create file\n");
|
||||
ok( CloseHandle(hfile), "failed toc lose file\n");
|
||||
|
||||
r = WaitForSingleObject( ov.hEvent, 1000 );
|
||||
ok( r == WAIT_OBJECT_0, "event should be ready\n" );
|
||||
|
||||
ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n");
|
||||
ok( ov.InternalHigh == 0x12, "ov.InternalHigh wrong\n");
|
||||
|
||||
pfni = (PFILE_NOTIFY_INFORMATION) buffer;
|
||||
ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
|
||||
ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" );
|
||||
ok( pfni->FileNameLength == 6, "len wrong\n" );
|
||||
ok( !memcmp(pfni->FileName,&szFoo[1],6), "name wrong\n" );
|
||||
|
||||
r = DeleteFileW( file );
|
||||
ok( r == TRUE, "failed to delete file\n");
|
||||
|
||||
r = RemoveDirectoryW( subdir );
|
||||
ok( r == TRUE, "failed to remove directory\n");
|
||||
|
||||
CloseHandle(hdir);
|
||||
|
||||
r = RemoveDirectoryW( path );
|
||||
ok( r == TRUE, "failed to remove directory\n");
|
||||
}
|
||||
|
||||
START_TEST(change)
|
||||
{
|
||||
HMODULE hkernel32 = GetModuleHandle("kernel32");
|
||||
pReadDirectoryChangesW = (fnReadDirectoryChangesW)
|
||||
GetProcAddress(hkernel32, "ReadDirectoryChangesW");
|
||||
|
||||
test_FindFirstChangeNotification();
|
||||
test_ffcn();
|
||||
test_readdirectorychanges();
|
||||
test_readdirectorychanges_null();
|
||||
test_readdirectorychanges_filedir();
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Unit tests for code page to/from unicode translations
|
||||
*
|
||||
* Copyright (c) 2002 Dmitry Timoshkov
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winnls.h"
|
||||
|
||||
static void test_null_source(void)
|
||||
{
|
||||
int len;
|
||||
DWORD GLE;
|
||||
|
||||
SetLastError(0);
|
||||
len = WideCharToMultiByte(CP_ACP, 0, NULL, 0, NULL, 0, NULL, NULL);
|
||||
GLE = GetLastError();
|
||||
ok(!len && GLE == ERROR_INVALID_PARAMETER,
|
||||
"WideCharToMultiByte returned %d with GLE=%ld (expected 0 with ERROR_INVALID_PARAMETER)\n",
|
||||
len, GLE);
|
||||
}
|
||||
|
||||
/* lstrcmpW is not supported on Win9x! */
|
||||
static int mylstrcmpW(const WCHAR* str1, const WCHAR* str2)
|
||||
{
|
||||
while (*str1 && *str1==*str2) {
|
||||
str1++;
|
||||
str2++;
|
||||
}
|
||||
return *str1-*str2;
|
||||
}
|
||||
|
||||
static void test_negative_source_length(void)
|
||||
{
|
||||
int len;
|
||||
char buf[10];
|
||||
WCHAR bufW[10];
|
||||
static const WCHAR foobarW[] = {'f','o','o','b','a','r',0};
|
||||
|
||||
/* Test, whether any negative source length works as strlen() + 1 */
|
||||
SetLastError( 0xdeadbeef );
|
||||
memset(buf,'x',sizeof(buf));
|
||||
len = WideCharToMultiByte(CP_ACP, 0, foobarW, -2002, buf, 10, NULL, NULL);
|
||||
ok(len == 7 && !lstrcmpA(buf, "foobar") && GetLastError() == 0xdeadbeef,
|
||||
"WideCharToMultiByte(-2002): len=%d error=%ld\n",len,GetLastError());
|
||||
|
||||
SetLastError( 0xdeadbeef );
|
||||
memset(bufW,'x',sizeof(bufW));
|
||||
len = MultiByteToWideChar(CP_ACP, 0, "foobar", -2002, bufW, 10);
|
||||
ok(len == 7 && !mylstrcmpW(bufW, foobarW) && GetLastError() == 0xdeadbeef,
|
||||
"MultiByteToWideChar(-2002): len=%d error=%ld\n",len,GetLastError());
|
||||
}
|
||||
|
||||
static void test_overlapped_buffers(void)
|
||||
{
|
||||
static const WCHAR strW[] = {'j','u','s','t',' ','a',' ','t','e','s','t',0};
|
||||
static const char strA[] = "just a test";
|
||||
char buf[256];
|
||||
int ret;
|
||||
|
||||
lstrcpyW((WCHAR *)(buf + 1), strW);
|
||||
ret = WideCharToMultiByte(CP_ACP, 0, (WCHAR *)(buf + 1), -1, buf, sizeof(buf), NULL, NULL);
|
||||
ok(ret == sizeof(strA), "unexpected ret %d != %d\n", ret, sizeof(strA));
|
||||
ok(!memcmp(buf, strA, sizeof(strA)), "conversion failed: %s\n", buf);
|
||||
}
|
||||
|
||||
START_TEST(codepage)
|
||||
{
|
||||
test_null_source();
|
||||
test_negative_source_length();
|
||||
test_overlapped_buffers();
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,593 +0,0 @@
|
|||
/*
|
||||
* Unit tests for console API
|
||||
*
|
||||
* Copyright (c) 2003,2004 Eric Pouech
|
||||
*
|
||||
* 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 "wine/test.h"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* DEFAULT_ATTRIB is used for all initial filling of the console.
|
||||
* all modifications are made with TEST_ATTRIB so that we could check
|
||||
* what has to be modified or not
|
||||
*/
|
||||
#define TEST_ATTRIB (BACKGROUND_BLUE | FOREGROUND_GREEN)
|
||||
#define DEFAULT_ATTRIB (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)
|
||||
/* when filling the screen with non-blank chars, this macro defines
|
||||
* what character should be at position 'c'
|
||||
*/
|
||||
#define CONTENT(c) ('A' + (((c).Y * 17 + (c).X) % 23))
|
||||
|
||||
#define okCURSOR(hCon, c) do { \
|
||||
CONSOLE_SCREEN_BUFFER_INFO __sbi; \
|
||||
BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
|
||||
__sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
|
||||
ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
|
||||
(c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
|
||||
} while (0)
|
||||
|
||||
#define okCHAR(hCon, c, ch, attr) do { \
|
||||
char __ch; WORD __attr; DWORD __len; BOOL expect; \
|
||||
expect = ReadConsoleOutputCharacter((hCon), &__ch, 1, (c), &__len) == 1 && __len == 1 && __ch == (ch); \
|
||||
ok(expect, "At (%d,%d): expecting char '%c'/%02x got '%c'/%02x\n", (c).X, (c).Y, (ch), (ch), __ch, __ch); \
|
||||
expect = ReadConsoleOutputAttribute((hCon), &__attr, 1, (c), &__len) == 1 && __len == 1 && __attr == (attr); \
|
||||
ok(expect, "At (%d,%d): expecting attr %04x got %04x\n", (c).X, (c).Y, (attr), __attr); \
|
||||
} while (0)
|
||||
|
||||
/* FIXME: this could be optimized on a speed point of view */
|
||||
static void resetContent(HANDLE hCon, COORD sbSize, BOOL content)
|
||||
{
|
||||
COORD c;
|
||||
WORD attr = DEFAULT_ATTRIB;
|
||||
char ch;
|
||||
DWORD len;
|
||||
|
||||
for (c.X = 0; c.X < sbSize.X; c.X++)
|
||||
{
|
||||
for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
|
||||
{
|
||||
ch = (content) ? CONTENT(c) : ' ';
|
||||
WriteConsoleOutputAttribute(hCon, &attr, 1, c, &len);
|
||||
WriteConsoleOutputCharacterA(hCon, &ch, 1, c, &len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testCursor(HANDLE hCon, COORD sbSize)
|
||||
{
|
||||
COORD c;
|
||||
|
||||
c.X = c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n");
|
||||
ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n",
|
||||
ERROR_INVALID_HANDLE, GetLastError());
|
||||
|
||||
c.X = c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
|
||||
okCURSOR(hCon, c);
|
||||
|
||||
c.X = sbSize.X - 1;
|
||||
c.Y = sbSize.Y - 1;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in lower-right\n");
|
||||
okCURSOR(hCon, c);
|
||||
|
||||
c.X = sbSize.X;
|
||||
c.Y = sbSize.Y - 1;
|
||||
ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
|
||||
ERROR_INVALID_PARAMETER, GetLastError());
|
||||
|
||||
c.X = sbSize.X - 1;
|
||||
c.Y = sbSize.Y;
|
||||
ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
|
||||
ERROR_INVALID_PARAMETER, GetLastError());
|
||||
|
||||
c.X = -1;
|
||||
c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
|
||||
ERROR_INVALID_PARAMETER, GetLastError());
|
||||
|
||||
c.X = 0;
|
||||
c.Y = -1;
|
||||
ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
|
||||
ERROR_INVALID_PARAMETER, GetLastError());
|
||||
}
|
||||
|
||||
static void testWriteSimple(HANDLE hCon, COORD sbSize)
|
||||
{
|
||||
COORD c;
|
||||
DWORD len;
|
||||
const char* mytest = "abcdefg";
|
||||
const int mylen = strlen(mytest);
|
||||
|
||||
/* single line write */
|
||||
c.X = c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
|
||||
|
||||
ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
|
||||
c.Y = 0;
|
||||
for (c.X = 0; c.X < mylen; c.X++)
|
||||
{
|
||||
okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
|
||||
}
|
||||
|
||||
okCURSOR(hCon, c);
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
}
|
||||
|
||||
static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize)
|
||||
{
|
||||
COORD c;
|
||||
DWORD len, mode;
|
||||
const char* mytest = "123";
|
||||
const int mylen = strlen(mytest);
|
||||
int ret;
|
||||
int p;
|
||||
|
||||
ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode & ~(ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT)),
|
||||
"clearing wrap at EOL & processed output\n");
|
||||
|
||||
/* write line, wrapping disabled, buffer exceeds sb width */
|
||||
c.X = sbSize.X - 3; c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
|
||||
|
||||
ret = WriteConsole(hCon, mytest, mylen, &len, NULL);
|
||||
ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %ld\n", ret, len);
|
||||
c.Y = 0;
|
||||
for (p = mylen - 3; p < mylen; p++)
|
||||
{
|
||||
c.X = sbSize.X - 3 + p % 3;
|
||||
okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
|
||||
}
|
||||
|
||||
c.X = 0; c.Y = 1;
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
|
||||
p = sbSize.X - 3 + mylen % 3;
|
||||
c.X = p; c.Y = 0;
|
||||
|
||||
/* write line, wrapping disabled, strings end on end of line */
|
||||
c.X = sbSize.X - mylen; c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
|
||||
|
||||
ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
|
||||
}
|
||||
|
||||
static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize)
|
||||
{
|
||||
COORD c;
|
||||
DWORD len, mode;
|
||||
const char* mytest = "abcd\nf\tg";
|
||||
const int mylen = strlen(mytest);
|
||||
const int mylen2 = strchr(mytest, '\n') - mytest;
|
||||
int p;
|
||||
|
||||
ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) & ~ENABLE_WRAP_AT_EOL_OUTPUT),
|
||||
"clearing wrap at EOL & setting processed output\n");
|
||||
|
||||
/* write line, wrapping disabled, buffer exceeds sb width */
|
||||
c.X = sbSize.X - 5; c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-5\n");
|
||||
|
||||
ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
|
||||
c.Y = 0;
|
||||
for (c.X = sbSize.X - 5; c.X < sbSize.X - 1; c.X++)
|
||||
{
|
||||
okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB);
|
||||
}
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
|
||||
c.X = 0; c.Y++;
|
||||
okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
|
||||
for (c.X = 1; c.X < 8; c.X++)
|
||||
okCHAR(hCon, c, ' ', TEST_ATTRIB);
|
||||
okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
|
||||
c.X++;
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
|
||||
okCURSOR(hCon, c);
|
||||
|
||||
/* write line, wrapping disabled, strings end on end of line */
|
||||
c.X = sbSize.X - 4; c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
|
||||
|
||||
ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
|
||||
c.Y = 0;
|
||||
for (c.X = sbSize.X - 4; c.X < sbSize.X; c.X++)
|
||||
{
|
||||
okCHAR(hCon, c, mytest[c.X - sbSize.X + 4], TEST_ATTRIB);
|
||||
}
|
||||
c.X = 0; c.Y++;
|
||||
okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
|
||||
for (c.X = 1; c.X < 8; c.X++)
|
||||
okCHAR(hCon, c, ' ', TEST_ATTRIB);
|
||||
okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
|
||||
c.X++;
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
|
||||
okCURSOR(hCon, c);
|
||||
|
||||
/* write line, wrapping disabled, strings end after end of line */
|
||||
c.X = sbSize.X - 3; c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
|
||||
|
||||
ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
|
||||
c.Y = 0;
|
||||
for (p = mylen2 - 3; p < mylen2; p++)
|
||||
{
|
||||
c.X = sbSize.X - 3 + p % 3;
|
||||
okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
|
||||
}
|
||||
c.X = 0; c.Y = 1;
|
||||
okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
|
||||
for (c.X = 1; c.X < 8; c.X++)
|
||||
okCHAR(hCon, c, ' ', TEST_ATTRIB);
|
||||
okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
|
||||
c.X++;
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
|
||||
okCURSOR(hCon, c);
|
||||
}
|
||||
|
||||
static void testWriteWrappedNotProcessed(HANDLE hCon, COORD sbSize)
|
||||
{
|
||||
COORD c;
|
||||
DWORD len, mode;
|
||||
const char* mytest = "abcd\nf\tg";
|
||||
const int mylen = strlen(mytest);
|
||||
int p;
|
||||
|
||||
ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon,(mode | ENABLE_WRAP_AT_EOL_OUTPUT) & ~(ENABLE_PROCESSED_OUTPUT)),
|
||||
"setting wrap at EOL & clearing processed output\n");
|
||||
|
||||
/* write line, wrapping enabled, buffer doesn't exceed sb width */
|
||||
c.X = sbSize.X - 9; c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
|
||||
|
||||
ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
|
||||
c.Y = 0;
|
||||
for (p = 0; p < mylen; p++)
|
||||
{
|
||||
c.X = sbSize.X - 9 + p;
|
||||
okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
|
||||
}
|
||||
c.X = sbSize.X - 9 + mylen;
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
c.X = 0; c.Y = 1;
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
|
||||
/* write line, wrapping enabled, buffer does exceed sb width */
|
||||
c.X = sbSize.X - 3; c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
|
||||
|
||||
c.Y = 1;
|
||||
c.X = mylen - 3;
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
}
|
||||
|
||||
static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize)
|
||||
{
|
||||
COORD c;
|
||||
DWORD len, mode;
|
||||
const char* mytest = "abcd\nf\tg";
|
||||
const int mylen = strlen(mytest);
|
||||
int p;
|
||||
|
||||
ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)),
|
||||
"setting wrap at EOL & processed output\n");
|
||||
|
||||
/* write line, wrapping enabled, buffer doesn't exceed sb width */
|
||||
c.X = sbSize.X - 9; c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
|
||||
|
||||
ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
|
||||
for (p = 0; p < 4; p++)
|
||||
{
|
||||
c.X = sbSize.X - 9 + p;
|
||||
okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
|
||||
}
|
||||
c.X = sbSize.X - 9 + p;
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
c.X = 0; c.Y++;
|
||||
okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
|
||||
for (c.X = 1; c.X < 8; c.X++)
|
||||
okCHAR(hCon, c, ' ', TEST_ATTRIB);
|
||||
okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
|
||||
c.X++;
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
okCURSOR(hCon, c);
|
||||
|
||||
/* write line, wrapping enabled, buffer does exceed sb width */
|
||||
c.X = sbSize.X - 3; c.Y = 2;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
|
||||
|
||||
ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
|
||||
for (p = 0; p < 3; p++)
|
||||
{
|
||||
c.X = sbSize.X - 3 + p;
|
||||
okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
|
||||
}
|
||||
c.X = 0; c.Y++;
|
||||
okCHAR(hCon, c, mytest[3], TEST_ATTRIB);
|
||||
c.X++;
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
|
||||
c.X = 0; c.Y++;
|
||||
okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
|
||||
for (c.X = 1; c.X < 8; c.X++)
|
||||
okCHAR(hCon, c, ' ', TEST_ATTRIB);
|
||||
okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
|
||||
c.X++;
|
||||
okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
|
||||
okCURSOR(hCon, c);
|
||||
}
|
||||
|
||||
static void testWrite(HANDLE hCon, COORD sbSize)
|
||||
{
|
||||
/* FIXME: should in fact insure that the sb is at least 10 character wide */
|
||||
ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n");
|
||||
resetContent(hCon, sbSize, FALSE);
|
||||
testWriteSimple(hCon, sbSize);
|
||||
resetContent(hCon, sbSize, FALSE);
|
||||
testWriteNotWrappedNotProcessed(hCon, sbSize);
|
||||
resetContent(hCon, sbSize, FALSE);
|
||||
testWriteNotWrappedProcessed(hCon, sbSize);
|
||||
resetContent(hCon, sbSize, FALSE);
|
||||
testWriteWrappedNotProcessed(hCon, sbSize);
|
||||
resetContent(hCon, sbSize, FALSE);
|
||||
testWriteWrappedProcessed(hCon, sbSize);
|
||||
}
|
||||
|
||||
static void testScroll(HANDLE hCon, COORD sbSize)
|
||||
{
|
||||
SMALL_RECT scroll, clip;
|
||||
COORD dst, c, tc;
|
||||
CHAR_INFO ci;
|
||||
|
||||
#define W 11
|
||||
#define H 7
|
||||
|
||||
#define IN_SRECT(r,c) ((r).Left <= (c).X && (c).X <= (r).Right && (r).Top <= (c).Y && (c).Y <= (r).Bottom)
|
||||
#define IN_SRECT2(r,d,c) ((d).X <= (c).X && (c).X <= (d).X + (r).Right - (r).Left && (d).Y <= (c).Y && (c).Y <= (d).Y + (r).Bottom - (r).Top)
|
||||
|
||||
/* no clipping, src & dst rect don't overlap */
|
||||
resetContent(hCon, sbSize, TRUE);
|
||||
|
||||
scroll.Left = 0;
|
||||
scroll.Right = W - 1;
|
||||
scroll.Top = 0;
|
||||
scroll.Bottom = H - 1;
|
||||
dst.X = W + 3;
|
||||
dst.Y = H + 3;
|
||||
ci.Char.UnicodeChar = '#';
|
||||
ci.Attributes = TEST_ATTRIB;
|
||||
|
||||
clip.Left = 0;
|
||||
clip.Right = sbSize.X - 1;
|
||||
clip.Top = 0;
|
||||
clip.Bottom = sbSize.Y - 1;
|
||||
|
||||
ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
|
||||
|
||||
for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
|
||||
{
|
||||
for (c.X = 0; c.X < sbSize.X; c.X++)
|
||||
{
|
||||
if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
|
||||
{
|
||||
tc.X = c.X - dst.X;
|
||||
tc.Y = c.Y - dst.Y;
|
||||
okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
|
||||
}
|
||||
else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
|
||||
okCHAR(hCon, c, '#', TEST_ATTRIB);
|
||||
else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
|
||||
}
|
||||
}
|
||||
|
||||
/* no clipping, src & dst rect do overlap */
|
||||
resetContent(hCon, sbSize, TRUE);
|
||||
|
||||
scroll.Left = 0;
|
||||
scroll.Right = W - 1;
|
||||
scroll.Top = 0;
|
||||
scroll.Bottom = H - 1;
|
||||
dst.X = W /2;
|
||||
dst.Y = H / 2;
|
||||
ci.Char.UnicodeChar = '#';
|
||||
ci.Attributes = TEST_ATTRIB;
|
||||
|
||||
clip.Left = 0;
|
||||
clip.Right = sbSize.X - 1;
|
||||
clip.Top = 0;
|
||||
clip.Bottom = sbSize.Y - 1;
|
||||
|
||||
ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
|
||||
|
||||
for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
|
||||
{
|
||||
for (c.X = 0; c.X < sbSize.X; c.X++)
|
||||
{
|
||||
if (dst.X <= c.X && c.X < dst.X + W && dst.Y <= c.Y && c.Y < dst.Y + H)
|
||||
{
|
||||
tc.X = c.X - dst.X;
|
||||
tc.Y = c.Y - dst.Y;
|
||||
okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
|
||||
}
|
||||
else if (c.X < W && c.Y < H) okCHAR(hCon, c, '#', TEST_ATTRIB);
|
||||
else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
|
||||
}
|
||||
}
|
||||
|
||||
/* clipping, src & dst rect don't overlap */
|
||||
resetContent(hCon, sbSize, TRUE);
|
||||
|
||||
scroll.Left = 0;
|
||||
scroll.Right = W - 1;
|
||||
scroll.Top = 0;
|
||||
scroll.Bottom = H - 1;
|
||||
dst.X = W + 3;
|
||||
dst.Y = H + 3;
|
||||
ci.Char.UnicodeChar = '#';
|
||||
ci.Attributes = TEST_ATTRIB;
|
||||
|
||||
clip.Left = W / 2;
|
||||
clip.Right = min(W + W / 2, sbSize.X - 1);
|
||||
clip.Top = H / 2;
|
||||
clip.Bottom = min(H + H / 2, sbSize.Y - 1);
|
||||
|
||||
ok(ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n");
|
||||
|
||||
for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
|
||||
{
|
||||
for (c.X = 0; c.X < sbSize.X; c.X++)
|
||||
{
|
||||
if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
|
||||
{
|
||||
tc.X = c.X - dst.X;
|
||||
tc.Y = c.Y - dst.Y;
|
||||
okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
|
||||
}
|
||||
else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
|
||||
okCHAR(hCon, c, '#', TEST_ATTRIB);
|
||||
else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
|
||||
}
|
||||
}
|
||||
|
||||
/* clipping, src & dst rect do overlap */
|
||||
resetContent(hCon, sbSize, TRUE);
|
||||
|
||||
scroll.Left = 0;
|
||||
scroll.Right = W - 1;
|
||||
scroll.Top = 0;
|
||||
scroll.Bottom = H - 1;
|
||||
dst.X = W / 2 - 3;
|
||||
dst.Y = H / 2 - 3;
|
||||
ci.Char.UnicodeChar = '#';
|
||||
ci.Attributes = TEST_ATTRIB;
|
||||
|
||||
clip.Left = W / 2;
|
||||
clip.Right = min(W + W / 2, sbSize.X - 1);
|
||||
clip.Top = H / 2;
|
||||
clip.Bottom = min(H + H / 2, sbSize.Y - 1);
|
||||
|
||||
ok(ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n");
|
||||
|
||||
for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
|
||||
{
|
||||
for (c.X = 0; c.X < sbSize.X; c.X++)
|
||||
{
|
||||
if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
|
||||
{
|
||||
tc.X = c.X - dst.X;
|
||||
tc.Y = c.Y - dst.Y;
|
||||
okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
|
||||
}
|
||||
else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
|
||||
okCHAR(hCon, c, '#', TEST_ATTRIB);
|
||||
else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int mch_count;
|
||||
/* we need the event as Wine console event generation isn't synchronous
|
||||
* (ie GenerateConsoleCtrlEvent returns before all ctrl-handlers in all
|
||||
* processes have been called).
|
||||
*/
|
||||
static HANDLE mch_event;
|
||||
static BOOL WINAPI mch(DWORD event)
|
||||
{
|
||||
mch_count++;
|
||||
SetEvent(mch_event);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void testCtrlHandler(void)
|
||||
{
|
||||
ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %lu\n", GetLastError());
|
||||
ok(SetConsoleCtrlHandler(mch, TRUE), "Couldn't set handler\n");
|
||||
/* wine requires the event for the test, as we cannot insure, so far, that event
|
||||
* are processed synchronously in GenerateConsoleCtrlEvent()
|
||||
*/
|
||||
mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
mch_count = 0;
|
||||
ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
|
||||
#if 0 /* FIXME: it isn't synchronous on wine but it can still happen before we test */
|
||||
todo_wine ok(mch_count == 1, "Event isn't synchronous\n");
|
||||
#endif
|
||||
ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n");
|
||||
CloseHandle(mch_event);
|
||||
|
||||
/* Turning off ctrl-c handling doesn't work on win9x such way ... */
|
||||
ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
|
||||
mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
mch_count = 0;
|
||||
if(!(GetVersion() & 0x80000000))
|
||||
/* ... and next line leads to an unhandled exception on 9x. Avoid it on 9x. */
|
||||
ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
|
||||
ok(WaitForSingleObject(mch_event, 3000) == WAIT_TIMEOUT && mch_count == 0, "Event shouldn't have been sent\n");
|
||||
CloseHandle(mch_event);
|
||||
ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n");
|
||||
ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %lu\n", GetLastError());
|
||||
}
|
||||
|
||||
START_TEST(console)
|
||||
{
|
||||
HANDLE hConIn, hConOut;
|
||||
BOOL ret;
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
|
||||
/* be sure we have a clean console (and that's our own)
|
||||
* FIXME: this will make the test fail (currently) if we don't run
|
||||
* under X11
|
||||
* Another solution would be to rerun the test under wineconsole with
|
||||
* the curses backend
|
||||
*/
|
||||
|
||||
/* first, we detach and open a fresh console to play with */
|
||||
FreeConsole();
|
||||
ok(AllocConsole(), "Couldn't alloc console\n");
|
||||
hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
|
||||
/* now verify everything's ok */
|
||||
ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
|
||||
ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
|
||||
|
||||
ok(ret = GetConsoleScreenBufferInfo(hConOut, &sbi), "Getting sb info\n");
|
||||
if (!ret) return;
|
||||
|
||||
/* Non interactive tests */
|
||||
testCursor(hConOut, sbi.dwSize);
|
||||
/* will test wrapped (on/off) & processed (on/off) strings output */
|
||||
testWrite(hConOut, sbi.dwSize);
|
||||
/* will test line scrolling at the bottom of the screen */
|
||||
/* testBottomScroll(); */
|
||||
/* will test all the scrolling operations */
|
||||
testScroll(hConOut, sbi.dwSize);
|
||||
/* will test sb creation / modification... */
|
||||
/* testScreenBuffer() */
|
||||
testCtrlHandler();
|
||||
/* still to be done: access rights & access on objects */
|
||||
}
|
|
@ -1,482 +0,0 @@
|
|||
/*
|
||||
* Unit test suite for directory functions.
|
||||
*
|
||||
* Copyright 2002 Dmitry Timoshkov
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
|
||||
/* If you change something in these tests, please do the same
|
||||
* for GetSystemDirectory tests.
|
||||
*/
|
||||
static void test_GetWindowsDirectoryA(void)
|
||||
{
|
||||
UINT len, len_with_null;
|
||||
char buf[MAX_PATH];
|
||||
|
||||
len_with_null = GetWindowsDirectoryA(NULL, 0);
|
||||
ok(len_with_null <= MAX_PATH, "should fit into MAX_PATH\n");
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
len_with_null = GetWindowsDirectoryA(buf, 1);
|
||||
ok(lstrcmpA(buf, "foo") == 0, "should not touch the buffer\n");
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
len = GetWindowsDirectoryA(buf, len_with_null - 1);
|
||||
ok(lstrcmpA(buf, "foo") == 0, "should not touch the buffer\n");
|
||||
ok(len == len_with_null, "GetWindowsDirectoryW returned %d, expected %d\n",
|
||||
len, len_with_null);
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
len = GetWindowsDirectoryA(buf, len_with_null);
|
||||
ok(lstrcmpA(buf, "foo") != 0, "should touch the buffer\n");
|
||||
ok(len == strlen(buf), "returned length should be equal to the length of string\n");
|
||||
ok(len == len_with_null-1, "GetWindowsDirectoryA returned %d, expected %d\n",
|
||||
len, len_with_null-1);
|
||||
}
|
||||
|
||||
static void test_GetWindowsDirectoryW(void)
|
||||
{
|
||||
UINT len, len_with_null;
|
||||
WCHAR buf[MAX_PATH];
|
||||
static const WCHAR fooW[] = {'f','o','o',0};
|
||||
|
||||
len_with_null = GetWindowsDirectoryW(NULL, 0);
|
||||
if (len_with_null==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
|
||||
return;
|
||||
ok(len_with_null <= MAX_PATH, "should fit into MAX_PATH\n");
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
len = GetWindowsDirectoryW(buf, 1);
|
||||
ok(lstrcmpW(buf, fooW) == 0, "should not touch the buffer\n");
|
||||
ok(len == len_with_null, "GetWindowsDirectoryW returned %d, expected %d\n",
|
||||
len, len_with_null);
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
len = GetWindowsDirectoryW(buf, len_with_null - 1);
|
||||
ok(lstrcmpW(buf, fooW) == 0, "should not touch the buffer\n");
|
||||
ok(len == len_with_null, "GetWindowsDirectoryW returned %d, expected %d\n",
|
||||
len, len_with_null);
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
len = GetWindowsDirectoryW(buf, len_with_null);
|
||||
ok(lstrcmpW(buf, fooW) != 0, "should touch the buffer\n");
|
||||
ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
|
||||
ok(len == len_with_null-1, "GetWindowsDirectoryW returned %d, expected %d\n",
|
||||
len, len_with_null-1);
|
||||
}
|
||||
|
||||
|
||||
/* If you change something in these tests, please do the same
|
||||
* for GetWindowsDirectory tests.
|
||||
*/
|
||||
static void test_GetSystemDirectoryA(void)
|
||||
{
|
||||
UINT len, len_with_null;
|
||||
char buf[MAX_PATH];
|
||||
|
||||
len_with_null = GetSystemDirectoryA(NULL, 0);
|
||||
ok(len_with_null <= MAX_PATH, "should fit into MAX_PATH\n");
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
len = GetSystemDirectoryA(buf, 1);
|
||||
ok(lstrcmpA(buf, "foo") == 0, "should not touch the buffer\n");
|
||||
ok(len == len_with_null, "GetSystemDirectoryA returned %d, expected %d\n",
|
||||
len, len_with_null);
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
len = GetSystemDirectoryA(buf, len_with_null - 1);
|
||||
ok(lstrcmpA(buf, "foo") == 0, "should not touch the buffer\n");
|
||||
ok(len == len_with_null, "GetSystemDirectoryA returned %d, expected %d\n",
|
||||
len, len_with_null);
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
len = GetSystemDirectoryA(buf, len_with_null);
|
||||
ok(lstrcmpA(buf, "foo") != 0, "should touch the buffer\n");
|
||||
ok(len == strlen(buf), "returned length should be equal to the length of string\n");
|
||||
ok(len == len_with_null-1, "GetSystemDirectoryW returned %d, expected %d\n",
|
||||
len, len_with_null-1);
|
||||
}
|
||||
|
||||
static void test_GetSystemDirectoryW(void)
|
||||
{
|
||||
UINT len, len_with_null;
|
||||
WCHAR buf[MAX_PATH];
|
||||
static const WCHAR fooW[] = {'f','o','o',0};
|
||||
|
||||
len_with_null = GetSystemDirectoryW(NULL, 0);
|
||||
if (len_with_null==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
|
||||
return;
|
||||
ok(len_with_null <= MAX_PATH, "should fit into MAX_PATH\n");
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
len = GetSystemDirectoryW(buf, 1);
|
||||
ok(lstrcmpW(buf, fooW) == 0, "should not touch the buffer\n");
|
||||
ok(len == len_with_null, "GetSystemDirectoryW returned %d, expected %d\n",
|
||||
len, len_with_null);
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
len = GetSystemDirectoryW(buf, len_with_null - 1);
|
||||
ok(lstrcmpW(buf, fooW) == 0, "should not touch the buffer\n");
|
||||
ok(len == len_with_null, "GetSystemDirectoryW returned %d, expected %d\n",
|
||||
len, len_with_null);
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
len = GetSystemDirectoryW(buf, len_with_null);
|
||||
ok(lstrcmpW(buf, fooW) != 0, "should touch the buffer\n");
|
||||
ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
|
||||
ok(len == len_with_null-1, "GetSystemDirectoryW returned %d, expected %d\n",
|
||||
len, len_with_null-1);
|
||||
}
|
||||
|
||||
static void test_CreateDirectoryA(void)
|
||||
{
|
||||
char tmpdir[MAX_PATH];
|
||||
BOOL ret;
|
||||
|
||||
ret = CreateDirectoryA(NULL, NULL);
|
||||
ok(ret == FALSE && (GetLastError() == ERROR_PATH_NOT_FOUND ||
|
||||
GetLastError() == ERROR_INVALID_PARAMETER),
|
||||
"CreateDirectoryA(NULL): ret=%d err=%ld\n", ret, GetLastError());
|
||||
|
||||
ret = CreateDirectoryA("", NULL);
|
||||
ok(ret == FALSE && (GetLastError() == ERROR_BAD_PATHNAME ||
|
||||
GetLastError() == ERROR_PATH_NOT_FOUND),
|
||||
"CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError());
|
||||
|
||||
ret = GetSystemDirectoryA(tmpdir, MAX_PATH);
|
||||
ok(ret < MAX_PATH, "System directory should fit into MAX_PATH\n");
|
||||
|
||||
ret = SetCurrentDirectoryA(tmpdir);
|
||||
ok(ret == TRUE, "could not chdir to the System directory\n");
|
||||
|
||||
ret = CreateDirectoryA(".", NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS,
|
||||
"CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError());
|
||||
|
||||
|
||||
ret = CreateDirectoryA("..", NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS,
|
||||
"CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError());
|
||||
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
tmpdir[3] = 0; /* truncate the path */
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == FALSE && (GetLastError() == ERROR_ALREADY_EXISTS ||
|
||||
GetLastError() == ERROR_ACCESS_DENIED),
|
||||
"CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError());
|
||||
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
lstrcatA(tmpdir, "Please Remove Me");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == TRUE, "CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS,
|
||||
"CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError());
|
||||
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == TRUE,
|
||||
"RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
|
||||
|
||||
lstrcatA(tmpdir, "?");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == FALSE && (GetLastError() == ERROR_INVALID_NAME ||
|
||||
GetLastError() == ERROR_PATH_NOT_FOUND),
|
||||
"CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError());
|
||||
RemoveDirectoryA(tmpdir);
|
||||
|
||||
tmpdir[lstrlenA(tmpdir) - 1] = '*';
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == FALSE && (GetLastError() == ERROR_INVALID_NAME ||
|
||||
GetLastError() == ERROR_PATH_NOT_FOUND),
|
||||
"CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError());
|
||||
RemoveDirectoryA(tmpdir);
|
||||
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
lstrcatA(tmpdir, "Please Remove Me/Please Remove Me");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND,
|
||||
"CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError());
|
||||
RemoveDirectoryA(tmpdir);
|
||||
|
||||
/* Test behavior with a trailing dot.
|
||||
* The directory should be created without the dot.
|
||||
*/
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
lstrcatA(tmpdir, "Please Remove Me.");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == TRUE,
|
||||
"CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
|
||||
lstrcatA(tmpdir, "/Please Remove Me");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == TRUE,
|
||||
"CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == TRUE,
|
||||
"RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
lstrcatA(tmpdir, "Please Remove Me");
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == TRUE,
|
||||
"RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
|
||||
/* Test behavior with two trailing dots.
|
||||
* The directory should be created without the trailing dots.
|
||||
*/
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
lstrcatA(tmpdir, "Please Remove Me..");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == TRUE,
|
||||
"CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
|
||||
lstrcatA(tmpdir, "/Please Remove Me");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == TRUE || /* On Win98 */
|
||||
(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND), /* On NT! */
|
||||
"CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError());
|
||||
if (ret == TRUE)
|
||||
{
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == TRUE,
|
||||
"RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
}
|
||||
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
lstrcatA(tmpdir, "Please Remove Me");
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == TRUE,
|
||||
"RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
|
||||
/* Test behavior with a trailing space.
|
||||
* The directory should be created without the trailing space.
|
||||
*/
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
lstrcatA(tmpdir, "Please Remove Me ");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == TRUE,
|
||||
"CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
|
||||
lstrcatA(tmpdir, "/Please Remove Me");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == TRUE || /* On Win98 */
|
||||
(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND), /* On NT! */
|
||||
"CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError());
|
||||
if (ret == TRUE)
|
||||
{
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == TRUE,
|
||||
"RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
}
|
||||
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
lstrcatA(tmpdir, "Please Remove Me");
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == TRUE,
|
||||
"RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
|
||||
/* Test behavior with a trailing space.
|
||||
* The directory should be created without the trailing spaces.
|
||||
*/
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
lstrcatA(tmpdir, "Please Remove Me ");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == TRUE,
|
||||
"CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
|
||||
lstrcatA(tmpdir, "/Please Remove Me");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == TRUE || /* On Win98 */
|
||||
(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND), /* On NT! */
|
||||
"CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError());
|
||||
if (ret == TRUE)
|
||||
{
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == TRUE,
|
||||
"RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
}
|
||||
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
lstrcatA(tmpdir, "Please Remove Me");
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == TRUE,
|
||||
"RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError());
|
||||
}
|
||||
|
||||
static void test_CreateDirectoryW(void)
|
||||
{
|
||||
WCHAR tmpdir[MAX_PATH];
|
||||
BOOL ret;
|
||||
static const WCHAR empty_strW[] = { 0 };
|
||||
static const WCHAR tmp_dir_name[] = {'P','l','e','a','s','e',' ','R','e','m','o','v','e',' ','M','e',0};
|
||||
static const WCHAR dotW[] = {'.',0};
|
||||
static const WCHAR slashW[] = {'/',0};
|
||||
static const WCHAR dotdotW[] = {'.','.',0};
|
||||
static const WCHAR questionW[] = {'?',0};
|
||||
|
||||
ret = CreateDirectoryW(NULL, NULL);
|
||||
if (!ret && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
|
||||
return;
|
||||
ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND, "should not create NULL path\n");
|
||||
|
||||
ret = CreateDirectoryW(empty_strW, NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND, "should not create empty path\n");
|
||||
|
||||
ret = GetSystemDirectoryW(tmpdir, MAX_PATH);
|
||||
ok(ret < MAX_PATH, "System directory should fit into MAX_PATH\n");
|
||||
|
||||
ret = SetCurrentDirectoryW(tmpdir);
|
||||
ok(ret == TRUE, "could not chdir to the System directory\n");
|
||||
|
||||
ret = CreateDirectoryW(dotW, NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, "should not create existing path\n");
|
||||
|
||||
ret = CreateDirectoryW(dotdotW, NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, "should not create existing path\n");
|
||||
|
||||
GetTempPathW(MAX_PATH, tmpdir);
|
||||
tmpdir[3] = 0; /* truncate the path */
|
||||
ret = CreateDirectoryW(tmpdir, NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_ACCESS_DENIED, "should deny access to the drive root\n");
|
||||
|
||||
GetTempPathW(MAX_PATH, tmpdir);
|
||||
lstrcatW(tmpdir, tmp_dir_name);
|
||||
ret = CreateDirectoryW(tmpdir, NULL);
|
||||
ok(ret == TRUE, "CreateDirectoryW should always succeed\n");
|
||||
|
||||
ret = CreateDirectoryW(tmpdir, NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, "should not create existing path\n");
|
||||
|
||||
ret = RemoveDirectoryW(tmpdir);
|
||||
ok(ret == TRUE, "RemoveDirectoryW should always succeed\n");
|
||||
|
||||
lstrcatW(tmpdir, questionW);
|
||||
ret = CreateDirectoryW(tmpdir, NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME,
|
||||
"CreateDirectoryW with ? wildcard name should fail with error 183, ret=%s error=%ld\n",
|
||||
ret ? " True" : "False", GetLastError());
|
||||
ret = RemoveDirectoryW(tmpdir);
|
||||
|
||||
tmpdir[lstrlenW(tmpdir) - 1] = '*';
|
||||
ret = CreateDirectoryW(tmpdir, NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME,
|
||||
"CreateDirectoryW with * wildcard name should fail with error 183, ret=%s error=%ld\n",
|
||||
ret ? " True" : "False", GetLastError());
|
||||
ret = RemoveDirectoryW(tmpdir);
|
||||
|
||||
GetTempPathW(MAX_PATH, tmpdir);
|
||||
lstrcatW(tmpdir, tmp_dir_name);
|
||||
lstrcatW(tmpdir, slashW);
|
||||
lstrcatW(tmpdir, tmp_dir_name);
|
||||
ret = CreateDirectoryW(tmpdir, NULL);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND,
|
||||
"CreateDirectoryW with multiple nonexistent directories in path should fail\n");
|
||||
ret = RemoveDirectoryW(tmpdir);
|
||||
}
|
||||
|
||||
static void test_RemoveDirectoryA(void)
|
||||
{
|
||||
char tmpdir[MAX_PATH];
|
||||
BOOL ret;
|
||||
|
||||
GetTempPathA(MAX_PATH, tmpdir);
|
||||
lstrcatA(tmpdir, "Please Remove Me");
|
||||
ret = CreateDirectoryA(tmpdir, NULL);
|
||||
ok(ret == TRUE, "CreateDirectoryA should always succeed\n");
|
||||
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == TRUE, "RemoveDirectoryA should always succeed\n");
|
||||
|
||||
lstrcatA(tmpdir, "?");
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == FALSE && (GetLastError() == ERROR_INVALID_NAME ||
|
||||
GetLastError() == ERROR_PATH_NOT_FOUND),
|
||||
"RemoveDirectoryA with ? wildcard name should fail, ret=%s error=%ld\n",
|
||||
ret ? " True" : "False", GetLastError());
|
||||
|
||||
tmpdir[lstrlenA(tmpdir) - 1] = '*';
|
||||
ret = RemoveDirectoryA(tmpdir);
|
||||
ok(ret == FALSE && (GetLastError() == ERROR_INVALID_NAME ||
|
||||
GetLastError() == ERROR_PATH_NOT_FOUND),
|
||||
"RemoveDirectoryA with * wildcard name should fail, ret=%s error=%ld\n",
|
||||
ret ? " True" : "False", GetLastError());
|
||||
}
|
||||
|
||||
static void test_RemoveDirectoryW(void)
|
||||
{
|
||||
WCHAR tmpdir[MAX_PATH];
|
||||
BOOL ret;
|
||||
static const WCHAR tmp_dir_name[] = {'P','l','e','a','s','e',' ','R','e','m','o','v','e',' ','M','e',0};
|
||||
static const WCHAR questionW[] = {'?',0};
|
||||
|
||||
GetTempPathW(MAX_PATH, tmpdir);
|
||||
lstrcatW(tmpdir, tmp_dir_name);
|
||||
ret = CreateDirectoryW(tmpdir, NULL);
|
||||
if (!ret && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
|
||||
return;
|
||||
|
||||
ok(ret == TRUE, "CreateDirectoryW should always succeed\n");
|
||||
|
||||
ret = RemoveDirectoryW(tmpdir);
|
||||
ok(ret == TRUE, "RemoveDirectoryW should always succeed\n");
|
||||
|
||||
lstrcatW(tmpdir, questionW);
|
||||
ret = RemoveDirectoryW(tmpdir);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME,
|
||||
"RemoveDirectoryW with wildcard should fail with error 183, ret=%s error=%ld\n",
|
||||
ret ? " True" : "False", GetLastError());
|
||||
|
||||
tmpdir[lstrlenW(tmpdir) - 1] = '*';
|
||||
ret = RemoveDirectoryW(tmpdir);
|
||||
ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME,
|
||||
"RemoveDirectoryW with * wildcard name should fail with error 183, ret=%s error=%ld\n",
|
||||
ret ? " True" : "False", GetLastError());
|
||||
}
|
||||
|
||||
static void test_SetCurrentDirectoryA(void)
|
||||
{
|
||||
SetLastError(0);
|
||||
ok( !SetCurrentDirectoryA( "\\some_dummy_dir" ), "SetCurrentDirectoryA succeeded\n" );
|
||||
ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %ld\n", GetLastError() );
|
||||
ok( !SetCurrentDirectoryA( "\\some_dummy\\subdir" ), "SetCurrentDirectoryA succeeded\n" );
|
||||
ok( GetLastError() == ERROR_PATH_NOT_FOUND, "wrong error %ld\n", GetLastError() );
|
||||
}
|
||||
|
||||
START_TEST(directory)
|
||||
{
|
||||
test_GetWindowsDirectoryA();
|
||||
test_GetWindowsDirectoryW();
|
||||
|
||||
test_GetSystemDirectoryA();
|
||||
test_GetSystemDirectoryW();
|
||||
|
||||
test_CreateDirectoryA();
|
||||
test_CreateDirectoryW();
|
||||
|
||||
test_RemoveDirectoryA();
|
||||
test_RemoveDirectoryW();
|
||||
|
||||
test_SetCurrentDirectoryA();
|
||||
}
|
|
@ -1,209 +0,0 @@
|
|||
/*
|
||||
* Unit test suite for drive functions.
|
||||
*
|
||||
* Copyright 2002 Dmitry Timoshkov
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
|
||||
static DWORD (WINAPI *pGetDiskFreeSpaceExA)(LPCSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
|
||||
|
||||
static void test_GetDriveTypeA(void)
|
||||
{
|
||||
char drive[] = "?:\\";
|
||||
DWORD logical_drives;
|
||||
UINT type;
|
||||
|
||||
logical_drives = GetLogicalDrives();
|
||||
ok(logical_drives != 0, "GetLogicalDrives error %ld\n", GetLastError());
|
||||
|
||||
for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++)
|
||||
{
|
||||
type = GetDriveTypeA(drive);
|
||||
ok(type > 0 && type <= 6, "not a valid drive %c: type %u\n", drive[0], type);
|
||||
|
||||
if (!(logical_drives & 1))
|
||||
ok(type == DRIVE_NO_ROOT_DIR,
|
||||
"GetDriveTypeA should return DRIVE_NO_ROOT_DIR for inexistant drive %c: but not %u\n",
|
||||
drive[0], type);
|
||||
|
||||
logical_drives >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_GetDriveTypeW(void)
|
||||
{
|
||||
WCHAR drive[] = {'?',':','\\',0};
|
||||
DWORD logical_drives;
|
||||
UINT type;
|
||||
|
||||
logical_drives = GetLogicalDrives();
|
||||
ok(logical_drives != 0, "GetLogicalDrives error %ld\n", GetLastError());
|
||||
|
||||
for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++)
|
||||
{
|
||||
type = GetDriveTypeW(drive);
|
||||
if (type == DRIVE_UNKNOWN && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
|
||||
{
|
||||
/* Must be Win9x which doesn't support the Unicode functions */
|
||||
return;
|
||||
}
|
||||
ok(type > 0 && type <= 6, "not a valid drive %c: type %u\n", drive[0], type);
|
||||
|
||||
if (!(logical_drives & 1))
|
||||
ok(type == DRIVE_NO_ROOT_DIR,
|
||||
"GetDriveTypeW should return DRIVE_NO_ROOT_DIR for inexistant drive %c: but not %u\n",
|
||||
drive[0], type);
|
||||
|
||||
logical_drives >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_GetDiskFreeSpaceA(void)
|
||||
{
|
||||
BOOL ret;
|
||||
DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
|
||||
char drive[] = "?:\\";
|
||||
DWORD logical_drives;
|
||||
|
||||
ret = GetDiskFreeSpaceA(NULL, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
|
||||
ok(ret, "GetDiskFreeSpaceA error %ld\n", GetLastError());
|
||||
|
||||
ret = GetDiskFreeSpaceA("", §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
|
||||
ok(!ret && (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_INVALID_NAME),
|
||||
"GetDiskFreeSpaceA(\"\"): ret=%d GetLastError=%ld\n",
|
||||
ret, GetLastError());
|
||||
|
||||
ret = GetDiskFreeSpaceA("\\", §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
|
||||
ok(ret, "GetDiskFreeSpaceA error %ld\n", GetLastError());
|
||||
|
||||
ret = GetDiskFreeSpaceA("/", §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
|
||||
ok(ret, "GetDiskFreeSpaceA error %ld\n", GetLastError());
|
||||
|
||||
logical_drives = GetLogicalDrives();
|
||||
ok(logical_drives != 0, "GetLogicalDrives error %ld\n", GetLastError());
|
||||
|
||||
for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++)
|
||||
{
|
||||
UINT drivetype = GetDriveTypeA(drive);
|
||||
/* Skip floppy drives because NT pops up a MessageBox if no
|
||||
* floppy is present
|
||||
*/
|
||||
if (drivetype != DRIVE_REMOVABLE && drivetype != DRIVE_NO_ROOT_DIR)
|
||||
{
|
||||
ret = GetDiskFreeSpaceA(drive, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
|
||||
if (!(logical_drives & 1))
|
||||
ok(!ret && (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_INVALID_DRIVE),
|
||||
"GetDiskFreeSpaceA(%s): ret=%d GetLastError=%ld\n",
|
||||
drive, ret, GetLastError());
|
||||
else
|
||||
{
|
||||
ok(ret ||
|
||||
(!ret && (GetLastError() == ERROR_NOT_READY || GetLastError() == ERROR_INVALID_DRIVE)),
|
||||
"GetDiskFreeSpaceA(%s): ret=%d GetLastError=%ld\n",
|
||||
drive, ret, GetLastError());
|
||||
if( GetVersion() & 0x80000000)
|
||||
/* win3.0 thru winME */
|
||||
ok( total_clusters <= 65535,
|
||||
"total clusters is %ld > 65535\n", total_clusters);
|
||||
else if (pGetDiskFreeSpaceExA) {
|
||||
/* NT, 2k, XP : GetDiskFreeSpace shoud be accurate */
|
||||
ULARGE_INTEGER totEx, tot, d;
|
||||
|
||||
tot.QuadPart = sectors_per_cluster;
|
||||
tot.QuadPart = (tot.QuadPart * bytes_per_sector) * total_clusters;
|
||||
ret = pGetDiskFreeSpaceExA( drive, &d, &totEx, NULL);
|
||||
ok( ret || (!ret && ERROR_NOT_READY == GetLastError()),
|
||||
"GetDiskFreeSpaceExA( %s ) failed. GetLastError=%ld\n", drive, GetLastError());
|
||||
ok( bytes_per_sector == 0 || /* empty cd rom drive */
|
||||
totEx.QuadPart <= tot.QuadPart,
|
||||
"GetDiskFreeSpaceA should report at least as much bytes on disk %s as GetDiskFreeSpaceExA\n", drive);
|
||||
}
|
||||
}
|
||||
}
|
||||
logical_drives >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_GetDiskFreeSpaceW(void)
|
||||
{
|
||||
BOOL ret;
|
||||
DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
|
||||
WCHAR drive[] = {'?',':','\\',0};
|
||||
DWORD logical_drives;
|
||||
static const WCHAR empty_pathW[] = { 0 };
|
||||
static const WCHAR root_pathW[] = { '\\', 0 };
|
||||
static const WCHAR unix_style_root_pathW[] = { '/', 0 };
|
||||
|
||||
ret = GetDiskFreeSpaceW(NULL, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
|
||||
if (ret == 0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
|
||||
{
|
||||
/* Must be Win9x which doesn't support the Unicode functions */
|
||||
return;
|
||||
}
|
||||
ok(ret, "GetDiskFreeSpaceW error %ld\n", GetLastError());
|
||||
|
||||
ret = GetDiskFreeSpaceW(empty_pathW, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
|
||||
ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND,
|
||||
"GetDiskFreeSpaceW(\"\"): ret=%d GetLastError=%ld\n",
|
||||
ret, GetLastError());
|
||||
|
||||
ret = GetDiskFreeSpaceW(root_pathW, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
|
||||
ok(ret, "GetDiskFreeSpaceW(\"\") error %ld\n", GetLastError());
|
||||
|
||||
ret = GetDiskFreeSpaceW(unix_style_root_pathW, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
|
||||
ok(ret, "GetDiskFreeSpaceW error %ld\n", GetLastError());
|
||||
|
||||
logical_drives = GetLogicalDrives();
|
||||
ok(logical_drives != 0, "GetLogicalDrives error %ld\n", GetLastError());
|
||||
|
||||
for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++)
|
||||
{
|
||||
UINT drivetype = GetDriveTypeW(drive);
|
||||
/* Skip floppy drives because NT4 pops up a MessageBox if no floppy is present */
|
||||
if (drivetype != DRIVE_REMOVABLE && drivetype != DRIVE_NO_ROOT_DIR)
|
||||
{
|
||||
ret = GetDiskFreeSpaceW(drive, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
|
||||
if (!(logical_drives & 1))
|
||||
ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND,
|
||||
"GetDiskFreeSpaceW(%c): ret=%d GetLastError=%ld\n",
|
||||
drive[0], ret, GetLastError());
|
||||
else
|
||||
ok(ret || GetLastError() == ERROR_NOT_READY,
|
||||
"GetDiskFreeSpaceW(%c): ret=%d GetLastError=%ld\n",
|
||||
drive[0], ret, GetLastError());
|
||||
}
|
||||
logical_drives >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(drive)
|
||||
{
|
||||
HANDLE hkernel32 = GetModuleHandleA("kernel32");
|
||||
pGetDiskFreeSpaceExA = (void *) GetProcAddress(hkernel32, "GetDiskFreeSpaceExA");
|
||||
|
||||
test_GetDriveTypeA();
|
||||
test_GetDriveTypeW();
|
||||
|
||||
test_GetDiskFreeSpaceA();
|
||||
test_GetDiskFreeSpaceW();
|
||||
}
|
|
@ -1,232 +0,0 @@
|
|||
/*
|
||||
* Unit test suite for environment functions.
|
||||
*
|
||||
* Copyright 2002 Dmitry Timoshkov
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
|
||||
static void test_GetSetEnvironmentVariableA(void)
|
||||
{
|
||||
char buf[256];
|
||||
BOOL ret;
|
||||
DWORD ret_size;
|
||||
static const char name[] = "SomeWildName";
|
||||
static const char name_cased[] = "sOMEwILDnAME";
|
||||
static const char value[] = "SomeWildValue";
|
||||
|
||||
ret = SetEnvironmentVariableA(name, value);
|
||||
ok(ret == TRUE,
|
||||
"unexpected error in SetEnvironmentVariableA, GetLastError=%ld\n",
|
||||
GetLastError());
|
||||
|
||||
/* Try to retrieve the environment variable we just set */
|
||||
ret_size = GetEnvironmentVariableA(name, NULL, 0);
|
||||
ok(ret_size == strlen(value) + 1,
|
||||
"should return length with terminating 0 ret_size=%ld\n", ret_size);
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
ret_size = GetEnvironmentVariableA(name, buf, lstrlenA(value));
|
||||
ok(lstrcmpA(buf, "foo") == 0, "should not touch the buffer\n");
|
||||
ok(ret_size == strlen(value) + 1,
|
||||
"should return length with terminating 0 ret_size=%ld\n", ret_size);
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
ret_size = GetEnvironmentVariableA(name, buf, lstrlenA(value) + 1);
|
||||
ok(lstrcmpA(buf, value) == 0, "should touch the buffer\n");
|
||||
ok(ret_size == strlen(value),
|
||||
"should return length without terminating 0 ret_size=%ld\n", ret_size);
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
ret_size = GetEnvironmentVariableA(name_cased, buf, lstrlenA(value) + 1);
|
||||
ok(lstrcmpA(buf, value) == 0, "should touch the buffer\n");
|
||||
ok(ret_size == strlen(value),
|
||||
"should return length without terminating 0 ret_size=%ld\n", ret_size);
|
||||
|
||||
/* Remove that environment variable */
|
||||
ret = SetEnvironmentVariableA(name_cased, NULL);
|
||||
ok(ret == TRUE, "should erase existing variable\n");
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
ret_size = GetEnvironmentVariableA(name, buf, lstrlenA(value) + 1);
|
||||
ok(lstrcmpA(buf, "foo") == 0, "should not touch the buffer\n");
|
||||
ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND,
|
||||
"should not find variable but ret_size=%ld GetLastError=%ld\n",
|
||||
ret_size, GetLastError());
|
||||
|
||||
/* Check behavior of SetEnvironmentVariableA(name, "") */
|
||||
ret = SetEnvironmentVariableA(name, value);
|
||||
ok(ret == TRUE,
|
||||
"unexpected error in SetEnvironmentVariableA, GetLastError=%ld\n",
|
||||
GetLastError());
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
ret_size = GetEnvironmentVariableA(name_cased, buf, lstrlenA(value) + 1);
|
||||
ok(lstrcmpA(buf, value) == 0, "should touch the buffer\n");
|
||||
ok(ret_size == strlen(value),
|
||||
"should return length without terminating 0 ret_size=%ld\n", ret_size);
|
||||
|
||||
ret = SetEnvironmentVariableA(name_cased, "");
|
||||
ok(ret == TRUE,
|
||||
"should not fail with empty value but GetLastError=%ld\n", GetLastError());
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
SetLastError(0);
|
||||
ret_size = GetEnvironmentVariableA(name, buf, lstrlenA(value) + 1);
|
||||
ok(ret_size == 0 &&
|
||||
((GetLastError() == 0 && lstrcmpA(buf, "") == 0) ||
|
||||
(GetLastError() == ERROR_ENVVAR_NOT_FOUND)),
|
||||
"%s should be set to \"\" (NT) or removed (Win9x) but ret_size=%ld GetLastError=%ld and buf=%s\n",
|
||||
name, ret_size, GetLastError(), buf);
|
||||
|
||||
/* Test the limits */
|
||||
ret_size = GetEnvironmentVariableA(NULL, NULL, 0);
|
||||
ok(ret_size == 0 && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ENVVAR_NOT_FOUND),
|
||||
"should not find variable but ret_size=%ld GetLastError=%ld\n",
|
||||
ret_size, GetLastError());
|
||||
|
||||
ret_size = GetEnvironmentVariableA(NULL, buf, lstrlenA(value) + 1);
|
||||
ok(ret_size == 0 && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ENVVAR_NOT_FOUND),
|
||||
"should not find variable but ret_size=%ld GetLastError=%ld\n",
|
||||
ret_size, GetLastError());
|
||||
|
||||
ret_size = GetEnvironmentVariableA("", buf, lstrlenA(value) + 1);
|
||||
ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND,
|
||||
"should not find variable but ret_size=%ld GetLastError=%ld\n",
|
||||
ret_size, GetLastError());
|
||||
}
|
||||
|
||||
static void test_GetSetEnvironmentVariableW(void)
|
||||
{
|
||||
WCHAR buf[256];
|
||||
BOOL ret;
|
||||
DWORD ret_size;
|
||||
static const WCHAR name[] = {'S','o','m','e','W','i','l','d','N','a','m','e',0};
|
||||
static const WCHAR value[] = {'S','o','m','e','W','i','l','d','V','a','l','u','e',0};
|
||||
static const WCHAR name_cased[] = {'s','O','M','E','w','I','L','D','n','A','M','E',0};
|
||||
static const WCHAR empty_strW[] = { 0 };
|
||||
static const WCHAR fooW[] = {'f','o','o',0};
|
||||
|
||||
ret = SetEnvironmentVariableW(name, value);
|
||||
if (ret == FALSE && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
|
||||
{
|
||||
/* Must be Win9x which doesn't support the Unicode functions */
|
||||
return;
|
||||
}
|
||||
ok(ret == TRUE,
|
||||
"unexpected error in SetEnvironmentVariableW, GetLastError=%ld\n",
|
||||
GetLastError());
|
||||
|
||||
/* Try to retrieve the environment variable we just set */
|
||||
ret_size = GetEnvironmentVariableW(name, NULL, 0);
|
||||
ok(ret_size == lstrlenW(value) + 1,
|
||||
"should return length with terminating 0 ret_size=%ld\n",
|
||||
ret_size);
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value));
|
||||
ok(lstrcmpW(buf, fooW) == 0, "should not touch the buffer\n");
|
||||
|
||||
ok(ret_size == lstrlenW(value) + 1,
|
||||
"should return length with terminating 0 ret_size=%ld\n", ret_size);
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value) + 1);
|
||||
ok(lstrcmpW(buf, value) == 0, "should touch the buffer\n");
|
||||
ok(ret_size == lstrlenW(value),
|
||||
"should return length without terminating 0 ret_size=%ld\n", ret_size);
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
ret_size = GetEnvironmentVariableW(name_cased, buf, lstrlenW(value) + 1);
|
||||
ok(lstrcmpW(buf, value) == 0, "should touch the buffer\n");
|
||||
ok(ret_size == lstrlenW(value),
|
||||
"should return length without terminating 0 ret_size=%ld\n", ret_size);
|
||||
|
||||
/* Remove that environment variable */
|
||||
ret = SetEnvironmentVariableW(name_cased, NULL);
|
||||
ok(ret == TRUE, "should erase existing variable\n");
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value) + 1);
|
||||
ok(lstrcmpW(buf, fooW) == 0, "should not touch the buffer\n");
|
||||
ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND,
|
||||
"should not find variable but ret_size=%ld GetLastError=%ld\n",
|
||||
ret_size, GetLastError());
|
||||
|
||||
/* Check behavior of SetEnvironmentVariableW(name, "") */
|
||||
ret = SetEnvironmentVariableW(name, value);
|
||||
ok(ret == TRUE,
|
||||
"unexpected error in SetEnvironmentVariableW, GetLastError=%ld\n",
|
||||
GetLastError());
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value) + 1);
|
||||
ok(lstrcmpW(buf, value) == 0, "should touch the buffer\n");
|
||||
ok(ret_size == lstrlenW(value),
|
||||
"should return length without terminating 0 ret_size=%ld\n", ret_size);
|
||||
|
||||
ret = SetEnvironmentVariableW(name_cased, empty_strW);
|
||||
ok(ret == TRUE, "should not fail with empty value but GetLastError=%ld\n", GetLastError());
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value) + 1);
|
||||
ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND,
|
||||
"should not find variable but ret_size=%ld GetLastError=%ld\n",
|
||||
ret_size, GetLastError());
|
||||
ok(lstrcmpW(buf, empty_strW) == 0, "should copy an empty string\n");
|
||||
|
||||
/* Test the limits */
|
||||
ret_size = GetEnvironmentVariableW(NULL, NULL, 0);
|
||||
ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND,
|
||||
"should not find variable but ret_size=%ld GetLastError=%ld\n",
|
||||
ret_size, GetLastError());
|
||||
|
||||
ret_size = GetEnvironmentVariableW(NULL, buf, lstrlenW(value) + 1);
|
||||
ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND,
|
||||
"should not find variable but ret_size=%ld GetLastError=%ld\n",
|
||||
ret_size, GetLastError());
|
||||
|
||||
ret = SetEnvironmentVariableW(NULL, NULL);
|
||||
ok(ret == FALSE && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ENVVAR_NOT_FOUND),
|
||||
"should fail with NULL, NULL but ret=%d and GetLastError=%ld\n",
|
||||
ret, GetLastError());
|
||||
}
|
||||
|
||||
static void test_ExpandEnvironmentStringsA(void)
|
||||
{
|
||||
char buf[256], buf1[256];
|
||||
DWORD ret_size, ret_size1;
|
||||
|
||||
ret_size1 = GetWindowsDirectoryA(buf1,256);
|
||||
ok ((ret_size1 >0) && (ret_size1<256), "GetWindowsDirectory Failed\n");
|
||||
ret_size = ExpandEnvironmentStringsA("%SystemRoot%",buf,sizeof(buf));
|
||||
if (ERROR_ENVVAR_NOT_FOUND == GetLastError())
|
||||
return;
|
||||
ok(!strcmp(buf, buf1), "ExpandEnvironmentStrings failed %s vs %s. ret_size = %ld\n", buf, buf1, ret_size);
|
||||
}
|
||||
|
||||
START_TEST(environ)
|
||||
{
|
||||
test_GetSetEnvironmentVariableA();
|
||||
test_GetSetEnvironmentVariableW();
|
||||
test_ExpandEnvironmentStringsA();
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,226 +0,0 @@
|
|||
/* Unit test suite for FormatMessageA
|
||||
*
|
||||
* Copyright 2002 Mike McCormack 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 <stdarg.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
|
||||
/* #define ok(cond,failstr) if(!(cond)) {printf("line %d : %s\n",__LINE__,failstr);exit(1);} */
|
||||
|
||||
static DWORD doit(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id,
|
||||
LPSTR out, DWORD outsize, ... )
|
||||
{
|
||||
va_list list;
|
||||
DWORD r;
|
||||
|
||||
va_start(list, outsize);
|
||||
r = FormatMessageA(flags, src, msg_id,
|
||||
lang_id, out, outsize, &list);
|
||||
va_end(list);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void test_message_from_string(void)
|
||||
{
|
||||
CHAR out[0x100] = {0};
|
||||
DWORD r;
|
||||
static const WCHAR szwTest[] = { 't','e','s','t',0};
|
||||
|
||||
/* the basics */
|
||||
r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR),NULL);
|
||||
ok(!strcmp("test", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* using the format feature */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!s!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), "test");
|
||||
ok(!strcmp("test", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* no format */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), "test");
|
||||
ok(!strcmp("test", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* two pieces */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1%2", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), "te","st");
|
||||
ok(!strcmp("test", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* three pieces */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1%3%2%1", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), "t","s","e");
|
||||
ok(!strcmp("test", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* s doesn't seem to work in format strings */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%!s!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), "test");
|
||||
ok(!strcmp("!s!", out),"failed out=[%s]\n",out);
|
||||
ok(r==3,"failed: r=%ld\n",r);
|
||||
|
||||
/* S is unicode */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!S!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), szwTest);
|
||||
ok(!strcmp("test", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* as characters */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!c!%2!c!%3!c!%1!c!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), 't','e','s');
|
||||
ok(!strcmp("test", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* some numbers */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!d!%2!d!%3!d!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), 1,2,3);
|
||||
ok(!strcmp("123", out),"failed out=[%s]\n",out);
|
||||
ok(r==3,"failed: r=%ld\n",r);
|
||||
|
||||
/* a single digit with some spacing */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4d!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), 1);
|
||||
ok(!strcmp(" 1", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* a single digit, left justified */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!-4d!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), 1);
|
||||
ok(!strcmp("1 ", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* two digit decimal number */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4d!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), 11);
|
||||
ok(!strcmp(" 11", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* a hex number */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4x!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), 11);
|
||||
ok(!strcmp(" b", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* a hex number, upper case */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4X!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), 11);
|
||||
ok(!strcmp(" B", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* a hex number, upper case, left justified */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!-4X!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), 11);
|
||||
ok(!strcmp("B ", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* a long hex number, upper case */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4X!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), 0x1ab);
|
||||
ok(!strcmp(" 1AB", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* two percent... */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, " %%%% ", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp(" %% ", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* periods are special cases */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, " %.%. %1!d!", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR), 0x1ab);
|
||||
ok(!strcmp(" .. 427", out),"failed out=[%s]\n",out);
|
||||
ok(r==7,"failed: r=%ld\n",r);
|
||||
|
||||
/* %0 ends the line */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "test%0test", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp("test", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* %! prints an exclaimation */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "yah%!%0 ", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp("yah!", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* %space */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "% % ", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp(" ", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "hi\n", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp("hi\r\n", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "hi\r\n", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp("hi\r\n", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "\r", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp("\r\n", out),"failed out=[%s]\n",out);
|
||||
ok(r==2,"failed: r=%ld\n",r);
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING, "\r\r\n", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp("\r\n\r\n", out),"failed out=[%s]\n",out);
|
||||
ok(r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* change of pace... test the low byte of dwflags */
|
||||
/* line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\n", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp("hi ", out) || !strcmp("hi\r\n", out),"failed out=[%s]\n",out);
|
||||
ok(r==3 || r==4,"failed: r=%ld\n",r);
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\r\n", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp("hi ", out),"failed out=[%s]\n",out);
|
||||
ok(r==3,"failed: r=%ld\n",r);
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp(" ", out),"failed out=[%s]\n",out);
|
||||
ok(r==1,"failed: r=%ld\n",r);
|
||||
|
||||
/* carriage return line feed */
|
||||
r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r\r\n", 0,
|
||||
0, out, sizeof(out)/sizeof(CHAR));
|
||||
ok(!strcmp(" ", out),"failed out=[%s]\n",out);
|
||||
ok(r==2,"failed: r=%ld\n",r);
|
||||
}
|
||||
|
||||
START_TEST(format_msg)
|
||||
{
|
||||
test_message_from_string();
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,282 +0,0 @@
|
|||
/*
|
||||
* Unit test suite for heap functions
|
||||
*
|
||||
* Copyright 2003 Dimitrie O. Paun
|
||||
* Copyright 2006 Detlef Riekenberg
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wine/test.h"
|
||||
|
||||
#define MAGIC_DEAD 0xdeadbeef
|
||||
|
||||
static SIZE_T resize_9x(SIZE_T size)
|
||||
{
|
||||
DWORD dwSizeAligned = (size + 3) & ~3;
|
||||
return max(dwSizeAligned, 12); /* at least 12 bytes */
|
||||
}
|
||||
|
||||
START_TEST(heap)
|
||||
{
|
||||
LPVOID mem;
|
||||
LPVOID msecond;
|
||||
DWORD res;
|
||||
UINT flags;
|
||||
HGLOBAL gbl;
|
||||
HGLOBAL hsecond;
|
||||
SIZE_T size;
|
||||
|
||||
/* Heap*() functions */
|
||||
mem = HeapAlloc(GetProcessHeap(), 0, 0);
|
||||
ok(mem != NULL, "memory not allocated for size 0\n");
|
||||
|
||||
mem = HeapReAlloc(GetProcessHeap(), 0, NULL, 10);
|
||||
ok(mem == NULL, "memory allocated by HeapReAlloc\n");
|
||||
|
||||
for (size = 0; size <= 256; size++)
|
||||
{
|
||||
SIZE_T heap_size;
|
||||
mem = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
heap_size = HeapSize(GetProcessHeap(), 0, mem);
|
||||
ok(heap_size == size || heap_size == resize_9x(size),
|
||||
"HeapSize returned %lu instead of %lu or %lu\n", heap_size, size, resize_9x(size));
|
||||
HeapFree(GetProcessHeap(), 0, mem);
|
||||
}
|
||||
|
||||
/* Global*() functions */
|
||||
gbl = GlobalAlloc(GMEM_MOVEABLE, 0);
|
||||
ok(gbl != NULL, "global memory not allocated for size 0\n");
|
||||
|
||||
gbl = GlobalReAlloc(gbl, 10, GMEM_MOVEABLE);
|
||||
ok(gbl != NULL, "Can't realloc global memory\n");
|
||||
size = GlobalSize(gbl);
|
||||
ok(size >= 10 && size <= 16, "Memory not resized to size 10, instead size=%ld\n", size);
|
||||
|
||||
gbl = GlobalReAlloc(gbl, 0, GMEM_MOVEABLE);
|
||||
ok(gbl != NULL, "GlobalReAlloc should not fail on size 0\n");
|
||||
|
||||
size = GlobalSize(gbl);
|
||||
ok(size == 0, "Memory not resized to size 0, instead size=%ld\n", size);
|
||||
ok(GlobalFree(gbl) == NULL, "Memory not freed\n");
|
||||
size = GlobalSize(gbl);
|
||||
ok(size == 0, "Memory should have been freed, size=%ld\n", size);
|
||||
|
||||
gbl = GlobalReAlloc(0, 10, GMEM_MOVEABLE);
|
||||
ok(gbl == NULL, "global realloc allocated memory\n");
|
||||
|
||||
/* GlobalLock / GlobalUnlock with a valid handle */
|
||||
gbl = GlobalAlloc(GMEM_MOVEABLE, 256);
|
||||
|
||||
SetLastError(MAGIC_DEAD);
|
||||
mem = GlobalLock(gbl); /* #1 */
|
||||
ok(mem != NULL, "returned %p with %ld (expected '!= NULL')\n", mem, GetLastError());
|
||||
SetLastError(MAGIC_DEAD);
|
||||
flags = GlobalFlags(gbl);
|
||||
ok( flags == 1, "returned 0x%04x with %ld (expected '0x0001')\n",
|
||||
flags, GetLastError());
|
||||
|
||||
SetLastError(MAGIC_DEAD);
|
||||
msecond = GlobalLock(gbl); /* #2 */
|
||||
ok( msecond == mem, "returned %p with %ld (expected '%p')\n",
|
||||
msecond, GetLastError(), mem);
|
||||
SetLastError(MAGIC_DEAD);
|
||||
flags = GlobalFlags(gbl);
|
||||
ok( flags == 2, "returned 0x%04x with %ld (expected '0x0002')\n",
|
||||
flags, GetLastError());
|
||||
SetLastError(MAGIC_DEAD);
|
||||
|
||||
SetLastError(MAGIC_DEAD);
|
||||
res = GlobalUnlock(gbl); /* #1 */
|
||||
ok(res, "returned %ld with %ld (expected '!= 0')\n", res, GetLastError());
|
||||
SetLastError(MAGIC_DEAD);
|
||||
flags = GlobalFlags(gbl);
|
||||
ok( flags , "returned 0x%04x with %ld (expected '!= 0')\n",
|
||||
flags, GetLastError());
|
||||
|
||||
SetLastError(MAGIC_DEAD);
|
||||
res = GlobalUnlock(gbl); /* #0 */
|
||||
/* NT: ERROR_SUCCESS (documented on MSDN), 9x: untouched */
|
||||
ok(!res && ((GetLastError() == ERROR_SUCCESS) || (GetLastError() == MAGIC_DEAD)),
|
||||
"returned %ld with %ld (expected '0' with: ERROR_SUCCESS or " \
|
||||
"MAGIC_DEAD)\n", res, GetLastError());
|
||||
SetLastError(MAGIC_DEAD);
|
||||
flags = GlobalFlags(gbl);
|
||||
ok( !flags , "returned 0x%04x with %ld (expected '0')\n",
|
||||
flags, GetLastError());
|
||||
|
||||
/* Unlock an already unlocked Handle */
|
||||
SetLastError(MAGIC_DEAD);
|
||||
res = GlobalUnlock(gbl);
|
||||
/* NT: ERROR_NOT_LOCKED, 9x: untouched */
|
||||
ok( !res &&
|
||||
((GetLastError() == ERROR_NOT_LOCKED) || (GetLastError() == MAGIC_DEAD)),
|
||||
"returned %ld with %ld (expected '0' with: ERROR_NOT_LOCKED or " \
|
||||
"MAGIC_DEAD)\n", res, GetLastError());
|
||||
|
||||
GlobalFree(gbl);
|
||||
/* invalid handles are catched in windows: */
|
||||
SetLastError(MAGIC_DEAD);
|
||||
hsecond = GlobalFree(gbl); /* invalid handle: free memory twice */
|
||||
ok( (hsecond == gbl) && (GetLastError() == ERROR_INVALID_HANDLE),
|
||||
"returned %p with 0x%08lx (expected %p with ERROR_INVALID_HANDLE)\n",
|
||||
hsecond, GetLastError(), gbl);
|
||||
SetLastError(MAGIC_DEAD);
|
||||
flags = GlobalFlags(gbl);
|
||||
ok( (flags == GMEM_INVALID_HANDLE) && (GetLastError() == ERROR_INVALID_HANDLE),
|
||||
"returned 0x%04x with 0x%08lx (expected GMEM_INVALID_HANDLE with " \
|
||||
"ERROR_INVALID_HANDLE)\n", flags, GetLastError());
|
||||
SetLastError(MAGIC_DEAD);
|
||||
size = GlobalSize(gbl);
|
||||
ok( (size == 0) && (GetLastError() == ERROR_INVALID_HANDLE),
|
||||
"returned %ld with 0x%08lx (expected '0' with ERROR_INVALID_HANDLE)\n",
|
||||
size, GetLastError());
|
||||
|
||||
SetLastError(MAGIC_DEAD);
|
||||
mem = GlobalLock(gbl);
|
||||
ok( (mem == NULL) && (GetLastError() == ERROR_INVALID_HANDLE),
|
||||
"returned %p with 0x%08lx (expected NULL with ERROR_INVALID_HANDLE)\n",
|
||||
mem, GetLastError());
|
||||
|
||||
/* documented on MSDN: GlobalUnlock() return FALSE on failure.
|
||||
Win9x and wine return FALSE with ERROR_INVALID_HANDLE, but on
|
||||
NT 3.51 and XPsp2, TRUE with ERROR_INVALID_HANDLE is returned.
|
||||
The similar Test for LocalUnlock() works on all Systems */
|
||||
SetLastError(MAGIC_DEAD);
|
||||
res = GlobalUnlock(gbl);
|
||||
ok(GetLastError() == ERROR_INVALID_HANDLE,
|
||||
"returned %ld with %ld (expected ERROR_INVALID_HANDLE)\n",
|
||||
res, GetLastError());
|
||||
|
||||
|
||||
/* ####################################### */
|
||||
/* Local*() functions */
|
||||
gbl = LocalAlloc(LMEM_MOVEABLE, 0);
|
||||
ok(gbl != NULL, "local memory not allocated for size 0\n");
|
||||
|
||||
gbl = LocalReAlloc(gbl, 10, LMEM_MOVEABLE);
|
||||
ok(gbl != NULL, "Can't realloc local memory\n");
|
||||
size = LocalSize(gbl);
|
||||
ok(size >= 10 && size <= 16, "Memory not resized to size 10, instead size=%ld\n", size);
|
||||
|
||||
gbl = LocalReAlloc(gbl, 0, LMEM_MOVEABLE);
|
||||
ok(gbl != NULL, "LocalReAlloc should not fail on size 0\n");
|
||||
|
||||
size = LocalSize(gbl);
|
||||
ok(size == 0, "Memory not resized to size 0, instead size=%ld\n", size);
|
||||
ok(LocalFree(gbl) == NULL, "Memory not freed\n");
|
||||
size = LocalSize(gbl);
|
||||
ok(size == 0, "Memory should have been freed, size=%ld\n", size);
|
||||
|
||||
gbl = LocalReAlloc(0, 10, LMEM_MOVEABLE);
|
||||
ok(gbl == NULL, "local realloc allocated memory\n");
|
||||
|
||||
/* LocalLock / LocalUnlock with a valid handle */
|
||||
gbl = LocalAlloc(LMEM_MOVEABLE, 256);
|
||||
SetLastError(MAGIC_DEAD);
|
||||
mem = LocalLock(gbl); /* #1 */
|
||||
ok(mem != NULL, "returned %p with %ld (expected '!= NULL')\n", mem, GetLastError());
|
||||
SetLastError(MAGIC_DEAD);
|
||||
flags = LocalFlags(gbl);
|
||||
ok( flags == 1, "returned 0x%04x with %ld (expected '0x0001')\n",
|
||||
flags, GetLastError());
|
||||
|
||||
SetLastError(MAGIC_DEAD);
|
||||
msecond = LocalLock(gbl); /* #2 */
|
||||
ok( msecond == mem, "returned %p with %ld (expected '%p')\n",
|
||||
msecond, GetLastError(), mem);
|
||||
SetLastError(MAGIC_DEAD);
|
||||
flags = LocalFlags(gbl);
|
||||
ok( flags == 2, "returned 0x%04x with %ld (expected '0x0002')\n",
|
||||
flags, GetLastError());
|
||||
SetLastError(MAGIC_DEAD);
|
||||
|
||||
SetLastError(MAGIC_DEAD);
|
||||
res = LocalUnlock(gbl); /* #1 */
|
||||
ok(res, "returned %ld with %ld (expected '!= 0')\n", res, GetLastError());
|
||||
SetLastError(MAGIC_DEAD);
|
||||
flags = LocalFlags(gbl);
|
||||
ok( flags , "returned 0x%04x with %ld (expected '!= 0')\n",
|
||||
flags, GetLastError());
|
||||
|
||||
SetLastError(MAGIC_DEAD);
|
||||
res = LocalUnlock(gbl); /* #0 */
|
||||
/* NT: ERROR_SUCCESS (documented on MSDN), 9x: untouched */
|
||||
ok(!res && ((GetLastError() == ERROR_SUCCESS) || (GetLastError() == MAGIC_DEAD)),
|
||||
"returned %ld with %ld (expected '0' with: ERROR_SUCCESS or " \
|
||||
"MAGIC_DEAD)\n", res, GetLastError());
|
||||
SetLastError(MAGIC_DEAD);
|
||||
flags = LocalFlags(gbl);
|
||||
ok( !flags , "returned 0x%04x with %ld (expected '0')\n",
|
||||
flags, GetLastError());
|
||||
|
||||
/* Unlock an already unlocked Handle */
|
||||
SetLastError(MAGIC_DEAD);
|
||||
res = LocalUnlock(gbl);
|
||||
/* NT: ERROR_NOT_LOCKED, 9x: untouched */
|
||||
ok( !res &&
|
||||
((GetLastError() == ERROR_NOT_LOCKED) || (GetLastError() == MAGIC_DEAD)),
|
||||
"returned %ld with %ld (expected '0' with: ERROR_NOT_LOCKED or " \
|
||||
"MAGIC_DEAD)\n", res, GetLastError());
|
||||
|
||||
LocalFree(gbl);
|
||||
/* invalid handles are catched in windows: */
|
||||
SetLastError(MAGIC_DEAD);
|
||||
hsecond = LocalFree(gbl); /* invalid handle: free memory twice */
|
||||
ok( (hsecond == gbl) && (GetLastError() == ERROR_INVALID_HANDLE),
|
||||
"returned %p with 0x%08lx (expected %p with ERROR_INVALID_HANDLE)\n",
|
||||
hsecond, GetLastError(), gbl);
|
||||
SetLastError(MAGIC_DEAD);
|
||||
flags = LocalFlags(gbl);
|
||||
ok( (flags == LMEM_INVALID_HANDLE) && (GetLastError() == ERROR_INVALID_HANDLE),
|
||||
"returned 0x%04x with 0x%08lx (expected LMEM_INVALID_HANDLE with " \
|
||||
"ERROR_INVALID_HANDLE)\n", flags, GetLastError());
|
||||
SetLastError(MAGIC_DEAD);
|
||||
size = LocalSize(gbl);
|
||||
ok( (size == 0) && (GetLastError() == ERROR_INVALID_HANDLE),
|
||||
"returned %ld with 0x%08lx (expected '0' with ERROR_INVALID_HANDLE)\n",
|
||||
size, GetLastError());
|
||||
|
||||
SetLastError(MAGIC_DEAD);
|
||||
mem = LocalLock(gbl);
|
||||
ok( (mem == NULL) && (GetLastError() == ERROR_INVALID_HANDLE),
|
||||
"returned %p with 0x%08lx (expected NULL with ERROR_INVALID_HANDLE)\n",
|
||||
mem, GetLastError());
|
||||
|
||||
/* This Test works the same on all Systems (GlobalUnlock() is different) */
|
||||
SetLastError(MAGIC_DEAD);
|
||||
res = LocalUnlock(gbl);
|
||||
ok(!res && (GetLastError() == ERROR_INVALID_HANDLE),
|
||||
"returned %ld with %ld (expected '0' with ERROR_INVALID_HANDLE)\n",
|
||||
res, GetLastError());
|
||||
|
||||
/* trying to lock empty memory should give an error */
|
||||
gbl = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,0);
|
||||
ok(gbl != NULL, "returned NULL\n");
|
||||
SetLastError(MAGIC_DEAD);
|
||||
mem = GlobalLock(gbl);
|
||||
/* NT: ERROR_DISCARDED, 9x: untouched */
|
||||
ok( (mem == NULL) &&
|
||||
((GetLastError() == ERROR_DISCARDED) || (GetLastError() == MAGIC_DEAD)),
|
||||
"returned %p with 0x%lx/%ld (expected 'NULL' with: ERROR_DISCARDED or " \
|
||||
"MAGIC_DEAD)\n", mem, GetLastError(), GetLastError());
|
||||
|
||||
GlobalFree(gbl);
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,290 +0,0 @@
|
|||
/*
|
||||
* Mailslot regression test
|
||||
*
|
||||
* Copyright 2003 Mike McCormack
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
static const char szmspath[] = "\\\\.\\mailslot\\wine_mailslot_test";
|
||||
|
||||
static int mailslot_test(void)
|
||||
{
|
||||
HANDLE hSlot, hSlot2, hWriter, hWriter2;
|
||||
unsigned char buffer[16];
|
||||
DWORD count, dwMax, dwNext, dwMsgCount, dwTimeout;
|
||||
|
||||
/* sanity check on GetMailslotInfo */
|
||||
dwMax = dwNext = dwMsgCount = dwTimeout = 0;
|
||||
ok( !GetMailslotInfo( INVALID_HANDLE_VALUE, &dwMax, &dwNext,
|
||||
&dwMsgCount, &dwTimeout ), "getmailslotinfo succeeded\n");
|
||||
|
||||
/* open a mailslot that doesn't exist */
|
||||
hWriter = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
ok( hWriter == INVALID_HANDLE_VALUE, "nonexistent mailslot\n");
|
||||
|
||||
/* open a mailslot without the right name */
|
||||
hSlot = CreateMailslot( "blah", 0, 0, NULL );
|
||||
ok( hSlot == INVALID_HANDLE_VALUE,
|
||||
"Created mailslot with invalid name\n");
|
||||
ok( GetLastError() == ERROR_INVALID_NAME,
|
||||
"error should be ERROR_INVALID_NAME\n");
|
||||
|
||||
/* open a mailslot with a null name */
|
||||
hSlot = CreateMailslot( NULL, 0, 0, NULL );
|
||||
ok( hSlot == INVALID_HANDLE_VALUE,
|
||||
"Created mailslot with invalid name\n");
|
||||
ok( GetLastError() == ERROR_PATH_NOT_FOUND,
|
||||
"error should be ERROR_PATH_NOT_FOUND\n");
|
||||
|
||||
/* valid open, but with wacky parameters ... then check them */
|
||||
hSlot = CreateMailslot( szmspath, -1, -1, NULL );
|
||||
ok( hSlot != INVALID_HANDLE_VALUE , "mailslot with valid name failed\n");
|
||||
dwMax = dwNext = dwMsgCount = dwTimeout = 0;
|
||||
ok( GetMailslotInfo( hSlot, &dwMax, &dwNext, &dwMsgCount, &dwTimeout ),
|
||||
"getmailslotinfo failed\n");
|
||||
ok( dwMax == ~0U, "dwMax incorrect\n");
|
||||
ok( dwNext == MAILSLOT_NO_MESSAGE, "dwNext incorrect\n");
|
||||
ok( dwMsgCount == 0, "dwMsgCount incorrect\n");
|
||||
ok( dwTimeout == ~0U, "dwTimeout incorrect\n");
|
||||
ok( GetMailslotInfo( hSlot, NULL, NULL, NULL, NULL ),
|
||||
"getmailslotinfo failed\n");
|
||||
ok( CloseHandle(hSlot), "failed to close mailslot\n");
|
||||
|
||||
/* now open it for real */
|
||||
hSlot = CreateMailslot( szmspath, 0, 0, NULL );
|
||||
ok( hSlot != INVALID_HANDLE_VALUE , "valid mailslot failed\n");
|
||||
|
||||
/* try and read/write to it */
|
||||
count = 0;
|
||||
memset(buffer, 0, sizeof buffer);
|
||||
ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL),
|
||||
"slot read\n");
|
||||
ok( !WriteFile( hSlot, buffer, sizeof buffer, &count, NULL),
|
||||
"slot write\n");
|
||||
|
||||
/* now try and openthe client, but with the wrong sharing mode */
|
||||
hWriter = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE,
|
||||
0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
ok( hWriter == INVALID_HANDLE_VALUE, "bad sharing mode\n");
|
||||
ok( GetLastError() == ERROR_SHARING_VIOLATION,
|
||||
"error should be ERROR_SHARING_VIOLATION\n");
|
||||
|
||||
/* now open the client with the correct sharing mode */
|
||||
hWriter = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
ok( hWriter != INVALID_HANDLE_VALUE, "existing mailslot\n");
|
||||
|
||||
/*
|
||||
* opening a client should make no difference to
|
||||
* whether we can read or write the mailslot
|
||||
*/
|
||||
ok( !ReadFile( hSlot, buffer, sizeof buffer/2, &count, NULL),
|
||||
"slot read\n");
|
||||
ok( !WriteFile( hSlot, buffer, sizeof buffer/2, &count, NULL),
|
||||
"slot write\n");
|
||||
|
||||
/*
|
||||
* we can't read from this client,
|
||||
* but we should be able to write to it
|
||||
*/
|
||||
ok( !ReadFile( hWriter, buffer, sizeof buffer/2, &count, NULL),
|
||||
"can read client\n");
|
||||
ok( WriteFile( hWriter, buffer, sizeof buffer/2, &count, NULL),
|
||||
"can't write client\n");
|
||||
ok( !ReadFile( hWriter, buffer, sizeof buffer/2, &count, NULL),
|
||||
"can read client\n");
|
||||
|
||||
/*
|
||||
* seeing as there's something in the slot,
|
||||
* we should be able to read it once
|
||||
*/
|
||||
ok( ReadFile( hSlot, buffer, sizeof buffer, &count, NULL),
|
||||
"slot read\n");
|
||||
ok( count == (sizeof buffer/2), "short read\n" );
|
||||
|
||||
/* but not again */
|
||||
ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL),
|
||||
"slot read\n");
|
||||
|
||||
/* now try open another writer... should fail */
|
||||
hWriter2 = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
ok( hWriter2 == INVALID_HANDLE_VALUE, "two writers\n");
|
||||
|
||||
/* now try open another as a reader ... also fails */
|
||||
hWriter2 = CreateFile(szmspath, GENERIC_READ,
|
||||
FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
ok( hWriter2 == INVALID_HANDLE_VALUE, "writer + reader\n");
|
||||
|
||||
/* now try open another as a writer ... still fails */
|
||||
hWriter2 = CreateFile(szmspath, GENERIC_WRITE,
|
||||
FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
ok( hWriter2 == INVALID_HANDLE_VALUE, "writer\n");
|
||||
|
||||
/* now open another one */
|
||||
hSlot2 = CreateMailslot( szmspath, 0, 0, NULL );
|
||||
ok( hSlot2 == INVALID_HANDLE_VALUE , "opened two mailslots\n");
|
||||
|
||||
/* close the client again */
|
||||
ok( CloseHandle( hWriter ), "closing the client\n");
|
||||
|
||||
/*
|
||||
* now try reopen it with slightly different permissions ...
|
||||
* shared writing
|
||||
*/
|
||||
hWriter = CreateFile(szmspath, GENERIC_WRITE,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
ok( hWriter != INVALID_HANDLE_VALUE, "sharing writer\n");
|
||||
|
||||
/*
|
||||
* now try open another as a writer ...
|
||||
* but don't share with the first ... fail
|
||||
*/
|
||||
hWriter2 = CreateFile(szmspath, GENERIC_WRITE,
|
||||
FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
ok( hWriter2 == INVALID_HANDLE_VALUE, "greedy writer succeeded\n");
|
||||
|
||||
/* now try open another as a writer ... and share with the first */
|
||||
hWriter2 = CreateFile(szmspath, GENERIC_WRITE,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
ok( hWriter2 != INVALID_HANDLE_VALUE, "2nd sharing writer\n");
|
||||
|
||||
/* check the mailslot info */
|
||||
dwMax = dwNext = dwMsgCount = dwTimeout = 0;
|
||||
ok( GetMailslotInfo( hSlot, &dwMax, &dwNext, &dwMsgCount, &dwTimeout ),
|
||||
"getmailslotinfo failed\n");
|
||||
ok( dwNext == MAILSLOT_NO_MESSAGE, "dwNext incorrect\n");
|
||||
ok( dwMax == 0, "dwMax incorrect\n");
|
||||
ok( dwMsgCount == 0, "dwMsgCount incorrect\n");
|
||||
ok( dwTimeout == 0, "dwTimeout incorrect\n");
|
||||
|
||||
/* check there's still no data */
|
||||
ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), "slot read\n");
|
||||
|
||||
/* write two messages */
|
||||
buffer[0] = 'a';
|
||||
ok( WriteFile( hWriter, buffer, 1, &count, NULL), "1st write failed\n");
|
||||
|
||||
/* check the mailslot info */
|
||||
dwNext = dwMsgCount = 0;
|
||||
ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ),
|
||||
"getmailslotinfo failed\n");
|
||||
ok( dwNext == 1, "dwNext incorrect\n");
|
||||
ok( dwMsgCount == 1, "dwMsgCount incorrect\n");
|
||||
|
||||
buffer[0] = 'b';
|
||||
buffer[1] = 'c';
|
||||
ok( WriteFile( hWriter2, buffer, 2, &count, NULL), "2nd write failed\n");
|
||||
|
||||
/* check the mailslot info */
|
||||
dwNext = dwMsgCount = 0;
|
||||
ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ),
|
||||
"getmailslotinfo failed\n");
|
||||
ok( dwNext == 1, "dwNext incorrect\n");
|
||||
todo_wine {
|
||||
ok( dwMsgCount == 2, "dwMsgCount incorrect\n");
|
||||
}
|
||||
|
||||
/* write a 3rd message with zero size */
|
||||
ok( WriteFile( hWriter2, buffer, 0, &count, NULL), "3rd write failed\n");
|
||||
|
||||
/* check the mailslot info */
|
||||
dwNext = dwMsgCount = 0;
|
||||
ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ),
|
||||
"getmailslotinfo failed\n");
|
||||
ok( dwNext == 1, "dwNext incorrect\n");
|
||||
todo_wine {
|
||||
ok( dwMsgCount == 3, "dwMsgCount incorrect\n");
|
||||
}
|
||||
|
||||
buffer[0]=buffer[1]=0;
|
||||
|
||||
/*
|
||||
* then check that they come out with the correct order and size,
|
||||
* then the slot is empty
|
||||
*/
|
||||
ok( ReadFile( hSlot, buffer, sizeof buffer, &count, NULL),
|
||||
"1st slot read failed\n");
|
||||
ok( count == 1, "failed to get 1st message\n");
|
||||
ok( buffer[0] == 'a', "1st message wrong\n");
|
||||
|
||||
/* check the mailslot info */
|
||||
dwNext = dwMsgCount = 0;
|
||||
ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ),
|
||||
"getmailslotinfo failed\n");
|
||||
ok( dwNext == 2, "dwNext incorrect\n");
|
||||
todo_wine {
|
||||
ok( dwMsgCount == 2, "dwMsgCount incorrect\n");
|
||||
}
|
||||
|
||||
/* read the second message */
|
||||
ok( ReadFile( hSlot, buffer, sizeof buffer, &count, NULL),
|
||||
"2nd slot read failed\n");
|
||||
ok( count == 2, "failed to get 2nd message\n");
|
||||
ok( ( buffer[0] == 'b' ) && ( buffer[1] == 'c' ), "2nd message wrong\n");
|
||||
|
||||
/* check the mailslot info */
|
||||
dwNext = dwMsgCount = 0;
|
||||
ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ),
|
||||
"getmailslotinfo failed\n");
|
||||
todo_wine {
|
||||
ok( dwNext == 0, "dwNext incorrect\n");
|
||||
ok( dwMsgCount == 1, "dwMsgCount incorrect\n");
|
||||
}
|
||||
|
||||
/* read the 3rd (zero length) message */
|
||||
todo_wine {
|
||||
ok( ReadFile( hSlot, buffer, sizeof buffer, &count, NULL),
|
||||
"3rd slot read failed\n");
|
||||
}
|
||||
ok( count == 0, "failed to get 3rd message\n");
|
||||
|
||||
/*
|
||||
* now there should be no more messages
|
||||
* check the mailslot info
|
||||
*/
|
||||
dwNext = dwMsgCount = 0;
|
||||
ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ),
|
||||
"getmailslotinfo failed\n");
|
||||
ok( dwNext == MAILSLOT_NO_MESSAGE, "dwNext incorrect\n");
|
||||
ok( dwMsgCount == 0, "dwMsgCount incorrect\n");
|
||||
|
||||
/* check that reads fail */
|
||||
ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL),
|
||||
"3rd slot read succeeded\n");
|
||||
|
||||
/* finally close the mailslot and its client */
|
||||
ok( CloseHandle( hWriter2 ), "closing 2nd client\n");
|
||||
ok( CloseHandle( hWriter ), "closing the client\n");
|
||||
ok( CloseHandle( hSlot ), "closing the mailslot\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
START_TEST(mailslot)
|
||||
{
|
||||
mailslot_test();
|
||||
}
|
|
@ -1,184 +0,0 @@
|
|||
/*
|
||||
* Unit tests for module/DLL/library API
|
||||
*
|
||||
* Copyright (c) 2004 Eric Pouech
|
||||
*
|
||||
* 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 "wine/test.h"
|
||||
#include <windows.h>
|
||||
|
||||
static BOOL is_unicode_enabled = TRUE;
|
||||
|
||||
static BOOL cmpStrAW(const char* a, const WCHAR* b, DWORD lenA, DWORD lenB)
|
||||
{
|
||||
WCHAR aw[1024];
|
||||
|
||||
DWORD len = MultiByteToWideChar( AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
|
||||
a, lenA, aw, sizeof(aw) / sizeof(aw[0]) );
|
||||
if (len != lenB) return FALSE;
|
||||
return memcmp(aw, b, len * sizeof(WCHAR)) == 0;
|
||||
}
|
||||
|
||||
static void testGetModuleFileName(const char* name)
|
||||
{
|
||||
HMODULE hMod;
|
||||
char bufA[MAX_PATH];
|
||||
WCHAR bufW[MAX_PATH];
|
||||
DWORD len1A, len1W = 0, len2A, len2W = 0;
|
||||
|
||||
hMod = (name) ? GetModuleHandle(name) : NULL;
|
||||
|
||||
/* first test, with enough space in buffer */
|
||||
memset(bufA, '-', sizeof(bufA));
|
||||
len1A = GetModuleFileNameA(hMod, bufA, sizeof(bufA));
|
||||
ok(len1A > 0, "Getting module filename for handle %p\n", hMod);
|
||||
|
||||
if (is_unicode_enabled)
|
||||
{
|
||||
memset(bufW, '-', sizeof(bufW));
|
||||
len1W = GetModuleFileNameW(hMod, bufW, sizeof(bufW) / sizeof(WCHAR));
|
||||
ok(len1W > 0, "Getting module filename for handle %p\n", hMod);
|
||||
}
|
||||
|
||||
ok(len1A == strlen(bufA), "Unexpected length of GetModuleFilenameA (%ld/%d)\n", len1A, strlen(bufA));
|
||||
|
||||
if (is_unicode_enabled)
|
||||
{
|
||||
ok(len1W == lstrlenW(bufW), "Unexpected length of GetModuleFilenameW (%ld/%d)\n", len1W, lstrlenW(bufW));
|
||||
ok(cmpStrAW(bufA, bufW, len1A, len1W), "Comparing GetModuleFilenameAW results\n");
|
||||
}
|
||||
|
||||
/* second test with a buffer too small */
|
||||
memset(bufA, '-', sizeof(bufA));
|
||||
len2A = GetModuleFileNameA(hMod, bufA, len1A / 2);
|
||||
ok(len2A > 0, "Getting module filename for handle %p\n", hMod);
|
||||
|
||||
if (is_unicode_enabled)
|
||||
{
|
||||
memset(bufW, '-', sizeof(bufW));
|
||||
len2W = GetModuleFileNameW(hMod, bufW, len1W / 2);
|
||||
ok(len2W > 0, "Getting module filename for handle %p\n", hMod);
|
||||
ok(cmpStrAW(bufA, bufW, len2A, len2W), "Comparing GetModuleFilenameAW results with buffer too small\n" );
|
||||
ok(len1W / 2 == len2W, "Correct length in GetModuleFilenameW with buffer too small (%ld/%ld)\n", len1W / 2, len2W);
|
||||
}
|
||||
|
||||
ok(len1A / 2 == len2A ||
|
||||
len1A / 2 == len2A + 1, /* Win9x */
|
||||
"Correct length in GetModuleFilenameA with buffer too small (%ld/%ld)\n", len1A / 2, len2A);
|
||||
}
|
||||
|
||||
static void testGetModuleFileName_Wrong(void)
|
||||
{
|
||||
char bufA[MAX_PATH];
|
||||
WCHAR bufW[MAX_PATH];
|
||||
|
||||
/* test wrong handle */
|
||||
if (is_unicode_enabled)
|
||||
{
|
||||
bufW[0] = '*';
|
||||
ok(GetModuleFileNameW((void*)0xffffffff, bufW, sizeof(bufW) / sizeof(WCHAR)) == 0, "Unexpected success in module handle\n");
|
||||
ok(bufW[0] == '*', "When failing, buffer shouldn't be written to\n");
|
||||
}
|
||||
|
||||
bufA[0] = '*';
|
||||
ok(GetModuleFileNameA((void*)0xffffffff, bufA, sizeof(bufA)) == 0, "Unexpected success in module handle\n");
|
||||
ok(bufA[0] == '*' ||
|
||||
bufA[0] == 0 /* Win9x */,
|
||||
"When failing, buffer shouldn't be written to\n");
|
||||
}
|
||||
|
||||
static void testLoadLibraryA(void)
|
||||
{
|
||||
HMODULE hModule, hModule1;
|
||||
FARPROC fp;
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
hModule = LoadLibraryA("kernel32.dll");
|
||||
ok( hModule != NULL, "kernel32.dll should be loadable\n");
|
||||
ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %08lx\n", GetLastError());
|
||||
|
||||
fp = GetProcAddress(hModule, "CreateFileA");
|
||||
ok( fp != NULL, "CreateFileA should be there\n");
|
||||
ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %08lx\n", GetLastError());
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
hModule1 = LoadLibraryA("kernel32 ");
|
||||
/* Only winNT does this */
|
||||
if (GetLastError() != ERROR_DLL_NOT_FOUND)
|
||||
{
|
||||
ok( hModule1 != NULL, "\"kernel32 \" should be loadable\n");
|
||||
ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %08lx\n", GetLastError());
|
||||
ok( hModule == hModule1, "Loaded wrong module\n");
|
||||
FreeLibrary(hModule1);
|
||||
}
|
||||
FreeLibrary(hModule);
|
||||
}
|
||||
|
||||
static void testLoadLibraryA_Wrong(void)
|
||||
{
|
||||
HMODULE hModule;
|
||||
|
||||
/* Try to load a nonexistent dll */
|
||||
SetLastError(0xdeadbeef);
|
||||
hModule = LoadLibraryA("non_ex_pv.dll");
|
||||
ok( !hModule, "non_ex_pv.dll should be not loadable\n");
|
||||
ok( GetLastError() == ERROR_MOD_NOT_FOUND || GetLastError() == ERROR_DLL_NOT_FOUND,
|
||||
"Expected ERROR_MOD_NOT_FOUND or ERROR_DLL_NOT_FOUND (win9x), got %08lx\n", GetLastError());
|
||||
|
||||
/* Just in case */
|
||||
FreeLibrary(hModule);
|
||||
}
|
||||
|
||||
static void testGetProcAddress_Wrong(void)
|
||||
{
|
||||
FARPROC fp;
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
fp = GetProcAddress(NULL, "non_ex_call");
|
||||
ok( !fp, "non_ex_call should not be found\n");
|
||||
ok( GetLastError() == ERROR_PROC_NOT_FOUND || GetLastError() == ERROR_INVALID_HANDLE,
|
||||
"Expected ERROR_PROC_NOT_FOUND or ERROR_INVALID_HANDLE(win9x), got %08lx\n", GetLastError());
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
fp = GetProcAddress((HMODULE)0xdeadbeef, "non_ex_call");
|
||||
ok( !fp, "non_ex_call should not be found\n");
|
||||
ok( GetLastError() == ERROR_MOD_NOT_FOUND || GetLastError() == ERROR_INVALID_HANDLE,
|
||||
"Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_HANDLE(win9x), got %08lx\n", GetLastError());
|
||||
}
|
||||
|
||||
START_TEST(module)
|
||||
{
|
||||
WCHAR filenameW[MAX_PATH];
|
||||
|
||||
/* Test if we can use GetModuleFileNameW */
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
GetModuleFileNameW(NULL, filenameW, MAX_PATH);
|
||||
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
|
||||
{
|
||||
trace("GetModuleFileNameW not existing on this platform, skipping W-calls\n");
|
||||
is_unicode_enabled = FALSE;
|
||||
}
|
||||
|
||||
testGetModuleFileName(NULL);
|
||||
testGetModuleFileName("kernel32.dll");
|
||||
testGetModuleFileName_Wrong();
|
||||
|
||||
testLoadLibraryA();
|
||||
testLoadLibraryA_Wrong();
|
||||
testGetProcAddress_Wrong();
|
||||
}
|
|
@ -1,942 +0,0 @@
|
|||
/*
|
||||
* Unit test suite for Get*PathNamesA and (Get|Set)CurrentDirectoryA.
|
||||
*
|
||||
* Copyright 2002 Geoffrey Hausheer
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
#include "winerror.h"
|
||||
#include "winnls.h"
|
||||
|
||||
#define HAS_TRAIL_SLASH_A(string) (string[lstrlenA(string)-1]=='\\')
|
||||
|
||||
#define LONGFILE "Long File test.path"
|
||||
#define SHORTFILE "pathtest.pth"
|
||||
#define SHORTDIR "shortdir"
|
||||
#define LONGDIR "Long Directory"
|
||||
#define NONFILE_SHORT "noexist.pth"
|
||||
#define NONFILE_LONG "NonExistent File"
|
||||
#define NONDIR_SHORT "notadir"
|
||||
#define NONDIR_LONG "NonExistent Directory"
|
||||
|
||||
#define NOT_A_VALID_DRIVE '@'
|
||||
|
||||
/* the following characters don't work well with GetFullPathNameA
|
||||
in Win98. I don't know if this is a FAT thing, or if it is an OS thing
|
||||
but I don't test these characters now.
|
||||
NOTE: Win2k allows GetFullPathNameA to work with them though
|
||||
|<>"
|
||||
*/
|
||||
static const CHAR funny_chars[]="!@#$%^&*()=+{}[],?'`";
|
||||
static const CHAR is_char_ok[] ="11111110111111111011";
|
||||
|
||||
static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR,LPSTR,DWORD);
|
||||
|
||||
/* a structure to deal with wine todos somewhat cleanly */
|
||||
typedef struct {
|
||||
DWORD shortlen;
|
||||
DWORD shorterror;
|
||||
DWORD s2llen;
|
||||
DWORD s2lerror;
|
||||
DWORD longlen;
|
||||
DWORD longerror;
|
||||
} SLpassfail;
|
||||
|
||||
/* function that tests GetFullPathNameA, GetShortPathNameA,GetLongPathNameA */
|
||||
/* NOTE: the passfail structure is used to allow cutomizeable todo checking
|
||||
for wine. It is not very pretty, but it sure beats duplicating this
|
||||
function lots of times
|
||||
*/
|
||||
static void test_ValidPathA(const CHAR *curdir, const CHAR *subdir, const CHAR *filename,
|
||||
CHAR *shortstr, SLpassfail *passfail, const CHAR *errstr)
|
||||
{
|
||||
CHAR tmpstr[MAX_PATH],
|
||||
fullpath[MAX_PATH], /*full path to the file (not short/long) */
|
||||
subpath[MAX_PATH], /*relative path to the file */
|
||||
fullpathshort[MAX_PATH], /*absolue path to the file (short format) */
|
||||
fullpathlong[MAX_PATH], /*absolute path to the file (long format) */
|
||||
curdirshort[MAX_PATH], /*absolute path to the current dir (short) */
|
||||
curdirlong[MAX_PATH]; /*absolute path to the current dir (long) */
|
||||
LPSTR strptr; /*ptr to the filename portion of the path */
|
||||
DWORD len;
|
||||
/* if passfail is NULL, we can perform all checks within this function,
|
||||
otherwise, we will return the relevant data in the passfail struct, so
|
||||
we must initialize it first
|
||||
*/
|
||||
if(passfail!=NULL) {
|
||||
passfail->shortlen=-1;passfail->s2llen=-1;passfail->longlen=-1;
|
||||
passfail->shorterror=0;passfail->s2lerror=0;passfail->longerror=0;
|
||||
}
|
||||
/* GetLongPathNameA is only supported on Win2k+ and Win98+ */
|
||||
if(pGetLongPathNameA) {
|
||||
ok((len=pGetLongPathNameA(curdir,curdirlong,MAX_PATH)),
|
||||
"%s: GetLongPathNameA failed\n",errstr);
|
||||
/*GetLongPathNameA can return a trailing '\\' but shouldn't do so here */
|
||||
ok(! HAS_TRAIL_SLASH_A(curdirlong),
|
||||
"%s: GetLongPathNameA should not have a trailing \\\n",errstr);
|
||||
}
|
||||
ok((len=GetShortPathNameA(curdir,curdirshort,MAX_PATH)),
|
||||
"%s: GetShortPathNameA failed\n",errstr);
|
||||
/*GetShortPathNameA can return a trailing '\\' but shouldn't do so here */
|
||||
ok(! HAS_TRAIL_SLASH_A(curdirshort),
|
||||
"%s: GetShortPathNameA should not have a trailing \\\n",errstr);
|
||||
/* build relative and absolute paths from inputs */
|
||||
if(lstrlenA(subdir)) {
|
||||
sprintf(subpath,"%s\\%s",subdir,filename);
|
||||
} else {
|
||||
lstrcpyA(subpath,filename);
|
||||
}
|
||||
sprintf(fullpath,"%s\\%s",curdir,subpath);
|
||||
sprintf(fullpathshort,"%s\\%s",curdirshort,subpath);
|
||||
sprintf(fullpathlong,"%s\\%s",curdirlong,subpath);
|
||||
/* Test GetFullPathNameA functionality */
|
||||
len=GetFullPathNameA(subpath,MAX_PATH,tmpstr,&strptr);
|
||||
ok(len, "GetFullPathNameA failed for: '%s'\n",subpath);
|
||||
if(HAS_TRAIL_SLASH_A(subpath)) {
|
||||
ok(strptr==NULL,
|
||||
"%s: GetFullPathNameA should not return a filename ptr\n",errstr);
|
||||
ok(lstrcmpiA(fullpath,tmpstr)==0,
|
||||
"%s: GetFullPathNameA returned '%s' instead of '%s'\n",
|
||||
errstr,tmpstr,fullpath);
|
||||
} else {
|
||||
ok(lstrcmpiA(strptr,filename)==0,
|
||||
"%s: GetFullPathNameA returned '%s' instead of '%s'\n",
|
||||
errstr,strptr,filename);
|
||||
ok(lstrcmpiA(fullpath,tmpstr)==0,
|
||||
"%s: GetFullPathNameA returned '%s' instead of '%s'\n",
|
||||
errstr,tmpstr,fullpath);
|
||||
}
|
||||
/* Test GetShortPathNameA functionality */
|
||||
SetLastError(0);
|
||||
len=GetShortPathNameA(fullpathshort,shortstr,MAX_PATH);
|
||||
if(passfail==NULL) {
|
||||
ok(len, "%s: GetShortPathNameA failed\n",errstr);
|
||||
} else {
|
||||
passfail->shortlen=len;
|
||||
passfail->shorterror=GetLastError();
|
||||
}
|
||||
/* Test GetLongPathNameA functionality
|
||||
We test both conversion from GetFullPathNameA and from GetShortPathNameA
|
||||
*/
|
||||
if(pGetLongPathNameA) {
|
||||
if(len!=0) {
|
||||
SetLastError(0);
|
||||
len=pGetLongPathNameA(shortstr,tmpstr,MAX_PATH);
|
||||
if(passfail==NULL) {
|
||||
ok(len,
|
||||
"%s: GetLongPathNameA failed during Short->Long conversion\n", errstr);
|
||||
ok(lstrcmpiA(fullpathlong,tmpstr)==0,
|
||||
"%s: GetLongPathNameA returned '%s' instead of '%s'\n",
|
||||
errstr,tmpstr,fullpathlong);
|
||||
} else {
|
||||
passfail->s2llen=len;
|
||||
passfail->s2lerror=GetLastError();
|
||||
}
|
||||
}
|
||||
SetLastError(0);
|
||||
len=pGetLongPathNameA(fullpath,tmpstr,MAX_PATH);
|
||||
if(passfail==NULL) {
|
||||
ok(len, "%s: GetLongPathNameA failed\n",errstr);
|
||||
if(HAS_TRAIL_SLASH_A(fullpath)) {
|
||||
ok(lstrcmpiA(fullpathlong,tmpstr)==0,
|
||||
"%s: GetLongPathNameA returned '%s' instead of '%s'\n",
|
||||
errstr,tmpstr,fullpathlong);
|
||||
} else {
|
||||
ok(lstrcmpiA(fullpathlong,tmpstr)==0,
|
||||
"%s: GetLongPathNameA returned '%s' instead of '%s'\n",
|
||||
errstr,tmpstr,fullpathlong);
|
||||
}
|
||||
} else {
|
||||
passfail->longlen=len;
|
||||
passfail->longerror=GetLastError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* split path into leading directory, and 8.3 filename */
|
||||
static void test_SplitShortPathA(CHAR *path,CHAR *dir,CHAR *eight,CHAR *three) {
|
||||
int done,error;
|
||||
int ext,fil;
|
||||
int len,i;
|
||||
len=lstrlenA(path);
|
||||
ext=len; fil=len; done=0; error=0;
|
||||
/* walk backwards over path looking for '.' or '\\' separators */
|
||||
for(i=len-1;(i>=0) && (!done);i--) {
|
||||
if(path[i]=='.')
|
||||
if(ext!=len) error=1; else ext=i;
|
||||
else if(path[i]=='\\') {
|
||||
if(i==len-1) {
|
||||
error=1;
|
||||
} else {
|
||||
fil=i;
|
||||
done=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Check that we didn't find a trailing '\\' or multiple '.' */
|
||||
ok(!error,"Illegal file found in 8.3 path '%s'\n",path);
|
||||
/* Separate dir, root, and extension */
|
||||
if(ext!=len) lstrcpyA(three,path+ext+1); else lstrcpyA(three,"");
|
||||
if(fil!=len) {
|
||||
lstrcpynA(eight,path+fil+1,ext-fil);
|
||||
lstrcpynA(dir,path,fil+1);
|
||||
} else {
|
||||
lstrcpynA(eight,path,ext+1);
|
||||
lstrcpyA(dir,"");
|
||||
}
|
||||
/* Validate that root and extension really are 8.3 */
|
||||
ok(lstrlenA(eight)<=8 && lstrlenA(three)<=3,
|
||||
"GetShortPathNAmeA did not return an 8.3 path\n");
|
||||
}
|
||||
|
||||
/* Check that GetShortPathNameA returns a valid 8.3 path */
|
||||
static void test_LongtoShortA(CHAR *teststr,const CHAR *goodstr,
|
||||
const CHAR *ext,const CHAR *errstr) {
|
||||
CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
|
||||
|
||||
test_SplitShortPathA(teststr,dir,eight,three);
|
||||
ok(lstrcmpiA(dir,goodstr)==0,
|
||||
"GetShortPathNameA returned '%s' instead of '%s'\n",dir,goodstr);
|
||||
ok(lstrcmpiA(three,ext)==0,
|
||||
"GetShortPathNameA returned '%s' with incorrect extension\n",three);
|
||||
}
|
||||
|
||||
/* Test that Get(Short|Long|Full)PathNameA work correctly with interesting
|
||||
characters in the filename.
|
||||
'valid' indicates whether this would be an allowed filename
|
||||
'todo' indicates that wine doesn't get this right yet.
|
||||
NOTE: We always call this routine with a nonexistent filename, so
|
||||
Get(Short|Long)PathNameA should never pass, but GetFullPathNameA
|
||||
should.
|
||||
*/
|
||||
static void test_FunnyChars(CHAR *curdir,CHAR *curdir_short,CHAR *filename, INT valid,CHAR *errstr)
|
||||
{
|
||||
CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH];
|
||||
SLpassfail passfail;
|
||||
|
||||
test_ValidPathA(curdir,"",filename,tmpstr,&passfail,errstr);
|
||||
if(valid) {
|
||||
sprintf(tmpstr1,"%s\\%s",curdir_short,filename);
|
||||
ok((passfail.shortlen==0 &&
|
||||
(passfail.shorterror==ERROR_FILE_NOT_FOUND || passfail.shorterror==ERROR_PATH_NOT_FOUND || !passfail.shorterror)) ||
|
||||
(passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
|
||||
"%s: GetShortPathNameA error: len=%ld error=%ld tmpstr=[%s]\n",
|
||||
errstr,passfail.shortlen,passfail.shorterror,tmpstr);
|
||||
} else {
|
||||
ok(passfail.shortlen==0 &&
|
||||
(passfail.shorterror==ERROR_INVALID_NAME || passfail.shorterror==ERROR_FILE_NOT_FOUND || !passfail.shorterror),
|
||||
"%s: GetShortPathA should have failed len=%ld, error=%ld\n",
|
||||
errstr,passfail.shortlen,passfail.shorterror);
|
||||
}
|
||||
if(pGetLongPathNameA) {
|
||||
ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
|
||||
if(valid) {
|
||||
ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"%s: GetLongPathA returned %ld and not %d\n",
|
||||
errstr,passfail.longerror,ERROR_FILE_NOT_FOUND);
|
||||
} else {
|
||||
ok(passfail.longerror==ERROR_INVALID_NAME ||
|
||||
passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"%s: GetLongPathA returned %ld and not %d or %d'\n",
|
||||
errstr, passfail.longerror,ERROR_INVALID_NAME,ERROR_FILE_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Routine to test that SetCurrentDirectory behaves as expected. */
|
||||
static void test_setdir(CHAR *olddir,CHAR *newdir,
|
||||
CHAR *cmprstr, INT pass, const CHAR *errstr)
|
||||
{
|
||||
CHAR tmppath[MAX_PATH], *dirptr;
|
||||
DWORD val,len,chklen;
|
||||
|
||||
val=SetCurrentDirectoryA(newdir);
|
||||
len=GetCurrentDirectoryA(MAX_PATH,tmppath);
|
||||
/* if 'pass' then the SetDirectoryA was supposed to pass */
|
||||
if(pass) {
|
||||
dirptr=(cmprstr==NULL) ? newdir : cmprstr;
|
||||
chklen=lstrlenA(dirptr);
|
||||
ok(val,"%s: SetCurrentDirectoryA failed\n",errstr);
|
||||
ok(len==chklen,
|
||||
"%s: SetCurrentDirectory did not change the directory, though it passed\n",
|
||||
errstr);
|
||||
ok(lstrcmpiA(dirptr,tmppath)==0,
|
||||
"%s: SetCurrentDirectory did not change the directory, though it passed\n",
|
||||
errstr);
|
||||
ok(SetCurrentDirectoryA(olddir),
|
||||
"%s: Couldn't set directory to it's original value\n",errstr);
|
||||
} else {
|
||||
/* else thest that it fails correctly */
|
||||
chklen=lstrlenA(olddir);
|
||||
ok(val==0,
|
||||
"%s: SetCurrentDirectoryA passed when it should have failed\n",errstr);
|
||||
ok(len==chklen,
|
||||
"%s: SetCurrentDirectory changed the directory, though it failed\n",
|
||||
errstr);
|
||||
ok(lstrcmpiA(olddir,tmppath)==0,
|
||||
"%s: SetCurrentDirectory changed the directory, though it failed\n",
|
||||
errstr);
|
||||
}
|
||||
}
|
||||
static void test_InitPathA(CHAR *newdir, CHAR *curDrive, CHAR *otherDrive)
|
||||
{
|
||||
CHAR tmppath[MAX_PATH], /*path to TEMP */
|
||||
tmpstr[MAX_PATH],
|
||||
tmpstr1[MAX_PATH];
|
||||
DWORD len,len1,drives;
|
||||
INT id;
|
||||
HANDLE hndl;
|
||||
BOOL bRes;
|
||||
|
||||
*curDrive = *otherDrive = NOT_A_VALID_DRIVE;
|
||||
|
||||
/* Get the current drive letter */
|
||||
if( GetCurrentDirectoryA( MAX_PATH, tmpstr))
|
||||
*curDrive = tmpstr[0];
|
||||
else
|
||||
trace( "Unable to discover current drive, some tests will not be conducted.\n");
|
||||
|
||||
/* Test GetTempPathA */
|
||||
len=GetTempPathA(MAX_PATH,tmppath);
|
||||
ok(len!=0 && len < MAX_PATH,"GetTempPathA failed\n");
|
||||
ok(HAS_TRAIL_SLASH_A(tmppath),
|
||||
"GetTempPathA returned a path that did not end in '\\'\n");
|
||||
lstrcpyA(tmpstr,"aaaaaaaa");
|
||||
len1=GetTempPathA(len,tmpstr);
|
||||
ok(len1==len+1,
|
||||
"GetTempPathA should return string length %ld instead of %ld\n",len+1,len1);
|
||||
|
||||
/* Test GetTmpFileNameA
|
||||
The only test we do here is whether GetTempFileNameA passes or not.
|
||||
We do not thoroughly test this function yet (specifically, whether
|
||||
it behaves correctly when 'unique' is non zero)
|
||||
*/
|
||||
ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed\n");
|
||||
sprintf(tmpstr,"pat%.4x.tmp",id & 0xffff);
|
||||
sprintf(tmpstr1,"pat%x.tmp",id & 0xffff);
|
||||
ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
|
||||
lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
|
||||
"GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
|
||||
newdir,tmpstr,tmpstr1,id);
|
||||
ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
|
||||
|
||||
id=GetTempFileNameA(tmppath,NULL,0,newdir);
|
||||
/* Windows 95, 98 return 0==id, while Windows 2000, XP return 0!=id */
|
||||
if (id)
|
||||
{
|
||||
sprintf(tmpstr,"%.4x.tmp",id & 0xffff);
|
||||
sprintf(tmpstr1,"%x.tmp",id & 0xffff);
|
||||
ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
|
||||
lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
|
||||
"GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
|
||||
newdir,tmpstr,tmpstr1,id);
|
||||
ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
|
||||
}
|
||||
|
||||
/* Find first valid drive letter that is neither newdir[0] nor curDrive */
|
||||
drives = GetLogicalDrives() & ~(1<<(newdir[0]-'A'));
|
||||
if( *curDrive != NOT_A_VALID_DRIVE)
|
||||
drives &= ~(1<<(*curDrive-'A'));
|
||||
if( drives)
|
||||
for( *otherDrive='A'; (drives & 1) == 0; drives>>=1, (*otherDrive)++);
|
||||
else
|
||||
trace( "Could not find alternative drive, some tests will not be conducted.\n");
|
||||
|
||||
/* Do some CreateDirectoryA tests */
|
||||
/* It would be nice to do test the SECURITY_ATTRIBUTES, but I don't
|
||||
really understand how they work.
|
||||
More formal tests should be done along with CreateFile tests
|
||||
*/
|
||||
ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed\n");
|
||||
ok(CreateDirectoryA(newdir,NULL)==0,
|
||||
"CreateDirectoryA succeeded even though a file of the same name exists\n");
|
||||
ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
|
||||
ok(CreateDirectoryA(newdir,NULL),"CreateDirectoryA failed\n");
|
||||
/* Create some files to test other functions. Note, we will test CreateFileA
|
||||
at some later point
|
||||
*/
|
||||
sprintf(tmpstr,"%s\\%s",newdir,SHORTDIR);
|
||||
ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
|
||||
sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
|
||||
ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
|
||||
bRes = CreateDirectoryA("c:",NULL);
|
||||
ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED ||
|
||||
GetLastError() == ERROR_ALREADY_EXISTS),
|
||||
"CreateDirectoryA(\"c:\" should have failed (%ld)\n", GetLastError());
|
||||
bRes = CreateDirectoryA("c:\\",NULL);
|
||||
ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED ||
|
||||
GetLastError() == ERROR_ALREADY_EXISTS),
|
||||
"CreateDirectoryA(\"c:\\\" should have failed (%ld)\n", GetLastError());
|
||||
sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,SHORTFILE);
|
||||
hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
|
||||
CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
|
||||
ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
|
||||
ok(CloseHandle(hndl),"CloseHandle failed\n");
|
||||
sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,LONGFILE);
|
||||
hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
|
||||
CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
|
||||
ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
|
||||
ok(CloseHandle(hndl),"CloseHandle failed\n");
|
||||
sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,SHORTFILE);
|
||||
hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
|
||||
CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
|
||||
ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
|
||||
ok(CloseHandle(hndl),"CloseHandle failed\n");
|
||||
sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,LONGFILE);
|
||||
hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
|
||||
CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
|
||||
ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
|
||||
ok(CloseHandle(hndl),"CloseHandle failed\n");
|
||||
}
|
||||
|
||||
/* Test GetCurrentDirectory & SetCurrentDirectory */
|
||||
static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir)
|
||||
{
|
||||
CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH];
|
||||
DWORD len,len1;
|
||||
/* Save the original directory, so that we can return to it at the end
|
||||
of the test
|
||||
*/
|
||||
len=GetCurrentDirectoryA(MAX_PATH,origdir);
|
||||
ok(len!=0 && len < MAX_PATH,"GetCurrentDirectoryA failed\n");
|
||||
/* Make sure that CetCurrentDirectoryA doesn't overwrite the buffer when the
|
||||
buffer size is too small to hold the current directory
|
||||
*/
|
||||
lstrcpyA(tmpstr,"aaaaaaa");
|
||||
len1=GetCurrentDirectoryA(len,tmpstr);
|
||||
ok(len1==len+1, "GetCurrentDirectoryA returned %ld instead of %ld\n",len1,len+1);
|
||||
ok(lstrcmpiA(tmpstr,"aaaaaaa")==0,
|
||||
"GetCurrentDirectoryA should not have modified the buffer\n");
|
||||
/* SetCurrentDirectoryA shouldn't care whether the string has a
|
||||
trailing '\\' or not
|
||||
*/
|
||||
sprintf(tmpstr,"%s\\",newdir);
|
||||
test_setdir(origdir,tmpstr,newdir,1,"check 1");
|
||||
test_setdir(origdir,newdir,NULL,1,"check 2");
|
||||
/* Set the directory to the working area. We just tested that this works,
|
||||
so why check it again.
|
||||
*/
|
||||
SetCurrentDirectoryA(newdir);
|
||||
/* Check that SetCurrentDirectory fails when a nonexistent dir is specified */
|
||||
sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_SHORT);
|
||||
test_setdir(newdir,tmpstr,NULL,0,"check 3");
|
||||
/* Check that SetCurrentDirectory fails for a nonexistent lond directory */
|
||||
sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_LONG);
|
||||
test_setdir(newdir,tmpstr,NULL,0,"check 4");
|
||||
/* Check that SetCurrentDirectory passes with a long directory */
|
||||
sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
|
||||
test_setdir(newdir,tmpstr,NULL,1,"check 5");
|
||||
/* Check that SetCurrentDirectory passes with a short relative directory */
|
||||
sprintf(tmpstr,"%s",SHORTDIR);
|
||||
sprintf(tmpstr1,"%s\\%s",newdir,SHORTDIR);
|
||||
test_setdir(newdir,tmpstr,tmpstr1,1,"check 6");
|
||||
/* starting with a '.' */
|
||||
sprintf(tmpstr,".\\%s",SHORTDIR);
|
||||
test_setdir(newdir,tmpstr,tmpstr1,1,"check 7");
|
||||
/* Check that SetCurrentDirectory passes with a short relative directory */
|
||||
sprintf(tmpstr,"%s",LONGDIR);
|
||||
sprintf(tmpstr1,"%s\\%s",newdir,LONGDIR);
|
||||
test_setdir(newdir,tmpstr,tmpstr1,1,"check 8");
|
||||
/* starting with a '.' */
|
||||
sprintf(tmpstr,".\\%s",LONGDIR);
|
||||
test_setdir(newdir,tmpstr,tmpstr1,1,"check 9");
|
||||
}
|
||||
|
||||
/* Cleanup the mess we made while executing these tests */
|
||||
static void test_CleanupPathA(CHAR *origdir, CHAR *curdir)
|
||||
{
|
||||
CHAR tmpstr[MAX_PATH];
|
||||
sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
|
||||
ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
|
||||
sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,LONGFILE);
|
||||
ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
|
||||
sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,SHORTFILE);
|
||||
ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
|
||||
sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
|
||||
ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
|
||||
sprintf(tmpstr,"%s\\%s",curdir,SHORTDIR);
|
||||
ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
|
||||
sprintf(tmpstr,"%s\\%s",curdir,LONGDIR);
|
||||
ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
|
||||
ok(SetCurrentDirectoryA(origdir),"SetCurrentDirectoryA failed\n");
|
||||
ok(RemoveDirectoryA(curdir),"RemoveDirectoryA failed\n");
|
||||
}
|
||||
|
||||
/* This routine will test Get(Full|Short|Long)PathNameA */
|
||||
static void test_PathNameA(CHAR *curdir, CHAR curDrive, CHAR otherDrive)
|
||||
{
|
||||
CHAR curdir_short[MAX_PATH],
|
||||
longdir_short[MAX_PATH];
|
||||
CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH],tmpstr2[MAX_PATH];
|
||||
LPSTR strptr; /*ptr to the filename portion of the path */
|
||||
DWORD len;
|
||||
INT i;
|
||||
CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
|
||||
SLpassfail passfail;
|
||||
|
||||
/* Get the short form of the current directory */
|
||||
ok((len=GetShortPathNameA(curdir,curdir_short,MAX_PATH)),
|
||||
"GetShortPathNameA failed\n");
|
||||
ok(!HAS_TRAIL_SLASH_A(curdir_short),
|
||||
"GetShortPathNameA should not have a trailing \\\n");
|
||||
/* Get the short form of the absolute-path to LONGDIR */
|
||||
sprintf(tmpstr,"%s\\%s",curdir_short,LONGDIR);
|
||||
ok((len=GetShortPathNameA(tmpstr,longdir_short,MAX_PATH)),
|
||||
"GetShortPathNameA failed\n");
|
||||
ok(lstrcmpiA(longdir_short+(len-1),"\\")!=0,
|
||||
"GetShortPathNameA should not have a trailing \\\n");
|
||||
|
||||
if (pGetLongPathNameA) {
|
||||
DWORD rc1,rc2;
|
||||
sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
|
||||
rc1=(*pGetLongPathNameA)(tmpstr,NULL,0);
|
||||
rc2=(*pGetLongPathNameA)(curdir,NULL,0);
|
||||
ok((rc1-strlen(tmpstr))==(rc2-strlen(curdir)),
|
||||
"GetLongPathNameA: wrong return code, %ld instead of %d\n",
|
||||
rc1, strlen(tmpstr)+1);
|
||||
|
||||
sprintf(dir,"%c:",curDrive);
|
||||
rc1=(*pGetLongPathNameA)(dir,tmpstr,sizeof(tmpstr));
|
||||
ok(strcmp(dir,tmpstr)==0,
|
||||
"GetLongPathNameA: returned '%s' instead of '%s' (rc=%ld)\n",
|
||||
tmpstr,dir,rc1);
|
||||
}
|
||||
|
||||
/* Check the cases where both file and directory exist first */
|
||||
/* Start with a 8.3 directory, 8.3 filename */
|
||||
test_ValidPathA(curdir,SHORTDIR,SHORTFILE,tmpstr,NULL,"test1");
|
||||
sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,SHORTFILE);
|
||||
ok(lstrcmpiA(tmpstr,tmpstr1)==0,
|
||||
"GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
|
||||
/* Now try a 8.3 directory, long file name */
|
||||
test_ValidPathA(curdir,SHORTDIR,LONGFILE,tmpstr,NULL,"test2");
|
||||
sprintf(tmpstr1,"%s\\%s",curdir_short,SHORTDIR);
|
||||
test_LongtoShortA(tmpstr,tmpstr1,"PAT","test2");
|
||||
/* Next is a long directory, 8.3 file */
|
||||
test_ValidPathA(curdir,LONGDIR,SHORTFILE,tmpstr,NULL,"test3");
|
||||
sprintf(tmpstr1,"%s\\%s",longdir_short,SHORTFILE);
|
||||
ok(lstrcmpiA(tmpstr,tmpstr1)==0,
|
||||
"GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
|
||||
/*Lastly a long directory, long file */
|
||||
test_ValidPathA(curdir,LONGDIR,LONGFILE,tmpstr,NULL,"test4");
|
||||
test_LongtoShortA(tmpstr,longdir_short,"PAT","test4");
|
||||
|
||||
/* Now check all of the invalid file w/ valid directory combinations */
|
||||
/* Start with a 8.3 directory, 8.3 filename */
|
||||
test_ValidPathA(curdir,SHORTDIR,NONFILE_SHORT,tmpstr,&passfail,"test5");
|
||||
sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,NONFILE_SHORT);
|
||||
ok((passfail.shortlen==0 &&
|
||||
(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
|
||||
(passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
|
||||
"GetShortPathNameA error: len=%ld error=%ld tmpstr=[%s]\n",
|
||||
passfail.shortlen,passfail.shorterror,tmpstr);
|
||||
if(pGetLongPathNameA) {
|
||||
ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
|
||||
}
|
||||
/* Now try a 8.3 directory, long file name */
|
||||
test_ValidPathA(curdir,SHORTDIR,NONFILE_LONG,tmpstr,&passfail,"test6");
|
||||
ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.shorterror==ERROR_FILE_NOT_FOUND ||
|
||||
!passfail.shorterror,
|
||||
"GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
|
||||
if(pGetLongPathNameA) {
|
||||
ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
|
||||
}
|
||||
/* Next is a long directory, 8.3 file */
|
||||
test_ValidPathA(curdir,LONGDIR,NONFILE_SHORT,tmpstr,&passfail,"test7");
|
||||
sprintf(tmpstr2,"%s\\%s",curdir_short,LONGDIR);
|
||||
GetShortPathNameA(tmpstr2,tmpstr1,MAX_PATH);
|
||||
strcat(tmpstr1,"\\" NONFILE_SHORT);
|
||||
ok((passfail.shortlen==0 &&
|
||||
(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
|
||||
(passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
|
||||
"GetShortPathNameA error: len=%ld error=%ld tmpstr=[%s]\n",
|
||||
passfail.shortlen,passfail.shorterror,tmpstr);
|
||||
if(pGetLongPathNameA) {
|
||||
ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
|
||||
}
|
||||
/*Lastly a long directory, long file */
|
||||
test_ValidPathA(curdir,LONGDIR,NONFILE_LONG,tmpstr,&passfail,"test8");
|
||||
ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.shorterror==ERROR_FILE_NOT_FOUND ||
|
||||
!passfail.shorterror,
|
||||
"GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
|
||||
if(pGetLongPathNameA) {
|
||||
ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
|
||||
}
|
||||
/* Now try again with directories that don't exist */
|
||||
/* 8.3 directory, 8.3 filename */
|
||||
test_ValidPathA(curdir,NONDIR_SHORT,SHORTFILE,tmpstr,&passfail,"test9");
|
||||
sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,NONDIR_SHORT,SHORTFILE);
|
||||
ok((passfail.shortlen==0 &&
|
||||
(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
|
||||
(passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
|
||||
"GetShortPathNameA error: len=%ld error=%ld tmpstr=[%s]\n",
|
||||
passfail.shortlen,passfail.shorterror,tmpstr);
|
||||
if(pGetLongPathNameA) {
|
||||
ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"GetLongPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'\n",
|
||||
passfail.longerror);
|
||||
}
|
||||
/* Now try a 8.3 directory, long file name */
|
||||
test_ValidPathA(curdir,NONDIR_SHORT,LONGFILE,tmpstr,&passfail,"test10");
|
||||
ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.shorterror==ERROR_FILE_NOT_FOUND ||
|
||||
!passfail.shorterror,
|
||||
"GetShortPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'\n",
|
||||
passfail.shorterror);
|
||||
if(pGetLongPathNameA) {
|
||||
ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"GetLongPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'\n",
|
||||
passfail.longerror);
|
||||
}
|
||||
/* Next is a long directory, 8.3 file */
|
||||
test_ValidPathA(curdir,NONDIR_LONG,SHORTFILE,tmpstr,&passfail,"test11");
|
||||
ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.shorterror==ERROR_FILE_NOT_FOUND ||
|
||||
!passfail.shorterror,
|
||||
"GetShortPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'\n",
|
||||
passfail.shorterror);
|
||||
if(pGetLongPathNameA) {
|
||||
ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"GetLongPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'\n",
|
||||
passfail.longerror);
|
||||
}
|
||||
/*Lastly a long directory, long file */
|
||||
test_ValidPathA(curdir,NONDIR_LONG,LONGFILE,tmpstr,&passfail,"test12");
|
||||
ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.shorterror==ERROR_FILE_NOT_FOUND ||
|
||||
!passfail.shorterror,
|
||||
"GetShortPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'\n",
|
||||
passfail.shorterror);
|
||||
if(pGetLongPathNameA) {
|
||||
ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"GetLongPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'\n",
|
||||
passfail.longerror);
|
||||
}
|
||||
/* Next try directories ending with '\\' */
|
||||
/* Existing Directories */
|
||||
sprintf(tmpstr,"%s\\",SHORTDIR);
|
||||
test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test13");
|
||||
sprintf(tmpstr,"%s\\",LONGDIR);
|
||||
test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test14");
|
||||
/* Nonexistent directories */
|
||||
sprintf(tmpstr,"%s\\",NONDIR_SHORT);
|
||||
test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test15");
|
||||
sprintf(tmpstr2,"%s\\%s",curdir_short,tmpstr);
|
||||
ok((passfail.shortlen==0 &&
|
||||
(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
|
||||
(passfail.shortlen==strlen(tmpstr2) && lstrcmpiA(tmpstr1,tmpstr2)==0),
|
||||
"GetShortPathNameA error: len=%ld error=%ld tmpstr=[%s]\n",
|
||||
passfail.shortlen,passfail.shorterror,tmpstr);
|
||||
if(pGetLongPathNameA) {
|
||||
ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"GetLongPathA returned %ld and not 'ERROR_FILE_NOT_FOUND'\n",
|
||||
passfail.longerror);
|
||||
}
|
||||
sprintf(tmpstr,"%s\\",NONDIR_LONG);
|
||||
test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test16");
|
||||
ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
|
||||
passfail.shorterror==ERROR_FILE_NOT_FOUND ||
|
||||
!passfail.shorterror,
|
||||
"GetShortPathA returned %ld and not 'ERROR_FILE_NOT_FOUND'\n",
|
||||
passfail.shorterror);
|
||||
if(pGetLongPathNameA) {
|
||||
ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
|
||||
ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
|
||||
"GetLongPathA returned %ld and not 'ERROR_FILE_NOT_FOUND'\n",
|
||||
passfail.longerror);
|
||||
}
|
||||
/* Test GetFullPathNameA with drive letters */
|
||||
if( curDrive != NOT_A_VALID_DRIVE) {
|
||||
sprintf(tmpstr,"%c:",curdir[0]);
|
||||
ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr2,&strptr),
|
||||
"GetFullPathNameA(%c:) failed\n", curdir[0]);
|
||||
GetCurrentDirectoryA(MAX_PATH,tmpstr);
|
||||
sprintf(tmpstr1,"%s\\",tmpstr);
|
||||
ok(lstrcmpiA(tmpstr,tmpstr2)==0 || lstrcmpiA(tmpstr1,tmpstr2)==0,
|
||||
"GetFullPathNameA(%c:) returned '%s' instead of '%s' or '%s'\n",
|
||||
curdir[0],tmpstr2,tmpstr,tmpstr1);
|
||||
|
||||
sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
|
||||
ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
|
||||
ok(lstrcmpiA(tmpstr,tmpstr1)==0,
|
||||
"GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
|
||||
ok(lstrcmpiA(SHORTFILE,strptr)==0,
|
||||
"GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
|
||||
}
|
||||
/* Without a leading slash, insert the current directory if on the current drive */
|
||||
sprintf(tmpstr,"%c:%s\\%s",curdir[0],SHORTDIR,SHORTFILE);
|
||||
ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
|
||||
sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
|
||||
ok(lstrcmpiA(tmpstr,tmpstr1)==0,
|
||||
"GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
|
||||
ok(lstrcmpiA(SHORTFILE,strptr)==0,
|
||||
"GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
|
||||
/* Otherwise insert the missing leading slash */
|
||||
if( otherDrive != NOT_A_VALID_DRIVE) {
|
||||
sprintf(tmpstr,"%c:%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
|
||||
ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed for %s\n", tmpstr);
|
||||
sprintf(tmpstr,"%c:\\%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
|
||||
ok(lstrcmpiA(tmpstr,tmpstr1)==0,
|
||||
"GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
|
||||
ok(lstrcmpiA(SHORTFILE,strptr)==0,
|
||||
"GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
|
||||
}
|
||||
/* Xilinx tools like to mix Unix and DOS formats, which Windows handles fine.
|
||||
So test for them. */
|
||||
if( curDrive != NOT_A_VALID_DRIVE) {
|
||||
sprintf(tmpstr,"%c:/%s\\%s",curDrive,SHORTDIR,SHORTFILE);
|
||||
ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
|
||||
sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
|
||||
ok(lstrcmpiA(tmpstr,tmpstr1)==0,
|
||||
"GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
|
||||
ok(lstrcmpiA(SHORTFILE,strptr)==0,
|
||||
"GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
|
||||
}
|
||||
/**/
|
||||
sprintf(tmpstr,"%c:%s/%s",curdir[0],SHORTDIR,SHORTFILE);
|
||||
ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
|
||||
sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
|
||||
ok(lstrcmpiA(tmpstr,tmpstr1)==0,
|
||||
"GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
|
||||
ok(lstrcmpiA(SHORTFILE,strptr)==0,
|
||||
"GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
|
||||
/* Windows will insert a drive letter in front of an absolute UNIX path */
|
||||
sprintf(tmpstr,"/%s/%s",SHORTDIR,SHORTFILE);
|
||||
ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
|
||||
sprintf(tmpstr,"%c:\\%s\\%s",*tmpstr1,SHORTDIR,SHORTFILE);
|
||||
ok(lstrcmpiA(tmpstr,tmpstr1)==0,
|
||||
"GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
|
||||
/* This passes in Wine because it still contains the pointer from the previous test */
|
||||
ok(lstrcmpiA(SHORTFILE,strptr)==0,
|
||||
"GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
|
||||
|
||||
/* Now try some relative paths */
|
||||
ok(GetShortPathNameA(LONGDIR,tmpstr,MAX_PATH),"GetShortPathNameA failed\n");
|
||||
test_SplitShortPathA(tmpstr,dir,eight,three);
|
||||
if(pGetLongPathNameA) {
|
||||
ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
|
||||
ok(lstrcmpiA(tmpstr1,LONGDIR)==0,
|
||||
"GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,LONGDIR);
|
||||
}
|
||||
sprintf(tmpstr,".\\%s",LONGDIR);
|
||||
ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed\n");
|
||||
test_SplitShortPathA(tmpstr1,dir,eight,three);
|
||||
ok(lstrcmpiA(dir,".")==0 || dir[0]=='\0',
|
||||
"GetShortPathNameA did not keep relative directory [%s]\n",tmpstr1);
|
||||
if(pGetLongPathNameA) {
|
||||
ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetLongPathNameA failed %s\n",
|
||||
tmpstr);
|
||||
ok(lstrcmpiA(tmpstr1,tmpstr)==0,
|
||||
"GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
|
||||
}
|
||||
/* Check out Get*PathNameA on some funny characters */
|
||||
for(i=0;i<lstrlenA(funny_chars);i++) {
|
||||
INT valid;
|
||||
valid=(is_char_ok[i]=='0') ? 0 : 1;
|
||||
sprintf(tmpstr1,"check%d-1",i);
|
||||
sprintf(tmpstr,"file%c000.ext",funny_chars[i]);
|
||||
test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
|
||||
sprintf(tmpstr1,"check%d-2",i);
|
||||
sprintf(tmpstr,"file000.e%ct",funny_chars[i]);
|
||||
test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
|
||||
sprintf(tmpstr1,"check%d-3",i);
|
||||
sprintf(tmpstr,"%cfile000.ext",funny_chars[i]);
|
||||
test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
|
||||
sprintf(tmpstr1,"check%d-4",i);
|
||||
sprintf(tmpstr,"file000%c.ext",funny_chars[i]);
|
||||
test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
|
||||
sprintf(tmpstr1,"check%d-5",i);
|
||||
sprintf(tmpstr,"Long %c File",funny_chars[i]);
|
||||
test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
|
||||
sprintf(tmpstr1,"check%d-6",i);
|
||||
sprintf(tmpstr,"%c Long File",funny_chars[i]);
|
||||
test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
|
||||
sprintf(tmpstr1,"check%d-7",i);
|
||||
sprintf(tmpstr,"Long File %c",funny_chars[i]);
|
||||
test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_GetTempPathA(char* tmp_dir)
|
||||
{
|
||||
DWORD len, len_with_null;
|
||||
char buf[MAX_PATH];
|
||||
|
||||
len_with_null = strlen(tmp_dir) + 1;
|
||||
|
||||
lstrcpyA(buf, "foo");
|
||||
len = GetTempPathA(MAX_PATH, buf);
|
||||
ok(len <= MAX_PATH, "should fit into MAX_PATH\n");
|
||||
ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
|
||||
ok(len == strlen(buf), "returned length should be equal to the length of string\n");
|
||||
|
||||
/* Some versions of Windows touch the buffer, some don't so we don't
|
||||
* test that. Also, NT sometimes exagerates the required buffer size
|
||||
* so we cannot test for an exact match. Finally, the
|
||||
* 'len_with_null - 1' case is so buggy on Windows it's not testable.
|
||||
* For instance in some cases Win98 returns len_with_null - 1 instead
|
||||
* of len_with_null.
|
||||
*/
|
||||
len = GetTempPathA(1, buf);
|
||||
ok(len >= len_with_null, "Expected >= %lu, got %lu\n", len_with_null, len);
|
||||
|
||||
len = GetTempPathA(0, NULL);
|
||||
ok(len >= len_with_null, "Expected >= %lu, got %lu\n", len_with_null, len);
|
||||
|
||||
/* The call above gave us the buffer size that Windows thinks is needed
|
||||
* so the next call should work
|
||||
*/
|
||||
lstrcpyA(buf, "foo");
|
||||
len = GetTempPathA(len, buf);
|
||||
ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
|
||||
ok(len == strlen(buf), "returned length should be equal to the length of string\n");
|
||||
}
|
||||
|
||||
static void test_GetTempPathW(char* tmp_dir)
|
||||
{
|
||||
DWORD len, len_with_null;
|
||||
WCHAR buf[MAX_PATH];
|
||||
WCHAR tmp_dirW[MAX_PATH];
|
||||
static const WCHAR fooW[] = {'f','o','o',0};
|
||||
|
||||
MultiByteToWideChar(CP_ACP,0,tmp_dir,-1,tmp_dirW,sizeof(tmp_dirW)/sizeof(*tmp_dirW));
|
||||
len_with_null = lstrlenW(tmp_dirW) + 1;
|
||||
|
||||
/* This one is different from ANSI version: ANSI version doesn't
|
||||
* touch the buffer, unicode version usually truncates the buffer
|
||||
* to zero size. NT still exagerates the required buffer size
|
||||
* sometimes so we cannot test for an exact match. Finally, the
|
||||
* 'len_with_null - 1' case is so buggy on Windows it's not testable.
|
||||
* For instance on NT4 it will sometimes return a path without the
|
||||
* trailing '\\' and sometimes return an error.
|
||||
*/
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
len = GetTempPathW(MAX_PATH, buf);
|
||||
if (len==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
|
||||
return;
|
||||
ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
|
||||
ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
len = GetTempPathW(1, buf);
|
||||
ok(buf[0] == 0, "unicode version should truncate the buffer to zero size\n");
|
||||
ok(len >= len_with_null, "Expected >= %lu, got %lu\n", len_with_null, len);
|
||||
|
||||
len = GetTempPathW(0, NULL);
|
||||
ok(len >= len_with_null, "Expected >= %lu, got %lu\n", len_with_null, len);
|
||||
|
||||
lstrcpyW(buf, fooW);
|
||||
len = GetTempPathW(len, buf);
|
||||
ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
|
||||
ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
|
||||
}
|
||||
|
||||
static void test_GetTempPath(void)
|
||||
{
|
||||
char save_TMP[MAX_PATH];
|
||||
char windir[MAX_PATH];
|
||||
char buf[MAX_PATH];
|
||||
|
||||
GetEnvironmentVariableA("TMP", save_TMP, sizeof(save_TMP));
|
||||
|
||||
/* test default configuration */
|
||||
trace("TMP=%s\n", save_TMP);
|
||||
strcpy(buf,save_TMP);
|
||||
if (buf[strlen(buf)-1]!='\\')
|
||||
strcat(buf,"\\");
|
||||
test_GetTempPathA(buf);
|
||||
test_GetTempPathW(buf);
|
||||
|
||||
/* TMP=C:\WINDOWS */
|
||||
GetWindowsDirectoryA(windir, sizeof(windir));
|
||||
SetEnvironmentVariableA("TMP", windir);
|
||||
GetEnvironmentVariableA("TMP", buf, sizeof(buf));
|
||||
trace("TMP=%s\n", buf);
|
||||
strcat(windir,"\\");
|
||||
test_GetTempPathA(windir);
|
||||
test_GetTempPathW(windir);
|
||||
|
||||
/* TMP=C:\ */
|
||||
GetWindowsDirectoryA(windir, sizeof(windir));
|
||||
windir[3] = 0;
|
||||
SetEnvironmentVariableA("TMP", windir);
|
||||
GetEnvironmentVariableA("TMP", buf, sizeof(buf));
|
||||
trace("TMP=%s\n", buf);
|
||||
test_GetTempPathA(windir);
|
||||
test_GetTempPathW(windir);
|
||||
|
||||
/* TMP=C: i.e. use current working directory of the specified drive */
|
||||
GetWindowsDirectoryA(windir, sizeof(windir));
|
||||
SetCurrentDirectoryA(windir);
|
||||
windir[2] = 0;
|
||||
SetEnvironmentVariableA("TMP", windir);
|
||||
GetEnvironmentVariableA("TMP", buf, sizeof(buf));
|
||||
trace("TMP=%s\n", buf);
|
||||
GetWindowsDirectoryA(windir, sizeof(windir));
|
||||
strcat(windir,"\\");
|
||||
test_GetTempPathA(windir);
|
||||
test_GetTempPathW(windir);
|
||||
|
||||
SetEnvironmentVariableA("TMP", save_TMP);
|
||||
}
|
||||
|
||||
START_TEST(path)
|
||||
{
|
||||
CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
|
||||
pGetLongPathNameA = (void*)GetProcAddress( GetModuleHandleA("kernel32.dll"),
|
||||
"GetLongPathNameA" );
|
||||
test_InitPathA(curdir, &curDrive, &otherDrive);
|
||||
test_CurrentDirectoryA(origdir,curdir);
|
||||
test_PathNameA(curdir, curDrive, otherDrive);
|
||||
test_CleanupPathA(origdir,curdir);
|
||||
test_GetTempPath();
|
||||
}
|
|
@ -1,781 +0,0 @@
|
|||
/*
|
||||
* Unit tests for named pipe functions in Wine
|
||||
*
|
||||
* Copyright (c) 2002 Dan Kegel
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winsock.h>
|
||||
#include <wtypes.h>
|
||||
#include <winerror.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
#define PIPENAME "\\\\.\\PiPe\\tests_pipe.c"
|
||||
|
||||
#define NB_SERVER_LOOPS 8
|
||||
|
||||
static HANDLE alarm_event;
|
||||
|
||||
static void test_CreateNamedPipe(int pipemode)
|
||||
{
|
||||
HANDLE hnp;
|
||||
HANDLE hFile;
|
||||
static const char obuf[] = "Bit Bucket";
|
||||
static const char obuf2[] = "More bits";
|
||||
char ibuf[32], *pbuf;
|
||||
DWORD written;
|
||||
DWORD readden;
|
||||
DWORD avail;
|
||||
DWORD lpmode;
|
||||
|
||||
if (pipemode == PIPE_TYPE_BYTE)
|
||||
trace("test_CreateNamedPipe starting in byte mode\n");
|
||||
else
|
||||
trace("test_CreateNamedPipe starting in message mode\n");
|
||||
/* Bad parameter checks */
|
||||
hnp = CreateNamedPipe("not a named pipe", PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
|
||||
/* nMaxInstances */ 1,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
|
||||
if (hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
|
||||
/* Is this the right way to notify user of skipped tests? */
|
||||
ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
|
||||
"CreateNamedPipe not supported on this platform, skipping tests.\n");
|
||||
return;
|
||||
}
|
||||
ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_NAME,
|
||||
"CreateNamedPipe should fail if name doesn't start with \\\\.\\pipe\n");
|
||||
|
||||
hnp = CreateNamedPipe(NULL,
|
||||
PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
|
||||
1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL);
|
||||
ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND,
|
||||
"CreateNamedPipe should fail if name is NULL\n");
|
||||
|
||||
hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
ok(hFile == INVALID_HANDLE_VALUE
|
||||
&& GetLastError() == ERROR_FILE_NOT_FOUND,
|
||||
"connecting to nonexistent named pipe should fail with ERROR_FILE_NOT_FOUND\n");
|
||||
|
||||
/* Functional checks */
|
||||
|
||||
hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
|
||||
/* nMaxInstances */ 1,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||
|
||||
ok(WaitNamedPipeA(PIPENAME, 2000), "WaitNamedPipe failed (%08lx)\n", GetLastError());
|
||||
|
||||
hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%08lx)\n", GetLastError());
|
||||
|
||||
/* don't try to do i/o if one side couldn't be opened, as it hangs */
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
HANDLE hFile2;
|
||||
|
||||
/* Make sure we can read and write a few bytes in both directions */
|
||||
memset(ibuf, 0, sizeof(ibuf));
|
||||
ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
|
||||
ok(written == sizeof(obuf), "write file len 1\n");
|
||||
ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
|
||||
ok(readden == sizeof(obuf), "peek 1 got %ld bytes\n", readden);
|
||||
ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
|
||||
ok(readden == sizeof(obuf), "read 1 got %ld bytes\n", readden);
|
||||
ok(memcmp(obuf, ibuf, written) == 0, "content 1 check\n");
|
||||
|
||||
memset(ibuf, 0, sizeof(ibuf));
|
||||
ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
|
||||
ok(written == sizeof(obuf2), "write file len 2\n");
|
||||
ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
|
||||
ok(readden == sizeof(obuf2), "peek 2 got %ld bytes\n", readden);
|
||||
ok(PeekNamedPipe(hnp, (LPVOID)1, 0, NULL, &readden, NULL), "Peek\n");
|
||||
ok(readden == sizeof(obuf2), "peek 2 got %ld bytes\n", readden);
|
||||
ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
|
||||
ok(readden == sizeof(obuf2), "read 2 got %ld bytes\n", readden);
|
||||
ok(memcmp(obuf2, ibuf, written) == 0, "content 2 check\n");
|
||||
|
||||
/* Test reading of multiple writes */
|
||||
memset(ibuf, 0, sizeof(ibuf));
|
||||
ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile3a\n");
|
||||
ok(written == sizeof(obuf), "write file len 3a\n");
|
||||
ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile3b\n");
|
||||
ok(written == sizeof(obuf2), "write file len 3b\n");
|
||||
ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek3\n");
|
||||
if (pipemode == PIPE_TYPE_BYTE) {
|
||||
todo_wine {
|
||||
/* should return all 23 bytes */
|
||||
ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %ld bytes\n", readden);
|
||||
}
|
||||
}
|
||||
else
|
||||
ok(readden == sizeof(obuf), "peek3 got %ld bytes\n", readden);
|
||||
if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
|
||||
ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %ld bytes available\n", avail);
|
||||
pbuf = ibuf;
|
||||
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 3a check\n");
|
||||
if (pipemode == PIPE_TYPE_BYTE) {
|
||||
todo_wine {
|
||||
pbuf += sizeof(obuf);
|
||||
ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "pipe content 3b check\n");
|
||||
}
|
||||
}
|
||||
ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
|
||||
ok(readden == sizeof(obuf) + sizeof(obuf2), "read 3 got %ld bytes\n", readden);
|
||||
pbuf = ibuf;
|
||||
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 3a check\n");
|
||||
pbuf += sizeof(obuf);
|
||||
ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 3b check\n");
|
||||
|
||||
/* Multiple writes in the reverse direction */
|
||||
memset(ibuf, 0, sizeof(ibuf));
|
||||
ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile4a\n");
|
||||
ok(written == sizeof(obuf), "write file len 4a\n");
|
||||
ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile4b\n");
|
||||
ok(written == sizeof(obuf2), "write file len 4b\n");
|
||||
ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek4\n");
|
||||
if (pipemode == PIPE_TYPE_BYTE) {
|
||||
todo_wine {
|
||||
/* should return all 23 bytes */
|
||||
ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %ld bytes\n", readden);
|
||||
}
|
||||
}
|
||||
else
|
||||
ok(readden == sizeof(obuf), "peek4 got %ld bytes\n", readden);
|
||||
if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
|
||||
ok(avail == sizeof(obuf) + sizeof(obuf2), "peek4 got %ld bytes available\n", avail);
|
||||
pbuf = ibuf;
|
||||
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 4a check\n");
|
||||
if (pipemode == PIPE_TYPE_BYTE) {
|
||||
todo_wine {
|
||||
pbuf += sizeof(obuf);
|
||||
ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "pipe content 4b check\n");
|
||||
}
|
||||
}
|
||||
ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
|
||||
if (pipemode == PIPE_TYPE_BYTE) {
|
||||
ok(readden == sizeof(obuf) + sizeof(obuf2), "read 4 got %ld bytes\n", readden);
|
||||
}
|
||||
else {
|
||||
todo_wine {
|
||||
ok(readden == sizeof(obuf), "read 4 got %ld bytes\n", readden);
|
||||
}
|
||||
}
|
||||
pbuf = ibuf;
|
||||
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 4a check\n");
|
||||
if (pipemode == PIPE_TYPE_BYTE) {
|
||||
pbuf += sizeof(obuf);
|
||||
ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 4b check\n");
|
||||
}
|
||||
|
||||
/* Test reading of multiple writes after a mode change
|
||||
(CreateFile always creates a byte mode pipe) */
|
||||
lpmode = PIPE_READMODE_MESSAGE;
|
||||
if (pipemode == PIPE_TYPE_BYTE) {
|
||||
/* trying to change the client end of a byte pipe to message mode should fail */
|
||||
ok(!SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
|
||||
}
|
||||
else {
|
||||
todo_wine {
|
||||
ok(SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
|
||||
}
|
||||
|
||||
memset(ibuf, 0, sizeof(ibuf));
|
||||
ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile5a\n");
|
||||
ok(written == sizeof(obuf), "write file len 3a\n");
|
||||
ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile5b\n");
|
||||
ok(written == sizeof(obuf2), "write file len 3b\n");
|
||||
ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek5\n");
|
||||
ok(readden == sizeof(obuf), "peek5 got %ld bytes\n", readden);
|
||||
if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
|
||||
ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %ld bytes available\n", avail);
|
||||
pbuf = ibuf;
|
||||
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
|
||||
ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
|
||||
todo_wine {
|
||||
ok(readden == sizeof(obuf), "read 5 got %ld bytes\n", readden);
|
||||
}
|
||||
pbuf = ibuf;
|
||||
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
|
||||
|
||||
/* Multiple writes in the reverse direction */
|
||||
/* the write of obuf2 from write4 should still be in the buffer */
|
||||
ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6a\n");
|
||||
todo_wine {
|
||||
ok(readden == sizeof(obuf2), "peek6a got %ld bytes\n", readden);
|
||||
ok(avail == sizeof(obuf2), "peek6a got %ld bytes available\n", avail);
|
||||
}
|
||||
if (avail > 0) {
|
||||
ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
|
||||
ok(readden == sizeof(obuf2), "read 6a got %ld bytes\n", readden);
|
||||
pbuf = ibuf;
|
||||
ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 6a check\n");
|
||||
}
|
||||
memset(ibuf, 0, sizeof(ibuf));
|
||||
ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile6a\n");
|
||||
ok(written == sizeof(obuf), "write file len 6a\n");
|
||||
ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile6b\n");
|
||||
ok(written == sizeof(obuf2), "write file len 6b\n");
|
||||
ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6\n");
|
||||
ok(readden == sizeof(obuf), "peek6 got %ld bytes\n", readden);
|
||||
if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
|
||||
ok(avail == sizeof(obuf) + sizeof(obuf2), "peek6b got %ld bytes available\n", avail);
|
||||
pbuf = ibuf;
|
||||
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
|
||||
ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
|
||||
todo_wine {
|
||||
ok(readden == sizeof(obuf), "read 6b got %ld bytes\n", readden);
|
||||
}
|
||||
pbuf = ibuf;
|
||||
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
|
||||
}
|
||||
|
||||
/* Picky conformance tests */
|
||||
|
||||
/* Verify that you can't connect to pipe again
|
||||
* until server calls DisconnectNamedPipe+ConnectNamedPipe
|
||||
* or creates a new pipe
|
||||
* case 1: other client not yet closed
|
||||
*/
|
||||
hFile2 = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
ok(hFile2 == INVALID_HANDLE_VALUE,
|
||||
"connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
|
||||
ok(GetLastError() == ERROR_PIPE_BUSY,
|
||||
"connecting to named pipe before other client closes should fail with ERROR_PIPE_BUSY\n");
|
||||
|
||||
ok(CloseHandle(hFile), "CloseHandle\n");
|
||||
|
||||
/* case 2: other client already closed */
|
||||
hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
ok(hFile == INVALID_HANDLE_VALUE,
|
||||
"connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
|
||||
ok(GetLastError() == ERROR_PIPE_BUSY,
|
||||
"connecting to named pipe after other client closes but before DisconnectNamedPipe should fail with ERROR_PIPE_BUSY\n");
|
||||
|
||||
ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
|
||||
|
||||
/* case 3: server has called DisconnectNamedPipe but not ConnectNamed Pipe */
|
||||
hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
ok(hFile == INVALID_HANDLE_VALUE,
|
||||
"connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
|
||||
ok(GetLastError() == ERROR_PIPE_BUSY,
|
||||
"connecting to named pipe after other client closes but before ConnectNamedPipe should fail with ERROR_PIPE_BUSY\n");
|
||||
|
||||
/* to be complete, we'd call ConnectNamedPipe here and loop,
|
||||
* but by default that's blocking, so we'd either have
|
||||
* to turn on the uncommon nonblocking mode, or
|
||||
* use another thread.
|
||||
*/
|
||||
}
|
||||
|
||||
ok(CloseHandle(hnp), "CloseHandle\n");
|
||||
|
||||
trace("test_CreateNamedPipe returning\n");
|
||||
}
|
||||
|
||||
static void test_CreateNamedPipe_instances_must_match(void)
|
||||
{
|
||||
HANDLE hnp, hnp2;
|
||||
|
||||
/* Check no mismatch */
|
||||
hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
/* nMaxInstances */ 2,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||
|
||||
hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
/* nMaxInstances */ 2,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
ok(hnp2 != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||
|
||||
ok(CloseHandle(hnp), "CloseHandle\n");
|
||||
ok(CloseHandle(hnp2), "CloseHandle\n");
|
||||
|
||||
/* Check nMaxInstances */
|
||||
hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
/* nMaxInstances */ 1,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||
|
||||
hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
/* nMaxInstances */ 1,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
ok(hnp2 == INVALID_HANDLE_VALUE
|
||||
&& GetLastError() == ERROR_PIPE_BUSY, "nMaxInstances not obeyed\n");
|
||||
|
||||
ok(CloseHandle(hnp), "CloseHandle\n");
|
||||
|
||||
/* Check PIPE_ACCESS_* */
|
||||
hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
/* nMaxInstances */ 2,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||
|
||||
hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
/* nMaxInstances */ 1,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
ok(hnp2 == INVALID_HANDLE_VALUE
|
||||
&& GetLastError() == ERROR_ACCESS_DENIED, "PIPE_ACCESS_* mismatch allowed\n");
|
||||
|
||||
ok(CloseHandle(hnp), "CloseHandle\n");
|
||||
|
||||
/* etc, etc */
|
||||
}
|
||||
|
||||
/** implementation of alarm() */
|
||||
static DWORD CALLBACK alarmThreadMain(LPVOID arg)
|
||||
{
|
||||
DWORD timeout = (DWORD) arg;
|
||||
trace("alarmThreadMain\n");
|
||||
if (WaitForSingleObject( alarm_event, timeout ) == WAIT_TIMEOUT)
|
||||
{
|
||||
ok(FALSE, "alarm\n");
|
||||
ExitProcess(1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
HANDLE hnp = INVALID_HANDLE_VALUE;
|
||||
|
||||
/** Trivial byte echo server - disconnects after each session */
|
||||
static DWORD CALLBACK serverThreadMain1(LPVOID arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
trace("serverThreadMain1 start\n");
|
||||
/* Set up a simple echo server */
|
||||
hnp = CreateNamedPipe(PIPENAME "serverThreadMain1", PIPE_ACCESS_DUPLEX,
|
||||
PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
/* nMaxInstances */ 1,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
|
||||
ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||
for (i = 0; i < NB_SERVER_LOOPS; i++) {
|
||||
char buf[512];
|
||||
DWORD written;
|
||||
DWORD readden;
|
||||
DWORD success;
|
||||
|
||||
/* Wait for client to connect */
|
||||
trace("Server calling ConnectNamedPipe...\n");
|
||||
ok(ConnectNamedPipe(hnp, NULL)
|
||||
|| GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe\n");
|
||||
trace("ConnectNamedPipe returned.\n");
|
||||
|
||||
/* Echo bytes once */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
trace("Server reading...\n");
|
||||
success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
|
||||
trace("Server done reading.\n");
|
||||
ok(success, "ReadFile\n");
|
||||
ok(readden, "short read\n");
|
||||
|
||||
trace("Server writing...\n");
|
||||
ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile\n");
|
||||
trace("Server done writing.\n");
|
||||
ok(written == readden, "write file len\n");
|
||||
|
||||
/* finish this connection, wait for next one */
|
||||
ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
|
||||
trace("Server done flushing.\n");
|
||||
ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
|
||||
trace("Server done disconnecting.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Trivial byte echo server - closes after each connection */
|
||||
static DWORD CALLBACK serverThreadMain2(LPVOID arg)
|
||||
{
|
||||
int i;
|
||||
HANDLE hnpNext = 0;
|
||||
|
||||
trace("serverThreadMain2\n");
|
||||
/* Set up a simple echo server */
|
||||
hnp = CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
|
||||
PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
/* nMaxInstances */ 2,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||
|
||||
for (i = 0; i < NB_SERVER_LOOPS; i++) {
|
||||
char buf[512];
|
||||
DWORD written;
|
||||
DWORD readden;
|
||||
DWORD success;
|
||||
|
||||
/* Wait for client to connect */
|
||||
trace("Server calling ConnectNamedPipe...\n");
|
||||
ok(ConnectNamedPipe(hnp, NULL)
|
||||
|| GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe\n");
|
||||
trace("ConnectNamedPipe returned.\n");
|
||||
|
||||
/* Echo bytes once */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
trace("Server reading...\n");
|
||||
success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
|
||||
trace("Server done reading.\n");
|
||||
ok(success, "ReadFile\n");
|
||||
|
||||
trace("Server writing...\n");
|
||||
ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile\n");
|
||||
trace("Server done writing.\n");
|
||||
ok(written == readden, "write file len\n");
|
||||
|
||||
/* finish this connection, wait for next one */
|
||||
ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
|
||||
ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
|
||||
|
||||
/* Set up next echo server */
|
||||
hnpNext =
|
||||
CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
|
||||
PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
/* nMaxInstances */ 2,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
|
||||
ok(hnpNext != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||
|
||||
ok(CloseHandle(hnp), "CloseHandle\n");
|
||||
hnp = hnpNext;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Trivial byte echo server - uses overlapped named pipe calls */
|
||||
static DWORD CALLBACK serverThreadMain3(LPVOID arg)
|
||||
{
|
||||
int i;
|
||||
HANDLE hEvent;
|
||||
|
||||
trace("serverThreadMain3\n");
|
||||
/* Set up a simple echo server */
|
||||
hnp = CreateNamedPipe(PIPENAME "serverThreadMain3", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
||||
PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
/* nMaxInstances */ 1,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||
|
||||
hEvent = CreateEvent(NULL, /* security attribute */
|
||||
TRUE, /* manual reset event */
|
||||
FALSE, /* initial state */
|
||||
NULL); /* name */
|
||||
ok(hEvent != NULL, "CreateEvent\n");
|
||||
|
||||
for (i = 0; i < NB_SERVER_LOOPS; i++) {
|
||||
char buf[512];
|
||||
DWORD written;
|
||||
DWORD readden;
|
||||
DWORD dummy;
|
||||
DWORD success;
|
||||
OVERLAPPED oOverlap;
|
||||
int letWFSOEwait = (i & 2);
|
||||
int letGORwait = (i & 1);
|
||||
DWORD err;
|
||||
|
||||
memset(&oOverlap, 0, sizeof(oOverlap));
|
||||
oOverlap.hEvent = hEvent;
|
||||
|
||||
/* Wait for client to connect */
|
||||
trace("Server calling overlapped ConnectNamedPipe...\n");
|
||||
success = ConnectNamedPipe(hnp, &oOverlap);
|
||||
err = GetLastError();
|
||||
ok(success || err == ERROR_IO_PENDING
|
||||
|| err == ERROR_PIPE_CONNECTED, "overlapped ConnectNamedPipe\n");
|
||||
trace("overlapped ConnectNamedPipe returned.\n");
|
||||
if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
|
||||
ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ConnectNamedPipe\n");
|
||||
success = GetOverlappedResult(hnp, &oOverlap, &dummy, letGORwait);
|
||||
if (!letGORwait && !letWFSOEwait && !success) {
|
||||
ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
|
||||
success = GetOverlappedResult(hnp, &oOverlap, &dummy, TRUE);
|
||||
}
|
||||
ok(success, "GetOverlappedResult ConnectNamedPipe\n");
|
||||
trace("overlapped ConnectNamedPipe operation complete.\n");
|
||||
|
||||
/* Echo bytes once */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
trace("Server reading...\n");
|
||||
success = ReadFile(hnp, buf, sizeof(buf), NULL, &oOverlap);
|
||||
trace("Server ReadFile returned...\n");
|
||||
err = GetLastError();
|
||||
ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile\n");
|
||||
trace("overlapped ReadFile returned.\n");
|
||||
if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
|
||||
ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ReadFile\n");
|
||||
success = GetOverlappedResult(hnp, &oOverlap, &readden, letGORwait);
|
||||
if (!letGORwait && !letWFSOEwait && !success) {
|
||||
ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
|
||||
success = GetOverlappedResult(hnp, &oOverlap, &readden, TRUE);
|
||||
}
|
||||
trace("Server done reading.\n");
|
||||
ok(success, "overlapped ReadFile\n");
|
||||
|
||||
trace("Server writing...\n");
|
||||
success = WriteFile(hnp, buf, readden, NULL, &oOverlap);
|
||||
trace("Server WriteFile returned...\n");
|
||||
err = GetLastError();
|
||||
ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile\n");
|
||||
trace("overlapped WriteFile returned.\n");
|
||||
if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
|
||||
ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait WriteFile\n");
|
||||
success = GetOverlappedResult(hnp, &oOverlap, &written, letGORwait);
|
||||
if (!letGORwait && !letWFSOEwait && !success) {
|
||||
ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
|
||||
success = GetOverlappedResult(hnp, &oOverlap, &written, TRUE);
|
||||
}
|
||||
trace("Server done writing.\n");
|
||||
ok(success, "overlapped WriteFile\n");
|
||||
ok(written == readden, "write file len\n");
|
||||
|
||||
/* finish this connection, wait for next one */
|
||||
ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
|
||||
ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exercizeServer(const char *pipename, HANDLE serverThread)
|
||||
{
|
||||
int i;
|
||||
|
||||
trace("exercizeServer starting\n");
|
||||
for (i = 0; i < NB_SERVER_LOOPS; i++) {
|
||||
HANDLE hFile=INVALID_HANDLE_VALUE;
|
||||
static const char obuf[] = "Bit Bucket";
|
||||
char ibuf[32];
|
||||
DWORD written;
|
||||
DWORD readden;
|
||||
int loop;
|
||||
|
||||
for (loop = 0; loop < 3; loop++) {
|
||||
DWORD err;
|
||||
trace("Client connecting...\n");
|
||||
/* Connect to the server */
|
||||
hFile = CreateFileA(pipename, GENERIC_READ | GENERIC_WRITE, 0,
|
||||
NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
err = GetLastError();
|
||||
if (loop == 0)
|
||||
ok(err == ERROR_PIPE_BUSY || err == ERROR_FILE_NOT_FOUND, "connecting to pipe\n");
|
||||
else
|
||||
ok(err == ERROR_PIPE_BUSY, "connecting to pipe\n");
|
||||
trace("connect failed, retrying\n");
|
||||
Sleep(200);
|
||||
}
|
||||
ok(hFile != INVALID_HANDLE_VALUE, "client opening named pipe\n");
|
||||
|
||||
/* Make sure it can echo */
|
||||
memset(ibuf, 0, sizeof(ibuf));
|
||||
trace("Client writing...\n");
|
||||
ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile to client end of pipe\n");
|
||||
ok(written == sizeof(obuf), "write file len\n");
|
||||
trace("Client reading...\n");
|
||||
ok(ReadFile(hFile, ibuf, sizeof(obuf), &readden, NULL), "ReadFile from client end of pipe\n");
|
||||
ok(readden == sizeof(obuf), "read file len\n");
|
||||
ok(memcmp(obuf, ibuf, written) == 0, "content check\n");
|
||||
|
||||
trace("Client closing...\n");
|
||||
ok(CloseHandle(hFile), "CloseHandle\n");
|
||||
}
|
||||
|
||||
ok(WaitForSingleObject(serverThread,INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject\n");
|
||||
CloseHandle(hnp);
|
||||
trace("exercizeServer returning\n");
|
||||
}
|
||||
|
||||
static void test_NamedPipe_2(void)
|
||||
{
|
||||
HANDLE serverThread;
|
||||
DWORD serverThreadId;
|
||||
HANDLE alarmThread;
|
||||
DWORD alarmThreadId;
|
||||
|
||||
trace("test_NamedPipe_2 starting\n");
|
||||
/* Set up a ten second timeout */
|
||||
alarm_event = CreateEvent( NULL, TRUE, FALSE, NULL );
|
||||
alarmThread = CreateThread(NULL, 0, alarmThreadMain, (void *) 10000, 0, &alarmThreadId);
|
||||
|
||||
/* The servers we're about to exercize do try to clean up carefully,
|
||||
* but to reduce the change of a test failure due to a pipe handle
|
||||
* leak in the test code, we'll use a different pipe name for each server.
|
||||
*/
|
||||
|
||||
/* Try server #1 */
|
||||
serverThread = CreateThread(NULL, 0, serverThreadMain1, (void *)8, 0, &serverThreadId);
|
||||
ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n");
|
||||
exercizeServer(PIPENAME "serverThreadMain1", serverThread);
|
||||
|
||||
/* Try server #2 */
|
||||
serverThread = CreateThread(NULL, 0, serverThreadMain2, 0, 0, &serverThreadId);
|
||||
ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n");
|
||||
exercizeServer(PIPENAME "serverThreadMain2", serverThread);
|
||||
|
||||
if( 0 ) /* overlapped pipe server doesn't work yet - it randomly fails */
|
||||
{
|
||||
/* Try server #3 */
|
||||
serverThread = CreateThread(NULL, 0, serverThreadMain3, 0, 0, &serverThreadId);
|
||||
ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n");
|
||||
exercizeServer(PIPENAME "serverThreadMain3", serverThread);
|
||||
}
|
||||
|
||||
ok(SetEvent( alarm_event ), "SetEvent\n");
|
||||
CloseHandle( alarm_event );
|
||||
trace("test_NamedPipe_2 returning\n");
|
||||
}
|
||||
|
||||
static int test_DisconnectNamedPipe(void)
|
||||
{
|
||||
HANDLE hnp;
|
||||
HANDLE hFile;
|
||||
static const char obuf[] = "Bit Bucket";
|
||||
char ibuf[32];
|
||||
DWORD written;
|
||||
DWORD readden;
|
||||
|
||||
hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
/* nMaxInstances */ 1,
|
||||
/* nOutBufSize */ 1024,
|
||||
/* nInBufSize */ 1024,
|
||||
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
|
||||
/* lpSecurityAttrib */ NULL);
|
||||
if (INVALID_HANDLE_VALUE == hnp) {
|
||||
trace ("Seems we have no named pipes.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL) == 0
|
||||
&& GetLastError() == ERROR_PIPE_LISTENING, "WriteFile to not-yet-connected pipe\n");
|
||||
ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
|
||||
&& GetLastError() == ERROR_PIPE_LISTENING, "ReadFile from not-yet-connected pipe\n");
|
||||
|
||||
hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed\n");
|
||||
|
||||
/* don't try to do i/o if one side couldn't be opened, as it hangs */
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
|
||||
/* see what happens if server calls DisconnectNamedPipe
|
||||
* when there are bytes in the pipe
|
||||
*/
|
||||
|
||||
ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
|
||||
ok(written == sizeof(obuf), "write file len\n");
|
||||
ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe while messages waiting\n");
|
||||
ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL) == 0
|
||||
&& GetLastError() == ERROR_PIPE_NOT_CONNECTED, "WriteFile to disconnected pipe\n");
|
||||
ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
|
||||
&& GetLastError() == ERROR_PIPE_NOT_CONNECTED,
|
||||
"ReadFile from disconnected pipe with bytes waiting\n");
|
||||
ok(CloseHandle(hFile), "CloseHandle\n");
|
||||
}
|
||||
|
||||
ok(CloseHandle(hnp), "CloseHandle\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
static void test_CreatePipe(void)
|
||||
{
|
||||
SECURITY_ATTRIBUTES pipe_attr;
|
||||
HANDLE piperead, pipewrite;
|
||||
DWORD written;
|
||||
DWORD read;
|
||||
char readbuf[32];
|
||||
|
||||
pipe_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
pipe_attr.bInheritHandle = TRUE;
|
||||
pipe_attr.lpSecurityDescriptor = NULL;
|
||||
ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n");
|
||||
ok(WriteFile(pipewrite,PIPENAME,sizeof(PIPENAME), &written, NULL), "Write to anonymous pipe failed\n");
|
||||
ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %ld bytes instead of %d\n", written,sizeof(PIPENAME));
|
||||
ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from non empty pipe failed\n");
|
||||
ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %ld bytes instead of %d\n", read, sizeof(PIPENAME));
|
||||
|
||||
/* Now write another chunk*/
|
||||
ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n");
|
||||
ok(WriteFile(pipewrite,PIPENAME,sizeof(PIPENAME), &written, NULL), "Write to anonymous pipe failed\n");
|
||||
ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %ld bytes instead of %d\n", written,sizeof(PIPENAME));
|
||||
/* and close the write end, read should still succeed*/
|
||||
ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n");
|
||||
ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from broken pipe withe with pending data failed\n");
|
||||
ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %ld bytes instead of %d\n", read, sizeof(PIPENAME));
|
||||
/* But now we need to get informed that the pipe is closed */
|
||||
ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n");
|
||||
}
|
||||
|
||||
START_TEST(pipe)
|
||||
{
|
||||
trace("test 1 of 6:\n");
|
||||
if (test_DisconnectNamedPipe())
|
||||
return;
|
||||
trace("test 2 of 6:\n");
|
||||
test_CreateNamedPipe_instances_must_match();
|
||||
trace("test 3 of 6:\n");
|
||||
test_NamedPipe_2();
|
||||
trace("test 4 of 6:\n");
|
||||
test_CreateNamedPipe(PIPE_TYPE_BYTE);
|
||||
trace("test 5 of 6\n");
|
||||
test_CreateNamedPipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
|
||||
trace("test 6 of 6\n");
|
||||
test_CreatePipe();
|
||||
trace("all tests done\n");
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* Unit tests for profile functions
|
||||
*
|
||||
* Copyright (c) 2003 Stefan Leichter
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "windows.h"
|
||||
|
||||
#define KEY "ProfileInt"
|
||||
#define SECTION "Test"
|
||||
#define TESTFILE ".\\testwine.ini"
|
||||
#define TESTFILE2 ".\\testwine2.ini"
|
||||
|
||||
struct _profileInt {
|
||||
LPCSTR section;
|
||||
LPCSTR key;
|
||||
LPCSTR value;
|
||||
LPCSTR iniFile;
|
||||
INT defaultVal;
|
||||
UINT result;
|
||||
UINT result9x;
|
||||
};
|
||||
|
||||
static void test_profile_int(void)
|
||||
{
|
||||
struct _profileInt profileInt[]={
|
||||
{ NULL, NULL, NULL, NULL, 70, 0 , 0}, /* 0 */
|
||||
{ NULL, NULL, NULL, TESTFILE, -1, 4294967295U, 0},
|
||||
{ NULL, NULL, NULL, TESTFILE, 1, 1 , 0},
|
||||
{ SECTION, NULL, NULL, TESTFILE, -1, 4294967295U, 0},
|
||||
{ SECTION, NULL, NULL, TESTFILE, 1, 1 , 0},
|
||||
{ NULL, KEY, NULL, TESTFILE, -1, 4294967295U, 0}, /* 5 */
|
||||
{ NULL, KEY, NULL, TESTFILE, 1, 1 , 0},
|
||||
{ SECTION, KEY, NULL, TESTFILE, -1, 4294967295U, 4294967295U},
|
||||
{ SECTION, KEY, NULL, TESTFILE, 1, 1 , 1},
|
||||
{ SECTION, KEY, "-1", TESTFILE, -1, 4294967295U, 4294967295U},
|
||||
{ SECTION, KEY, "-1", TESTFILE, 1, 4294967295U, 4294967295U}, /* 10 */
|
||||
{ SECTION, KEY, "1", TESTFILE, -1, 1 , 1},
|
||||
{ SECTION, KEY, "1", TESTFILE, 1, 1 , 1},
|
||||
{ SECTION, KEY, "+1", TESTFILE, -1, 1 , 0},
|
||||
{ SECTION, KEY, "+1", TESTFILE, 1, 1 , 0},
|
||||
{ SECTION, KEY, "4294967296", TESTFILE, -1, 0 , 0}, /* 15 */
|
||||
{ SECTION, KEY, "4294967296", TESTFILE, 1, 0 , 0},
|
||||
{ SECTION, KEY, "4294967297", TESTFILE, -1, 1 , 1},
|
||||
{ SECTION, KEY, "4294967297", TESTFILE, 1, 1 , 1},
|
||||
{ SECTION, KEY, "-4294967297", TESTFILE, -1, 4294967295U, 4294967295U},
|
||||
{ SECTION, KEY, "-4294967297", TESTFILE, 1, 4294967295U, 4294967295U}, /* 20 */
|
||||
{ SECTION, KEY, "42A94967297", TESTFILE, -1, 42 , 42},
|
||||
{ SECTION, KEY, "42A94967297", TESTFILE, 1, 42 , 42},
|
||||
{ SECTION, KEY, "B4294967297", TESTFILE, -1, 0 , 0},
|
||||
{ SECTION, KEY, "B4294967297", TESTFILE, 1, 0 , 0},
|
||||
};
|
||||
int i, num_test = (sizeof(profileInt)/sizeof(struct _profileInt));
|
||||
UINT res;
|
||||
|
||||
DeleteFileA( TESTFILE);
|
||||
|
||||
for (i=0; i < num_test; i++) {
|
||||
if (profileInt[i].value)
|
||||
WritePrivateProfileStringA(SECTION, KEY, profileInt[i].value,
|
||||
profileInt[i].iniFile);
|
||||
|
||||
res = GetPrivateProfileIntA(profileInt[i].section, profileInt[i].key,
|
||||
profileInt[i].defaultVal, profileInt[i].iniFile);
|
||||
ok((res == profileInt[i].result) || (res == profileInt[i].result9x),
|
||||
"test<%02d>: ret<%010u> exp<%010u><%010u>\n",
|
||||
i, res, profileInt[i].result, profileInt[i].result9x);
|
||||
}
|
||||
|
||||
DeleteFileA( TESTFILE);
|
||||
}
|
||||
|
||||
static void test_profile_string(void)
|
||||
{
|
||||
HANDLE h;
|
||||
int ret;
|
||||
DWORD count;
|
||||
char buf[100];
|
||||
char *p;
|
||||
/* test that lines without an '=' will not be enumerated */
|
||||
/* in the case below, name2 is a key while name3 is not. */
|
||||
char content[]="[s]\r\nname1=val1\r\nname2=\r\nname3\r\nname4=val4\r\n";
|
||||
DeleteFileA( TESTFILE2);
|
||||
h = CreateFileA( TESTFILE2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
ok( h != INVALID_HANDLE_VALUE, " cannot create %s\n", TESTFILE2);
|
||||
if( h == INVALID_HANDLE_VALUE) return;
|
||||
WriteFile( h, content, sizeof(content), &count, NULL);
|
||||
CloseHandle( h);
|
||||
|
||||
/* enumerate the keys */
|
||||
ret=GetPrivateProfileStringA( "s", NULL, "", buf, sizeof(buf),
|
||||
TESTFILE2);
|
||||
for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1)
|
||||
p[-1] = ',';
|
||||
/* and test */
|
||||
ok( ret == 18 && !strcmp( buf, "name1,name2,name4"), "wrong keys returned(%d): %s\n", ret,
|
||||
buf);
|
||||
|
||||
ret=GetPrivateProfileSectionA("s", buf, sizeof(buf), TESTFILE2);
|
||||
for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1)
|
||||
p[-1] = ',';
|
||||
/* and test */
|
||||
ok( ret == 35 && !strcmp( buf, "name1=val1,name2=,name3,name4=val4"), "wrong section returned(%d): %s\n",
|
||||
ret, buf);
|
||||
|
||||
/* add a new key to test that the file is quite usable */
|
||||
WritePrivateProfileStringA( "s", "name5", "val5", TESTFILE2);
|
||||
ret=GetPrivateProfileStringA( "s", NULL, "", buf, sizeof(buf),
|
||||
TESTFILE2);
|
||||
for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1)
|
||||
p[-1] = ',';
|
||||
ok( ret == 24 && !strcmp( buf, "name1,name2,name4,name5"), "wrong keys returned(%d): %s\n",
|
||||
ret, buf);
|
||||
|
||||
DeleteFileA( TESTFILE2);
|
||||
}
|
||||
|
||||
START_TEST(profile)
|
||||
{
|
||||
test_profile_int();
|
||||
test_profile_string();
|
||||
}
|
396
reactos/regtests/winetests/setupapi/parser.c
Normal file
396
reactos/regtests/winetests/setupapi/parser.c
Normal file
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
* INF file parsing tests
|
||||
*
|
||||
* Copyright 2002, 2005 Alexandre Julliard 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 <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
#include "winreg.h"
|
||||
#include "setupapi.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
static const char tmpfile[] = ".\\tmp.inf";
|
||||
|
||||
/* some large strings */
|
||||
#define A255 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
#define A256 "a" A255
|
||||
#define A400 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
"aaaaaaaaaaaaaaaa" A256
|
||||
#define A511 A255 A256
|
||||
#define A4097 "a" A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256
|
||||
|
||||
#define STD_HEADER "[Version]\r\nSignature=\"$CHICAGO$\"\r\n"
|
||||
|
||||
#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" \
|
||||
"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,
|
||||
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 );
|
||||
}
|
||||
|
||||
static const char *get_string_field( INFCONTEXT *context, DWORD index )
|
||||
{
|
||||
static char buffer[MAX_INF_STRING_LENGTH+32];
|
||||
if (SetupGetStringFieldA( context, index, buffer, sizeof(buffer), NULL )) return buffer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *get_line_text( INFCONTEXT *context )
|
||||
{
|
||||
static char buffer[MAX_INF_STRING_LENGTH+32];
|
||||
if (SetupGetLineTextA( context, 0, 0, 0, buffer, sizeof(buffer), NULL )) return buffer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Test various valid/invalid file formats */
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *data;
|
||||
DWORD error;
|
||||
UINT err_line;
|
||||
int todo;
|
||||
} invalid_files[] =
|
||||
{
|
||||
/* file contents expected error (or 0) errline todo */
|
||||
{ "\r\n", ERROR_WRONG_INF_STYLE, 0, 0 },
|
||||
{ "abcd\r\n", ERROR_WRONG_INF_STYLE, 0, 1 },
|
||||
{ "[Version]\r\n", ERROR_WRONG_INF_STYLE, 0, 0 },
|
||||
{ "[Version]\nSignature=", ERROR_WRONG_INF_STYLE, 0, 0 },
|
||||
{ "[Version]\nSignature=foo", ERROR_WRONG_INF_STYLE, 0, 0 },
|
||||
{ "[version]\nsignature=$chicago$", 0, 0, 0 },
|
||||
{ "[VERSION]\nSIGNATURE=$CHICAGO$", 0, 0, 0 },
|
||||
{ "[Version]\nSignature=$chicago$,abcd", 0, 0, 0 },
|
||||
{ "[Version]\nabc=def\nSignature=$chicago$", 0, 0, 0 },
|
||||
{ "[Version]\nabc=def\n[Version]\nSignature=$chicago$", 0, 0, 0 },
|
||||
{ STD_HEADER, 0, 0, 0 },
|
||||
{ STD_HEADER "[]\r\n", 0, 0, 0 },
|
||||
{ STD_HEADER "]\r\n", 0, 0, 0 },
|
||||
{ STD_HEADER "[" A255 "]\r\n", 0, 0, 0 },
|
||||
{ STD_HEADER "[ab\r\n", ERROR_BAD_SECTION_NAME_LINE, 3, 0 },
|
||||
{ STD_HEADER "\n\n[ab\x1a]\n", ERROR_BAD_SECTION_NAME_LINE, 5, 0 },
|
||||
{ STD_HEADER "[" A256 "]\r\n", ERROR_SECTION_NAME_TOO_LONG, 3, 0 },
|
||||
{ "[abc]\n" STD_HEADER, 0, 0, 0 },
|
||||
{ "abc\r\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 1, 0 },
|
||||
{ ";\n;\nabc\r\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 3, 0 },
|
||||
{ ";\n;\nab\nab\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 3, 0 },
|
||||
{ ";aa\n;bb\n" STD_HEADER, 0, 0, 0 },
|
||||
{ STD_HEADER " [TestSection\x00] \n", ERROR_BAD_SECTION_NAME_LINE, 3, 0 },
|
||||
{ STD_HEADER " [Test\x00Section] \n", ERROR_BAD_SECTION_NAME_LINE, 3, 0 },
|
||||
{ STD_HEADER " [TestSection\x00] \n", ERROR_BAD_SECTION_NAME_LINE, 3, 0 },
|
||||
{ STD_HEADER " [Test\x00Section] \n", ERROR_BAD_SECTION_NAME_LINE, 3, 0 },
|
||||
};
|
||||
|
||||
static void test_invalid_files(void)
|
||||
{
|
||||
unsigned int i;
|
||||
UINT err_line;
|
||||
HINF hinf;
|
||||
DWORD err;
|
||||
|
||||
for (i = 0; i < sizeof(invalid_files)/sizeof(invalid_files[0]); i++)
|
||||
{
|
||||
SetLastError( 0xdeadbeef );
|
||||
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 );
|
||||
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",
|
||||
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",
|
||||
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 /* 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 );
|
||||
}
|
||||
if (hinf != INVALID_HANDLE_VALUE) SetupCloseInfFile( hinf );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Test various section names */
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *data;
|
||||
const char *section;
|
||||
DWORD error;
|
||||
} section_names[] =
|
||||
{
|
||||
/* file contents section name error code */
|
||||
{ STD_HEADER "[TestSection]", "TestSection", 0 },
|
||||
{ STD_HEADER "[TestSection]\n", "TestSection", 0 },
|
||||
{ STD_HEADER "[TESTSECTION]\r\n", "TestSection", 0 },
|
||||
{ STD_HEADER "[TestSection]\n[abc]", "testsection", 0 },
|
||||
{ STD_HEADER ";[TestSection]\n", "TestSection", ERROR_SECTION_NOT_FOUND },
|
||||
{ STD_HEADER "[TestSection]\n", "Bad name", ERROR_SECTION_NOT_FOUND },
|
||||
/* spaces */
|
||||
{ STD_HEADER "[TestSection] \r\n", "TestSection", 0 },
|
||||
{ STD_HEADER " [TestSection]\r\n", "TestSection", 0 },
|
||||
{ STD_HEADER " [TestSection] dummy\r\n", "TestSection", 0 },
|
||||
{ STD_HEADER " [TestSection] [foo]\r\n", "TestSection", 0 },
|
||||
{ STD_HEADER " [ Test Section ] dummy\r\n", " Test Section ", 0 },
|
||||
{ STD_HEADER "[TestSection] \032\ndummy", "TestSection", 0 },
|
||||
{ STD_HEADER "[TestSection] \n\032dummy", "TestSection", 0 },
|
||||
/* special chars in section name */
|
||||
{ STD_HEADER "[Test[Section]\r\n", "Test[Section", 0 },
|
||||
{ STD_HEADER "[Test[S]ection]\r\n", "Test[S", 0 },
|
||||
{ STD_HEADER "[Test[[[Section]\r\n", "Test[[[Section", 0 },
|
||||
{ STD_HEADER "[]\r\n", "", 0 },
|
||||
{ STD_HEADER "[[[]\n", "[[", 0 },
|
||||
{ STD_HEADER "[Test\"Section]\r\n", "Test\"Section", 0 },
|
||||
{ STD_HEADER "[Test\\Section]\r\n", "Test\\Section", 0 },
|
||||
{ STD_HEADER "[Test\\ Section]\r\n", "Test\\ Section", 0 },
|
||||
{ STD_HEADER "[Test;Section]\r\n", "Test;Section", 0 },
|
||||
/* various control chars */
|
||||
{ STD_HEADER " [Test\r\b\tSection] \n", "Test\r\b\tSection", 0 },
|
||||
/* nulls */
|
||||
};
|
||||
|
||||
static void test_section_names(void)
|
||||
{
|
||||
unsigned int i;
|
||||
UINT err_line;
|
||||
HINF hinf;
|
||||
DWORD err;
|
||||
LONG ret;
|
||||
|
||||
for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); i++)
|
||||
{
|
||||
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() );
|
||||
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 );
|
||||
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 );
|
||||
}
|
||||
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",
|
||||
i, err, section_names[i].error );
|
||||
}
|
||||
SetupCloseInfFile( hinf );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Test various key and value names */
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *data;
|
||||
const char *key;
|
||||
const char *fields[10];
|
||||
} key_names[] =
|
||||
{
|
||||
/* file contents expected key expected fields */
|
||||
{ "ab=cd", "ab", { "cd" } },
|
||||
{ "ab=cd,ef,gh,ij", "ab", { "cd", "ef", "gh", "ij" } },
|
||||
{ "ab", "ab", { "ab" } },
|
||||
{ "ab,cd", NULL, { "ab", "cd" } },
|
||||
{ "ab,cd=ef", NULL, { "ab", "cd=ef" } },
|
||||
{ "=abcd,ef", "", { "abcd", "ef" } },
|
||||
/* backslashes */
|
||||
{ "ba\\\ncd=ef", "bacd", { "ef" } },
|
||||
{ "ab \\ \ncd=ef", "abcd", { "ef" } },
|
||||
{ "ab\\\ncd,ef", NULL, { "abcd", "ef" } },
|
||||
{ "ab \\ ;cc\ncd=ef", "abcd", { "ef" } },
|
||||
{ "ab \\ \\ \ncd=ef", "abcd", { "ef" } },
|
||||
{ "ba \\ dc=xx", "ba \\ dc", { "xx" } },
|
||||
{ "ba \\\\ \nc=d", "bac", { "d" } },
|
||||
{ "a=b\\\\c", "a", { "b\\\\c" } },
|
||||
{ "ab=cd \\ ", "ab", { "cd" } },
|
||||
{ "ba=c \\ \n \\ \n a", "ba", { "ca" } },
|
||||
{ "ba=c \\ \n \\ a", "ba", { "c\\ a" } },
|
||||
{ " \\ a= \\ b", "\\ a", { "\\ b" } },
|
||||
/* quotes */
|
||||
{ "Ab\"Cd\"=Ef", "AbCd", { "Ef" } },
|
||||
{ "Ab\"Cd=Ef\"", "AbCd=Ef", { "AbCd=Ef" } },
|
||||
{ "ab\"\"\"cd,ef=gh\"", "ab\"cd,ef=gh", { "ab\"cd,ef=gh" } },
|
||||
{ "ab\"\"cd=ef", "abcd", { "ef" } },
|
||||
{ "ab\"\"cd=ef,gh", "abcd", { "ef", "gh" } },
|
||||
{ "ab=cd\"\"ef", "ab", { "cdef" } },
|
||||
{ "ab=cd\",\"ef", "ab", { "cd,ef" } },
|
||||
{ "ab=cd\",ef", "ab", { "cd,ef" } },
|
||||
{ "ab=cd\",ef\\\nab", "ab", { "cd,ef\\" } },
|
||||
/* spaces */
|
||||
{ " a b = c , d \n", "a b", { "c", "d" } },
|
||||
{ " a b = c ,\" d\" \n", "a b", { "c", " d" } },
|
||||
{ " a b\r = c\r\n", "a b", { "c" } },
|
||||
/* empty fields */
|
||||
{ "a=b,,,c,,,d", "a", { "b", "", "", "c", "", "", "d" } },
|
||||
{ "a=b,\"\",c,\" \",d", "a", { "b", "", "c", " ", "d" } },
|
||||
{ "=,,b", "", { "", "", "b" } },
|
||||
{ ",=,,b", NULL, { "", "=", "", "b" } },
|
||||
{ "a=\n", "a", { "" } },
|
||||
{ "=", "", { "" } },
|
||||
/* eof */
|
||||
{ "ab=c\032d", "ab", { "c" } },
|
||||
{ "ab\032=cd", "ab", { "ab" } },
|
||||
/* nulls */
|
||||
{ "abcd=ef\x0gh", "abcd", { "ef" } },
|
||||
/* multiple sections with same name */
|
||||
{ "[Test2]\nab\n[Test]\nee=ff\n", "ee", { "ff" } },
|
||||
/* string substitution */
|
||||
{ "%foo%=%bar%\n" STR_SECTION, "aaa", { "bbb" } },
|
||||
{ "%foo%xx=%bar%yy\n" STR_SECTION, "aaaxx", { "bbbyy" } },
|
||||
{ "%% %foo%=%bar%\n" STR_SECTION, "% aaa", { "bbb" } },
|
||||
{ "%f\"o\"o%=ccc\n" STR_SECTION, "aaa", { "ccc" } },
|
||||
{ "abc=%bar;bla%\n" STR_SECTION, "abc", { "%bar" } },
|
||||
{ "loop=%loop%\n" STR_SECTION, "loop", { "%loop2%" } },
|
||||
{ "%per%%cent%=100\n" STR_SECTION, "12", { "100" } },
|
||||
{ "a=%big%\n" STR_SECTION, "a", { A400 } },
|
||||
{ "a=%verybig%\n" STR_SECTION, "a", { A511 } }, /* truncated to 511 */
|
||||
{ "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*/ } },
|
||||
};
|
||||
|
||||
/* check the key of a certain line */
|
||||
static const char *check_key( INFCONTEXT *context, const char *wanted )
|
||||
{
|
||||
const char *key = get_string_field( context, 0 );
|
||||
DWORD err = GetLastError();
|
||||
|
||||
if (!key)
|
||||
{
|
||||
ok( !wanted, "missing key %s\n", wanted );
|
||||
ok( err == 0 || err == ERROR_INVALID_PARAMETER, "last error set to %lx\n", err );
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( !strcmp( key, wanted ), "bad key %s/%s\n", key, wanted );
|
||||
ok( err == 0, "last error set to %lx\n", err );
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
static void test_key_names(void)
|
||||
{
|
||||
char buffer[MAX_INF_STRING_LENGTH+32];
|
||||
const char *key, *line;
|
||||
unsigned int i, index, count;
|
||||
UINT err_line;
|
||||
HINF hinf;
|
||||
DWORD err;
|
||||
BOOL ret;
|
||||
INFCONTEXT context;
|
||||
|
||||
for (i = 0; i < sizeof(key_names)/sizeof(key_names[0]); i++)
|
||||
{
|
||||
strcpy( buffer, STD_HEADER "[Test]\n" );
|
||||
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() );
|
||||
if (hinf == INVALID_HANDLE_VALUE) continue;
|
||||
|
||||
ret = SetupFindFirstLineA( hinf, "Test", 0, &context );
|
||||
assert( ret );
|
||||
|
||||
key = check_key( &context, key_names[i].key );
|
||||
|
||||
buffer[0] = buffer[1] = 0; /* build the full line */
|
||||
for (index = 0; ; index++)
|
||||
{
|
||||
const char *field = get_string_field( &context, index + 1 );
|
||||
err = GetLastError();
|
||||
if (field)
|
||||
{
|
||||
ok( err == 0, "line %u: bad error %lx\n", i, GetLastError() );
|
||||
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] );
|
||||
else
|
||||
ok( 0, "line %u: got extra field %s\n", i, field );
|
||||
strcat( buffer, "," );
|
||||
strcat( buffer, field );
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( err == 0 || err == ERROR_INVALID_PARAMETER,
|
||||
"line %u: bad error %lx\n", i, GetLastError() );
|
||||
if (key_names[i].fields[index])
|
||||
ok( 0, "line %u: missing field %s\n", i, key_names[i].fields[index] );
|
||||
}
|
||||
if (!key_names[i].fields[index]) break;
|
||||
}
|
||||
count = SetupGetFieldCount( &context );
|
||||
ok( count == index, "line %u: bad count %d/%d\n", i, index, count );
|
||||
|
||||
line = get_line_text( &context );
|
||||
ok( line != NULL, "line %u: SetupGetLineText failed\n", i );
|
||||
if (line) ok( !strcmp( line, buffer+1 ), "line %u: bad text %s/%s\n", i, line, buffer+1 );
|
||||
|
||||
SetupCloseInfFile( hinf );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
START_TEST(parser)
|
||||
{
|
||||
test_invalid_files();
|
||||
test_section_names();
|
||||
test_key_names();
|
||||
DeleteFileA( tmpfile );
|
||||
}
|
248
reactos/regtests/winetests/setupapi/query.c
Normal file
248
reactos/regtests/winetests/setupapi/query.c
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* Unit tests for setupapi.dll query functions
|
||||
*
|
||||
* Copyright (C) 2006 James Hawkins
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
#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;
|
||||
|
||||
GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
|
||||
len = lstrlenA(CURR_DIR);
|
||||
|
||||
if(len && (CURR_DIR[len-1] == '\\'))
|
||||
CURR_DIR[len-1] = 0;
|
||||
|
||||
GetWindowsDirectoryA(WIN_DIR, MAX_PATH);
|
||||
len = lstrlenA(WIN_DIR);
|
||||
|
||||
if (len && (WIN_DIR[len-1] == '\\'))
|
||||
WIN_DIR[len-1] = 0;
|
||||
}
|
||||
|
||||
static void append_str(char **str, const char *data)
|
||||
{
|
||||
sprintf(*str, data);
|
||||
*str += strlen(*str);
|
||||
}
|
||||
|
||||
static void create_inf_file(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, "[Version]\n");
|
||||
append_str(&ptr, "Signature=\"$Chicago$\"\n");
|
||||
append_str(&ptr, "AdvancedINF=2.5\n");
|
||||
|
||||
WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL);
|
||||
CloseHandle(hf);
|
||||
}
|
||||
|
||||
static BOOL check_info_filename(PSP_INF_INFORMATION info, LPSTR test)
|
||||
{
|
||||
LPSTR filename;
|
||||
DWORD size;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (!pSetupQueryInfFileInformationA(info, 0, NULL, 0, &size))
|
||||
return FALSE;
|
||||
|
||||
filename = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
if (!filename)
|
||||
return FALSE;
|
||||
|
||||
pSetupQueryInfFileInformationA(info, 0, filename, size, &size);
|
||||
|
||||
if (!lstrcmpiA(test, filename))
|
||||
ret = TRUE;
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PSP_INF_INFORMATION alloc_inf_info(LPSTR filename, DWORD search, PDWORD size)
|
||||
{
|
||||
PSP_INF_INFORMATION info;
|
||||
BOOL ret;
|
||||
|
||||
ret = pSetupGetInfInformationA(filename, search, NULL, 0, size);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
info = HeapAlloc(GetProcessHeap(), 0, *size);
|
||||
return info;
|
||||
}
|
||||
|
||||
static void test_SetupGetInfInformation(void)
|
||||
{
|
||||
PSP_INF_INFORMATION info;
|
||||
CHAR inf_filename[MAX_PATH];
|
||||
CHAR inf_one[MAX_PATH], inf_two[MAX_PATH];
|
||||
DWORD size;
|
||||
HINF hinf;
|
||||
BOOL ret;
|
||||
|
||||
lstrcpyA(inf_filename, CURR_DIR);
|
||||
lstrcatA(inf_filename, "\\");
|
||||
lstrcatA(inf_filename, "test.inf");
|
||||
|
||||
/* try an invalid inf handle */
|
||||
size = 0xdeadbeef;
|
||||
SetLastError(0xbeefcafe);
|
||||
ret = pSetupGetInfInformationA(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());
|
||||
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);
|
||||
ok(ret == FALSE, "Expected SetupGetInfInformation to fail\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
|
||||
ok(size == 0xdeadbeef, "Expected size to remain unchanged\n");
|
||||
|
||||
create_inf_file(inf_filename);
|
||||
|
||||
/* try an invalid search flag */
|
||||
size = 0xdeadbeef;
|
||||
SetLastError(0xbeefcafe);
|
||||
ret = pSetupGetInfInformationA(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());
|
||||
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);
|
||||
ok(ret == FALSE, "Expected SetupGetInfInformation to fail\n");
|
||||
ok(GetLastError() == ERROR_FILE_NOT_FOUND,
|
||||
"Expected ERROR_FILE_NOT_FOUND, got %ld\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);
|
||||
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 */
|
||||
SetLastError(0xbeefcafe);
|
||||
ret = pSetupGetInfInformationA(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());
|
||||
|
||||
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);
|
||||
ok(ret == FALSE, "Expected SetupGetInfInformation to fail\n");
|
||||
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
|
||||
"Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
|
||||
|
||||
/* successfully get the inf information */
|
||||
ret = pSetupGetInfInformationA(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);
|
||||
info = alloc_inf_info(hinf, INFINFO_INF_SPEC_IS_HINF, &size);
|
||||
ret = pSetupGetInfInformationA(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);
|
||||
|
||||
lstrcpyA(inf_one, WIN_DIR);
|
||||
lstrcatA(inf_one, "\\inf\\");
|
||||
lstrcatA(inf_one, "test.inf");
|
||||
create_inf_file(inf_one);
|
||||
|
||||
lstrcpyA(inf_two, WIN_DIR);
|
||||
lstrcatA(inf_two, "\\system32\\");
|
||||
lstrcatA(inf_two, "test.inf");
|
||||
create_inf_file(inf_two);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, info);
|
||||
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);
|
||||
ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n");
|
||||
ok(check_info_filename(info, inf_one), "Expected returned filename to be equal\n");
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, info);
|
||||
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);
|
||||
ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n");
|
||||
ok(check_info_filename(info, inf_two), "Expected returned filename to be equal\n");
|
||||
|
||||
DeleteFileA(inf_filename);
|
||||
DeleteFileA(inf_one);
|
||||
DeleteFileA(inf_two);
|
||||
}
|
||||
|
||||
START_TEST(query)
|
||||
{
|
||||
init_function_pointers();
|
||||
get_directories();
|
||||
|
||||
test_SetupGetInfInformation();
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
<define name="__USE_W32API" />
|
||||
<library>ntdll</library>
|
||||
<library>setupapi</library>
|
||||
<file>testlist.c</file>
|
||||
<file>parser.c</file>
|
||||
<file>query.c</file>
|
||||
<file>stringtable.c</file>
|
||||
<file>testlist.c</file>
|
||||
</module>
|
||||
|
|
|
@ -15,11 +15,10 @@
|
|||
*
|
||||
* 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
|
||||
*/
|
||||
/*
|
||||
* TODO:
|
||||
* Add case sensitivity test for StringTableAddString/StringTableLookupString
|
||||
* Add test for StringTableStringFromIdEx
|
||||
*/
|
||||
|
||||
|
@ -48,9 +47,12 @@ static VOID (WINAPI *pStringTableTrim)(HSTRING_TABLE);
|
|||
|
||||
HMODULE hdll;
|
||||
static WCHAR string[] = {'s','t','r','i','n','g',0};
|
||||
static WCHAR String[] = {'S','t','r','i','n','g',0};
|
||||
static WCHAR foo[] = {'f','o','o',0};
|
||||
DWORD hstring, hString, hfoo; /* Handles pointing to our strings */
|
||||
HANDLE table, table2; /* Handles pointing to our tables */
|
||||
|
||||
static void load_it_up()
|
||||
static void load_it_up(void)
|
||||
{
|
||||
hdll = LoadLibraryA("setupapi.dll");
|
||||
if (!hdll)
|
||||
|
@ -81,38 +83,78 @@ static void load_it_up()
|
|||
pStringTableStringFromId = (void*)GetProcAddress(hdll, "pSetupStringTableStringFromId");
|
||||
}
|
||||
|
||||
static void test_StringTableInitialize()
|
||||
static void test_StringTableInitialize(void)
|
||||
{
|
||||
table=pStringTableInitialize();
|
||||
ok(table!=NULL,"Failed to Initialize String Table\n");
|
||||
}
|
||||
|
||||
static void test_StringTableAddString()
|
||||
static void test_StringTableAddString(void)
|
||||
{
|
||||
DWORD retval;
|
||||
|
||||
retval=pStringTableAddString(table,string,0);
|
||||
ok(retval!=-1,"Failed to add string to String Table\n");
|
||||
/* 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);
|
||||
|
||||
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 */
|
||||
hString=pStringTableAddString(table,String,ST_CASE_SENSITIVE_COMPARE);
|
||||
ok(hstring!=hString,"String handle and string share same ID %lx in Table\n", hstring);
|
||||
}
|
||||
|
||||
static void test_StringTableDuplicate()
|
||||
static void test_StringTableDuplicate(void)
|
||||
{
|
||||
table2=pStringTableDuplicate(table);
|
||||
ok(table2!=NULL,"Failed to duplicate String Table\n");
|
||||
}
|
||||
|
||||
static void test_StringTableLookUpString()
|
||||
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);
|
||||
|
||||
retval2=pStringTableLookUpString(table2,string,0);
|
||||
ok(retval2!=-1,"Failed find string in String Table 2\n");
|
||||
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");
|
||||
|
||||
retval=pStringTableLookUpString(table,foo,0);
|
||||
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);
|
||||
|
||||
retval=pStringTableLookUpString(table2,foo,0);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
static void test_StringTableStringFromId()
|
||||
static void test_StringTableStringFromId(void)
|
||||
{
|
||||
WCHAR *string2, *string3;
|
||||
int result;
|
||||
|
@ -122,16 +164,14 @@ static void test_StringTableStringFromId()
|
|||
ok(string2!=NULL,"Failed to look up string by ID from String Table\n");
|
||||
|
||||
result=lstrcmpiW(string, string2);
|
||||
ok(result==0,"String %p does not match requested StringID %p\n",string,string2);
|
||||
ok(result==0,"StringID %p does not match requested StringID %p\n",string,string2);
|
||||
|
||||
todo_wine{
|
||||
/* This should not pass on Wine but it does */
|
||||
string3=pStringTableStringFromId(table,0);
|
||||
ok(string3!=NULL,"Failed to look up string by ID from String Table\n");
|
||||
/* This should never work */
|
||||
string3=pStringTableStringFromId(table,0);
|
||||
ok(string3!=NULL,"Failed to look up string by ID from String Table\n");
|
||||
|
||||
result=lstrcmpiW(string, string3);
|
||||
ok(result!=0,"String %p does not match requested StringID %p\n",string,string2);
|
||||
}
|
||||
result=lstrcmpiW(string, string3);
|
||||
ok(result!=0,"StringID %p matches requested StringID %p\n",string,string3);
|
||||
}
|
||||
|
||||
START_TEST(stringtable)
|
||||
|
|
|
@ -12,8 +12,8 @@ extern void func_stringtable(void);
|
|||
|
||||
const struct test winetest_testlist[] =
|
||||
{
|
||||
// { "parser", func_parser },
|
||||
// { "query", func_query },
|
||||
{ "parser", func_parser },
|
||||
{ "query", func_query },
|
||||
{ "stringtable", func_stringtable },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
/*
|
||||
* Synchronization tests
|
||||
*
|
||||
* Copyright 2005 Mike McCormack 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 <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
static void test_signalandwait(void)
|
||||
{
|
||||
DWORD (WINAPI *pSignalObjectAndWait)(HANDLE, HANDLE, DWORD, BOOL);
|
||||
HMODULE kernel32;
|
||||
DWORD r;
|
||||
int i;
|
||||
HANDLE event[2], maxevents[MAXIMUM_WAIT_OBJECTS], semaphore[2], file;
|
||||
|
||||
kernel32 = GetModuleHandle("kernel32");
|
||||
pSignalObjectAndWait = (void*) GetProcAddress(kernel32, "SignalObjectAndWait");
|
||||
|
||||
if (!pSignalObjectAndWait)
|
||||
return;
|
||||
|
||||
/* invalid parameters */
|
||||
r = pSignalObjectAndWait(NULL, NULL, 0, 0);
|
||||
if (r == ERROR_INVALID_FUNCTION)
|
||||
{
|
||||
trace("SignalObjectAndWait not implemented, skipping tests\n");
|
||||
return; /* Win98/ME */
|
||||
}
|
||||
ok( r == WAIT_FAILED, "should fail\n");
|
||||
|
||||
event[0] = CreateEvent(NULL, 0, 0, NULL);
|
||||
event[1] = CreateEvent(NULL, 1, 1, NULL);
|
||||
|
||||
ok( event[0] && event[1], "failed to create event flags\n");
|
||||
|
||||
r = pSignalObjectAndWait(event[0], NULL, 0, FALSE);
|
||||
ok( r == WAIT_FAILED, "should fail\n");
|
||||
|
||||
r = pSignalObjectAndWait(NULL, event[0], 0, FALSE);
|
||||
ok( r == WAIT_FAILED, "should fail\n");
|
||||
|
||||
|
||||
/* valid parameters */
|
||||
r = pSignalObjectAndWait(event[0], event[1], 0, FALSE);
|
||||
ok( r == WAIT_OBJECT_0, "should succeed\n");
|
||||
|
||||
/* event[0] is now signalled */
|
||||
r = pSignalObjectAndWait(event[0], event[0], 0, FALSE);
|
||||
ok( r == WAIT_OBJECT_0, "should succeed\n");
|
||||
|
||||
/* event[0] is not signalled */
|
||||
r = WaitForSingleObject(event[0], 0);
|
||||
ok( r == WAIT_TIMEOUT, "event was signalled\n");
|
||||
|
||||
r = pSignalObjectAndWait(event[0], event[0], 0, FALSE);
|
||||
ok( r == WAIT_OBJECT_0, "should succeed\n");
|
||||
|
||||
/* clear event[1] and check for a timeout */
|
||||
ok(ResetEvent(event[1]), "failed to clear event[1]\n");
|
||||
r = pSignalObjectAndWait(event[0], event[1], 0, FALSE);
|
||||
ok( r == WAIT_TIMEOUT, "should timeout\n");
|
||||
|
||||
CloseHandle(event[0]);
|
||||
CloseHandle(event[1]);
|
||||
|
||||
/* create the maximum number of events and make sure
|
||||
* we can wait on that many */
|
||||
for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
|
||||
{
|
||||
maxevents[i] = CreateEvent(NULL, 1, 1, NULL);
|
||||
ok( maxevents[i] != 0, "should create enough events\n");
|
||||
}
|
||||
r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
|
||||
ok( r != WAIT_FAILED && r != WAIT_TIMEOUT, "should succeed\n");
|
||||
|
||||
for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
|
||||
if (maxevents[i]) CloseHandle(maxevents[i]);
|
||||
|
||||
/* semaphores */
|
||||
semaphore[0] = CreateSemaphore( NULL, 0, 1, NULL );
|
||||
semaphore[1] = CreateSemaphore( NULL, 1, 1, NULL );
|
||||
ok( semaphore[0] && semaphore[1], "failed to create semaphore\n");
|
||||
|
||||
r = pSignalObjectAndWait(semaphore[0], semaphore[1], 0, FALSE);
|
||||
ok( r == WAIT_OBJECT_0, "should succeed\n");
|
||||
|
||||
r = pSignalObjectAndWait(semaphore[0], semaphore[1], 0, FALSE);
|
||||
ok( r == WAIT_FAILED, "should fail\n");
|
||||
|
||||
r = ReleaseSemaphore(semaphore[0],1,NULL);
|
||||
ok( r == FALSE, "should fail\n");
|
||||
|
||||
r = ReleaseSemaphore(semaphore[1],1,NULL);
|
||||
ok( r == TRUE, "should succeed\n");
|
||||
|
||||
CloseHandle(semaphore[0]);
|
||||
CloseHandle(semaphore[1]);
|
||||
|
||||
/* try a registry key */
|
||||
file = CreateFile("x", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
|
||||
r = pSignalObjectAndWait(file, file, 0, FALSE);
|
||||
ok( r == WAIT_FAILED, "should fail\n");
|
||||
ok( ERROR_INVALID_HANDLE == GetLastError(), "should return invalid handle error\n");
|
||||
CloseHandle(file);
|
||||
}
|
||||
|
||||
START_TEST(sync)
|
||||
{
|
||||
test_signalandwait();
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/* Automatically generated file; DO NOT EDIT!! */
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#define STANDALONE
|
||||
#include "wine/test.h"
|
||||
|
||||
extern void func_alloc(void);
|
||||
extern void func_atom(void);
|
||||
extern void func_change(void);
|
||||
extern void func_codepage(void);
|
||||
extern void func_comm(void);
|
||||
extern void func_console(void);
|
||||
extern void func_directory(void);
|
||||
extern void func_drive(void);
|
||||
extern void func_environ(void);
|
||||
extern void func_file(void);
|
||||
extern void func_format_msg(void);
|
||||
extern void func_generated(void);
|
||||
extern void func_heap(void);
|
||||
extern void func_locale(void);
|
||||
extern void func_module(void);
|
||||
extern void func_mailslot(void);
|
||||
extern void func_path(void);
|
||||
extern void func_pipe(void);
|
||||
extern void func_process(void);
|
||||
extern void func_profile(void);
|
||||
extern void func_sync(void);
|
||||
extern void func_thread(void);
|
||||
extern void func_time(void);
|
||||
extern void func_timer(void);
|
||||
extern void func_toolhelp(void);
|
||||
extern void func_virtual(void);
|
||||
extern void func_volume(void);
|
||||
|
||||
const struct test winetest_testlist[] =
|
||||
{
|
||||
{ "alloc", func_alloc },
|
||||
{ "atom", func_atom },
|
||||
{ "change", func_change },
|
||||
{ "codepage", func_codepage },
|
||||
{ "comm", func_comm },
|
||||
{ "console", func_console },
|
||||
{ "directory", func_directory },
|
||||
{ "drive", func_drive },
|
||||
{ "environ", func_environ },
|
||||
{ "file", func_file },
|
||||
{ "format_msg", func_format_msg },
|
||||
{ "generated", func_generated },
|
||||
{ "heap", func_heap },
|
||||
{ "locale", func_locale },
|
||||
{ "module", func_module },
|
||||
{ "mailslot", func_mailslot },
|
||||
{ "path", func_path },
|
||||
{ "pipe", func_pipe },
|
||||
{ "process", func_process },
|
||||
{ "profile", func_profile },
|
||||
{ "sync", func_sync },
|
||||
{ "thread", func_thread },
|
||||
{ "time", func_time },
|
||||
{ "timer", func_timer },
|
||||
{ "toolhelp", func_toolhelp },
|
||||
{ "virtual", func_virtual },
|
||||
{ "volume", func_volume },
|
||||
{ 0, 0 }
|
||||
};
|
|
@ -1,749 +0,0 @@
|
|||
/*
|
||||
* Unit test suite for directory functions.
|
||||
*
|
||||
* Copyright 2002 Geoffrey Hausheer
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */
|
||||
#define _WIN32_WINNT 0x0500
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "wine/test.h"
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winnt.h>
|
||||
#include <winerror.h>
|
||||
|
||||
/* Specify the number of simultaneous threads to test */
|
||||
#define NUM_THREADS 4
|
||||
/* Specify whether to test the extended priorities for Win2k/XP */
|
||||
#define USE_EXTENDED_PRIORITIES 0
|
||||
/* Specify whether to test the stack allocation in CreateThread */
|
||||
#define CHECK_STACK 0
|
||||
|
||||
/* Set CHECK_STACK to 1 if you want to try to test the stack-limit from
|
||||
CreateThread. So far I have been unable to make this work, and
|
||||
I am in doubt as to how portable it is. Also, according to MSDN,
|
||||
you shouldn't mix C-run-time-libraries (i.e. alloca) with CreateThread.
|
||||
Anyhow, the check is currently commented out
|
||||
*/
|
||||
#if CHECK_STACK
|
||||
# ifdef __try
|
||||
# define __TRY __try
|
||||
# define __EXCEPT __except
|
||||
# define __ENDTRY
|
||||
# else
|
||||
# include "wine/exception.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef BOOL (WINAPI *GetThreadPriorityBoost_t)(HANDLE,PBOOL);
|
||||
static GetThreadPriorityBoost_t pGetThreadPriorityBoost=NULL;
|
||||
|
||||
typedef HANDLE (WINAPI *OpenThread_t)(DWORD,BOOL,DWORD);
|
||||
static OpenThread_t pOpenThread=NULL;
|
||||
|
||||
typedef BOOL (WINAPI *QueueUserWorkItem_t)(LPTHREAD_START_ROUTINE,PVOID,ULONG);
|
||||
static QueueUserWorkItem_t pQueueUserWorkItem=NULL;
|
||||
|
||||
typedef DWORD (WINAPI *SetThreadIdealProcessor_t)(HANDLE,DWORD);
|
||||
static SetThreadIdealProcessor_t pSetThreadIdealProcessor=NULL;
|
||||
|
||||
typedef BOOL (WINAPI *SetThreadPriorityBoost_t)(HANDLE,BOOL);
|
||||
static SetThreadPriorityBoost_t pSetThreadPriorityBoost=NULL;
|
||||
|
||||
/* Functions not tested yet:
|
||||
AttachThreadInput
|
||||
CreateRemoteThread
|
||||
SetThreadContext
|
||||
SwitchToThread
|
||||
|
||||
In addition there are no checks that the inheritance works properly in
|
||||
CreateThread
|
||||
*/
|
||||
|
||||
DWORD tlsIndex;
|
||||
|
||||
typedef struct {
|
||||
int threadnum;
|
||||
HANDLE *event;
|
||||
DWORD *threadmem;
|
||||
} t1Struct;
|
||||
|
||||
/* WinME supports OpenThread but doesn't know about access restrictions so
|
||||
we require them to be either completely ignored or always obeyed.
|
||||
*/
|
||||
INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */
|
||||
#define obey_ar(x) \
|
||||
(obeying_ars == 0 \
|
||||
? ((x) \
|
||||
? (obeying_ars = +1) \
|
||||
: ((obeying_ars = -1), \
|
||||
trace("not restricted, assuming consistent behaviour\n"))) \
|
||||
: (obeying_ars < 0) \
|
||||
? ok(!(x), "access restrictions obeyed\n") \
|
||||
: ok( (x), "access restrictions not obeyed\n"))
|
||||
|
||||
/* Basic test that simultaneous threads can access shared memory,
|
||||
that the thread local storage routines work correctly, and that
|
||||
threads actually run concurrently
|
||||
*/
|
||||
static DWORD WINAPI threadFunc1(LPVOID p)
|
||||
{
|
||||
t1Struct *tstruct = (t1Struct *)p;
|
||||
int i;
|
||||
/* write our thread # into shared memory */
|
||||
tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId();
|
||||
ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0,
|
||||
"TlsSetValue failed\n");
|
||||
/* The threads synchronize before terminating. This is done by
|
||||
Signaling an event, and waiting for all events to occur
|
||||
*/
|
||||
SetEvent(tstruct->event[tstruct->threadnum]);
|
||||
WaitForMultipleObjects(NUM_THREADS,tstruct->event,TRUE,INFINITE);
|
||||
/* Double check that all threads really did run by validating that
|
||||
they have all written to the shared memory. There should be no race
|
||||
here, since all threads were synchronized after the write.*/
|
||||
for(i=0;i<NUM_THREADS;i++) {
|
||||
while(tstruct->threadmem[i]==0) ;
|
||||
}
|
||||
|
||||
/* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
|
||||
ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
|
||||
|
||||
/* Check that noone changed our tls memory */
|
||||
ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
|
||||
"TlsGetValue failed\n");
|
||||
return NUM_THREADS+tstruct->threadnum;
|
||||
}
|
||||
|
||||
static DWORD WINAPI threadFunc2(LPVOID p)
|
||||
{
|
||||
return 99;
|
||||
}
|
||||
|
||||
static DWORD WINAPI threadFunc3(LPVOID p)
|
||||
{
|
||||
HANDLE thread;
|
||||
thread=GetCurrentThread();
|
||||
SuspendThread(thread);
|
||||
return 99;
|
||||
}
|
||||
|
||||
static DWORD WINAPI threadFunc4(LPVOID p)
|
||||
{
|
||||
HANDLE event = (HANDLE)p;
|
||||
if(event != NULL) {
|
||||
SetEvent(event);
|
||||
}
|
||||
Sleep(99000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CHECK_STACK
|
||||
static DWORD WINAPI threadFunc5(LPVOID p)
|
||||
{
|
||||
DWORD *exitCode = (DWORD *)p;
|
||||
SYSTEM_INFO sysInfo;
|
||||
sysInfo.dwPageSize=0;
|
||||
GetSystemInfo(&sysInfo);
|
||||
*exitCode=0;
|
||||
__TRY
|
||||
{
|
||||
alloca(2*sysInfo.dwPageSize);
|
||||
}
|
||||
__EXCEPT(1) {
|
||||
*exitCode=1;
|
||||
}
|
||||
__ENDTRY
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check basic funcationality of CreateThread and Tls* functions */
|
||||
static VOID test_CreateThread_basic(void)
|
||||
{
|
||||
HANDLE thread[NUM_THREADS],event[NUM_THREADS];
|
||||
DWORD threadid[NUM_THREADS],curthreadId;
|
||||
DWORD threadmem[NUM_THREADS];
|
||||
DWORD exitCode;
|
||||
t1Struct tstruct[NUM_THREADS];
|
||||
int error;
|
||||
DWORD i,j;
|
||||
DWORD GLE, ret;
|
||||
|
||||
/* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
|
||||
ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
|
||||
|
||||
/* Retrieve current Thread ID for later comparisons */
|
||||
curthreadId=GetCurrentThreadId();
|
||||
/* Allocate some local storage */
|
||||
ok((tlsIndex=TlsAlloc())!=TLS_OUT_OF_INDEXES,"TlsAlloc failed\n");
|
||||
/* Create events for thread synchronization */
|
||||
for(i=0;i<NUM_THREADS;i++) {
|
||||
threadmem[i]=0;
|
||||
/* Note that it doesn't matter what type of event we chose here. This
|
||||
test isn't trying to thoroughly test events
|
||||
*/
|
||||
event[i]=CreateEventA(NULL,TRUE,FALSE,NULL);
|
||||
tstruct[i].threadnum=i;
|
||||
tstruct[i].threadmem=threadmem;
|
||||
tstruct[i].event=event;
|
||||
}
|
||||
|
||||
/* Test that passing arguments to threads works okay */
|
||||
for(i=0;i<NUM_THREADS;i++) {
|
||||
thread[i] = CreateThread(NULL,0,threadFunc1,
|
||||
&tstruct[i],0,&threadid[i]);
|
||||
ok(thread[i]!=NULL,"Create Thread failed\n");
|
||||
}
|
||||
/* Test that the threads actually complete */
|
||||
for(i=0;i<NUM_THREADS;i++) {
|
||||
error=WaitForSingleObject(thread[i],5000);
|
||||
ok(error==WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
|
||||
if(error!=WAIT_OBJECT_0) {
|
||||
TerminateThread(thread[i],i+NUM_THREADS);
|
||||
}
|
||||
ok(GetExitCodeThread(thread[i],&exitCode),"Could not retrieve ext code\n");
|
||||
ok(exitCode==i+NUM_THREADS,"Thread returned an incorrect exit code\n");
|
||||
}
|
||||
/* Test that each thread executed in its parent's address space
|
||||
(it was able to change threadmem and pass that change back to its parent)
|
||||
and that each thread id was independant). Note that we prove that the
|
||||
threads actually execute concurrently by having them block on each other
|
||||
in threadFunc1
|
||||
*/
|
||||
for(i=0;i<NUM_THREADS;i++) {
|
||||
error=0;
|
||||
for(j=i+1;j<NUM_THREADS;j++) {
|
||||
if (threadmem[i]==threadmem[j]) {
|
||||
error=1;
|
||||
}
|
||||
}
|
||||
ok(!error && threadmem[i]==threadid[i] && threadmem[i]!=curthreadId,
|
||||
"Thread did not execute successfully\n");
|
||||
ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
|
||||
}
|
||||
ok(TlsFree(tlsIndex)!=0,"TlsFree failed\n");
|
||||
|
||||
/* Test how passing NULL as a pointer to threadid works */
|
||||
SetLastError(0xFACEaBAD);
|
||||
thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,NULL);
|
||||
GLE = GetLastError();
|
||||
if (thread[0]) { /* NT */
|
||||
ok(GLE==0xFACEaBAD, "CreateThread set last error to %ld, expected 4207848365\n", GLE);
|
||||
ret = WaitForSingleObject(thread[0],100);
|
||||
ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
|
||||
ret = GetExitCodeThread(thread[0],&exitCode);
|
||||
ok(ret!=0, "GetExitCodeThread returned %ld (expected nonzero)\n", ret);
|
||||
ok(exitCode==99, "threadFunc2 exited with code: %ld (expected 99)\n", exitCode);
|
||||
ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n");
|
||||
}
|
||||
else { /* 9x */
|
||||
ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %ld, expected 87\n", GLE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that using the CREATE_SUSPENDED flag works */
|
||||
static VOID test_CreateThread_suspended(void)
|
||||
{
|
||||
HANDLE thread;
|
||||
DWORD threadId;
|
||||
int error;
|
||||
|
||||
thread = CreateThread(NULL,0,threadFunc2,NULL,
|
||||
CREATE_SUSPENDED,&threadId);
|
||||
ok(thread!=NULL,"Create Thread failed\n");
|
||||
/* Check that the thread is suspended */
|
||||
ok(SuspendThread(thread)==1,"Thread did not start suspended\n");
|
||||
ok(ResumeThread(thread)==2,"Resume thread returned an invalid value\n");
|
||||
/* Check that resume thread didn't actually start the thread. I can't think
|
||||
of a better way of checking this than just waiting. I am not sure if this
|
||||
will work on slow computers.
|
||||
*/
|
||||
ok(WaitForSingleObject(thread,1000)==WAIT_TIMEOUT,
|
||||
"ResumeThread should not have actually started the thread\n");
|
||||
/* Now actually resume the thread and make sure that it actually completes*/
|
||||
ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
|
||||
ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
|
||||
"Thread did not resume\n");
|
||||
if(error!=WAIT_OBJECT_0) {
|
||||
TerminateThread(thread,1);
|
||||
}
|
||||
ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
|
||||
}
|
||||
|
||||
/* Check that SuspendThread and ResumeThread work */
|
||||
static VOID test_SuspendThread(void)
|
||||
{
|
||||
HANDLE thread,access_thread;
|
||||
DWORD threadId,exitCode,error;
|
||||
int i;
|
||||
|
||||
thread = CreateThread(NULL,0,threadFunc3,NULL,
|
||||
0,&threadId);
|
||||
ok(thread!=NULL,"Create Thread failed\n");
|
||||
/* Check that the thread is suspended */
|
||||
/* Note that this is a polling method, and there is a race between
|
||||
SuspendThread being called (in the child, and the loop below timing out,
|
||||
so the test could fail on a heavily loaded or slow computer.
|
||||
*/
|
||||
error=0;
|
||||
for(i=0;error==0 && i<100;i++) {
|
||||
error=SuspendThread(thread);
|
||||
ResumeThread(thread);
|
||||
if(error==0) {
|
||||
Sleep(50);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
ok(error==1,"SuspendThread did not work\n");
|
||||
/* check that access restrictions are obeyed */
|
||||
if (pOpenThread) {
|
||||
access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_SUSPEND_RESUME),
|
||||
0,threadId);
|
||||
ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
|
||||
if (access_thread!=NULL) {
|
||||
obey_ar(SuspendThread(access_thread)==~0U);
|
||||
obey_ar(ResumeThread(access_thread)==~0U);
|
||||
ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
|
||||
}
|
||||
}
|
||||
/* Double check that the thread really is suspended */
|
||||
ok((error=GetExitCodeThread(thread,&exitCode))!=0 && exitCode==STILL_ACTIVE,
|
||||
"Thread did not really suspend\n");
|
||||
/* Resume the thread, and make sure it actually completes */
|
||||
ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
|
||||
ok((error=WaitForSingleObject(thread,1000))==WAIT_OBJECT_0,
|
||||
"Thread did not resume\n");
|
||||
if(error!=WAIT_OBJECT_0) {
|
||||
TerminateThread(thread,1);
|
||||
}
|
||||
/* Trying to suspend a terminated thread should fail */
|
||||
error=SuspendThread(thread);
|
||||
ok(error==~0U, "wrong return code: %ld\n", error);
|
||||
ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %ld\n", GetLastError());
|
||||
|
||||
ok(CloseHandle(thread)!=0,"CloseHandle Failed\n");
|
||||
}
|
||||
|
||||
/* Check that TerminateThread works properly
|
||||
*/
|
||||
static VOID test_TerminateThread(void)
|
||||
{
|
||||
HANDLE thread,access_thread,event;
|
||||
DWORD threadId,exitCode;
|
||||
event=CreateEventA(NULL,TRUE,FALSE,NULL);
|
||||
thread = CreateThread(NULL,0,threadFunc4,
|
||||
(LPVOID)event, 0,&threadId);
|
||||
ok(thread!=NULL,"Create Thread failed\n");
|
||||
/* TerminateThread has a race condition in Wine. If the thread is terminated
|
||||
before it starts, it leaves a process behind. Therefore, we wait for the
|
||||
thread to signal that it has started. There is no easy way to force the
|
||||
race to occur, so we don't try to find it.
|
||||
*/
|
||||
ok(WaitForSingleObject(event,5000)==WAIT_OBJECT_0,
|
||||
"TerminateThread didn't work\n");
|
||||
/* check that access restrictions are obeyed */
|
||||
if (pOpenThread) {
|
||||
access_thread=pOpenThread(THREAD_ALL_ACCESS & (~THREAD_TERMINATE),
|
||||
0,threadId);
|
||||
ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
|
||||
if (access_thread!=NULL) {
|
||||
obey_ar(TerminateThread(access_thread,99)==0);
|
||||
ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
|
||||
}
|
||||
}
|
||||
/* terminate a job and make sure it terminates */
|
||||
ok(TerminateThread(thread,99)!=0,"TerminateThread failed\n");
|
||||
ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
|
||||
"TerminateThread didn't work\n");
|
||||
ok(GetExitCodeThread(thread,&exitCode)!=STILL_ACTIVE,
|
||||
"TerminateThread should not leave the thread 'STILL_ACTIVE'\n");
|
||||
ok(exitCode==99, "TerminateThread returned invalid exit code\n");
|
||||
ok(CloseHandle(thread)!=0,"Error Closing thread handle\n");
|
||||
}
|
||||
|
||||
/* Check if CreateThread obeys the specified stack size. This code does
|
||||
not work properly, and is currently disabled
|
||||
*/
|
||||
static VOID test_CreateThread_stack(void)
|
||||
{
|
||||
#if CHECK_STACK
|
||||
/* The only way I know of to test the stack size is to use alloca
|
||||
and __try/__except. However, this is probably not portable,
|
||||
and I couldn't get it to work under Wine anyhow. However, here
|
||||
is the code which should allow for testing that CreateThread
|
||||
respects the stack-size limit
|
||||
*/
|
||||
HANDLE thread;
|
||||
DWORD threadId,exitCode;
|
||||
|
||||
SYSTEM_INFO sysInfo;
|
||||
sysInfo.dwPageSize=0;
|
||||
GetSystemInfo(&sysInfo);
|
||||
ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n");
|
||||
thread = CreateThread(NULL,sysInfo.dwPageSize,
|
||||
threadFunc5,&exitCode,
|
||||
0,&threadId);
|
||||
ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
|
||||
"TerminateThread didn't work\n");
|
||||
ok(exitCode==1,"CreateThread did not obey stack-size-limit\n");
|
||||
ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check whether setting/retrieving thread priorities works */
|
||||
static VOID test_thread_priority(void)
|
||||
{
|
||||
HANDLE curthread,access_thread;
|
||||
DWORD curthreadId,exitCode;
|
||||
int min_priority=-2,max_priority=2;
|
||||
BOOL disabled,rc;
|
||||
int i;
|
||||
|
||||
curthread=GetCurrentThread();
|
||||
curthreadId=GetCurrentThreadId();
|
||||
/* Check thread priority */
|
||||
/* NOTE: on Win2k/XP priority can be from -7 to 6. All other platforms it
|
||||
is -2 to 2. However, even on a real Win2k system, using thread
|
||||
priorities beyond the -2 to 2 range does not work. If you want to try
|
||||
anyway, enable USE_EXTENDED_PRIORITIES
|
||||
*/
|
||||
ok(GetThreadPriority(curthread)==THREAD_PRIORITY_NORMAL,
|
||||
"GetThreadPriority Failed\n");
|
||||
|
||||
if (pOpenThread) {
|
||||
/* check that access control is obeyed */
|
||||
access_thread=pOpenThread(THREAD_ALL_ACCESS &
|
||||
(~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
|
||||
0,curthreadId);
|
||||
ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
|
||||
if (access_thread!=NULL) {
|
||||
obey_ar(SetThreadPriority(access_thread,1)==0);
|
||||
obey_ar(GetThreadPriority(access_thread)==THREAD_PRIORITY_ERROR_RETURN);
|
||||
obey_ar(GetExitCodeThread(access_thread,&exitCode)==0);
|
||||
ok(CloseHandle(access_thread),"Error Closing thread handle\n");
|
||||
}
|
||||
#if USE_EXTENDED_PRIORITIES
|
||||
min_priority=-7; max_priority=6;
|
||||
#endif
|
||||
}
|
||||
for(i=min_priority;i<=max_priority;i++) {
|
||||
ok(SetThreadPriority(curthread,i)!=0,
|
||||
"SetThreadPriority Failed for priority: %d\n",i);
|
||||
ok(GetThreadPriority(curthread)==i,
|
||||
"GetThreadPriority Failed for priority: %d\n",i);
|
||||
}
|
||||
ok(SetThreadPriority(curthread,THREAD_PRIORITY_TIME_CRITICAL)!=0,
|
||||
"SetThreadPriority Failed\n");
|
||||
ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
|
||||
"GetThreadPriority Failed\n");
|
||||
ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
|
||||
"SetThreadPriority Failed\n");
|
||||
ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
|
||||
"GetThreadPriority Failed\n");
|
||||
ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
|
||||
|
||||
/* Check thread priority boost */
|
||||
if (!pGetThreadPriorityBoost || !pSetThreadPriorityBoost)
|
||||
return; /* Win9x */
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
rc=pGetThreadPriorityBoost(curthread,&disabled);
|
||||
if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
|
||||
return; /* WinME */
|
||||
|
||||
/* check that access control is obeyed */
|
||||
access_thread=pOpenThread(THREAD_ALL_ACCESS &
|
||||
(~THREAD_QUERY_INFORMATION) & (~THREAD_SET_INFORMATION),
|
||||
0,curthreadId);
|
||||
ok(access_thread!=NULL,"OpenThread returned an invalid handle\n");
|
||||
if (access_thread!=NULL) {
|
||||
obey_ar(pSetThreadPriorityBoost(access_thread,1)==0);
|
||||
obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0);
|
||||
ok(CloseHandle(access_thread),"Error Closing thread handle\n");
|
||||
}
|
||||
|
||||
todo_wine {
|
||||
ok(rc!=0,"error=%ld\n",GetLastError());
|
||||
|
||||
rc = pSetThreadPriorityBoost(curthread,1);
|
||||
ok( rc != 0, "error=%ld\n",GetLastError());
|
||||
rc=pGetThreadPriorityBoost(curthread,&disabled);
|
||||
ok(rc!=0 && disabled==1,
|
||||
"rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled);
|
||||
|
||||
rc = pSetThreadPriorityBoost(curthread,0);
|
||||
ok( rc != 0, "error=%ld\n",GetLastError());
|
||||
rc=pGetThreadPriorityBoost(curthread,&disabled);
|
||||
ok(rc!=0 && disabled==0,
|
||||
"rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled);
|
||||
}
|
||||
}
|
||||
|
||||
/* check the GetThreadTimes function */
|
||||
static VOID test_GetThreadTimes(void)
|
||||
{
|
||||
HANDLE thread,access_thread=NULL;
|
||||
FILETIME creationTime,exitTime,kernelTime,userTime;
|
||||
DWORD threadId;
|
||||
int error;
|
||||
|
||||
thread = CreateThread(NULL,0,threadFunc2,NULL,
|
||||
CREATE_SUSPENDED,&threadId);
|
||||
|
||||
ok(thread!=NULL,"Create Thread failed\n");
|
||||
/* check that access control is obeyed */
|
||||
if (pOpenThread) {
|
||||
access_thread=pOpenThread(THREAD_ALL_ACCESS &
|
||||
(~THREAD_QUERY_INFORMATION), 0,threadId);
|
||||
ok(access_thread!=NULL,
|
||||
"OpenThread returned an invalid handle\n");
|
||||
}
|
||||
ok(ResumeThread(thread)==1,"Resume thread returned an invalid value\n");
|
||||
ok(WaitForSingleObject(thread,5000)==WAIT_OBJECT_0,
|
||||
"ResumeThread didn't work\n");
|
||||
creationTime.dwLowDateTime=99; creationTime.dwHighDateTime=99;
|
||||
exitTime.dwLowDateTime=99; exitTime.dwHighDateTime=99;
|
||||
kernelTime.dwLowDateTime=99; kernelTime.dwHighDateTime=99;
|
||||
userTime.dwLowDateTime=99; userTime.dwHighDateTime=99;
|
||||
/* GetThreadTimes should set all of the parameters passed to it */
|
||||
error=GetThreadTimes(thread,&creationTime,&exitTime,
|
||||
&kernelTime,&userTime);
|
||||
if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
|
||||
ok(error!=0,"GetThreadTimes failed\n");
|
||||
ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
|
||||
"creationTime was invalid\n");
|
||||
ok(exitTime.dwLowDateTime!=99 || exitTime.dwHighDateTime!=99,
|
||||
"exitTime was invalid\n");
|
||||
ok(kernelTime.dwLowDateTime!=99 || kernelTime.dwHighDateTime!=99,
|
||||
"kernelTimewas invalid\n");
|
||||
ok(userTime.dwLowDateTime!=99 || userTime.dwHighDateTime!=99,
|
||||
"userTime was invalid\n");
|
||||
ok(CloseHandle(thread)!=0,"CloseHandle failed\n");
|
||||
if(access_thread!=NULL)
|
||||
{
|
||||
error=GetThreadTimes(access_thread,&creationTime,&exitTime,
|
||||
&kernelTime,&userTime);
|
||||
obey_ar(error==0);
|
||||
}
|
||||
}
|
||||
if(access_thread!=NULL) {
|
||||
ok(CloseHandle(access_thread)!=0,"CloseHandle Failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the processor affinity functions */
|
||||
/* NOTE: These functions should also be checked that they obey access control
|
||||
*/
|
||||
static VOID test_thread_processor(void)
|
||||
{
|
||||
HANDLE curthread,curproc;
|
||||
DWORD processMask,systemMask;
|
||||
SYSTEM_INFO sysInfo;
|
||||
int error=0;
|
||||
|
||||
sysInfo.dwNumberOfProcessors=0;
|
||||
GetSystemInfo(&sysInfo);
|
||||
ok(sysInfo.dwNumberOfProcessors>0,
|
||||
"GetSystemInfo failed to return a valid # of processors\n");
|
||||
/* Use the current Thread/process for all tests */
|
||||
curthread=GetCurrentThread();
|
||||
ok(curthread!=NULL,"GetCurrentThread failed\n");
|
||||
curproc=GetCurrentProcess();
|
||||
ok(curproc!=NULL,"GetCurrentProcess failed\n");
|
||||
/* Check the Affinity Mask functions */
|
||||
ok(GetProcessAffinityMask(curproc,&processMask,&systemMask)!=0,
|
||||
"GetProcessAffinityMask failed\n");
|
||||
ok(SetThreadAffinityMask(curthread,processMask)==processMask,
|
||||
"SetThreadAffinityMask failed\n");
|
||||
ok(SetThreadAffinityMask(curthread,processMask+1)==0,
|
||||
"SetThreadAffinityMask passed for an illegal processor\n");
|
||||
/* NOTE: This only works on WinNT/2000/XP) */
|
||||
if (pSetThreadIdealProcessor) {
|
||||
todo_wine {
|
||||
SetLastError(0);
|
||||
error=pSetThreadIdealProcessor(curthread,0);
|
||||
if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
|
||||
ok(error!=-1, "SetThreadIdealProcessor failed\n");
|
||||
}
|
||||
}
|
||||
if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
|
||||
error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
|
||||
ok(error==-1,
|
||||
"SetThreadIdealProcessor succeeded with an illegal processor #\n");
|
||||
todo_wine {
|
||||
error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
|
||||
ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VOID test_GetThreadExitCode(void)
|
||||
{
|
||||
DWORD exitCode, threadid;
|
||||
DWORD GLE, ret;
|
||||
HANDLE thread;
|
||||
|
||||
ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode);
|
||||
ok(ret==0, "GetExitCodeThread returned non zero value: %ld\n", ret);
|
||||
GLE = GetLastError();
|
||||
ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %ld (expected 6)\n", GLE);
|
||||
|
||||
thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid);
|
||||
ret = WaitForSingleObject(thread,100);
|
||||
ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
|
||||
ret = GetExitCodeThread(thread,&exitCode);
|
||||
ok(ret==exitCode || ret==1,
|
||||
"GetExitCodeThread returned %ld (expected 1 or %ld)\n", ret, exitCode);
|
||||
ok(exitCode==99, "threadFunc2 exited with code %ld (expected 99)\n", exitCode);
|
||||
ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
static int test_value = 0;
|
||||
static HANDLE event;
|
||||
|
||||
static void WINAPI set_test_val( int val )
|
||||
{
|
||||
test_value += val;
|
||||
}
|
||||
|
||||
static DWORD WINAPI threadFunc6(LPVOID p)
|
||||
{
|
||||
SetEvent( event );
|
||||
Sleep( 1000 );
|
||||
test_value *= (int)p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_SetThreadContext(void)
|
||||
{
|
||||
CONTEXT ctx;
|
||||
int *stack;
|
||||
HANDLE thread;
|
||||
DWORD threadid;
|
||||
DWORD prevcount;
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
event = CreateEvent( NULL, TRUE, FALSE, NULL );
|
||||
thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid );
|
||||
ok( thread != NULL, "CreateThread failed : (%ld)\n", GetLastError() );
|
||||
if (!thread)
|
||||
{
|
||||
trace("Thread creation failed, skipping rest of test\n");
|
||||
return;
|
||||
}
|
||||
WaitForSingleObject( event, INFINITE );
|
||||
SuspendThread( thread );
|
||||
CloseHandle( event );
|
||||
|
||||
ctx.ContextFlags = CONTEXT_FULL;
|
||||
SetLastError(0xdeadbeef);
|
||||
ok( GetThreadContext( thread, &ctx ), "GetThreadContext failed : (%ld)\n", GetLastError() );
|
||||
|
||||
/* simulate a call to set_test_val(10) */
|
||||
stack = (int *)ctx.Esp;
|
||||
stack[-1] = 10;
|
||||
stack[-2] = ctx.Eip;
|
||||
ctx.Esp -= 2 * sizeof(int *);
|
||||
ctx.Eip = (DWORD)set_test_val;
|
||||
SetLastError(0xdeadbeef);
|
||||
ok( SetThreadContext( thread, &ctx ), "SetThreadContext failed : (%ld)\n", GetLastError() );
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
prevcount = ResumeThread( thread );
|
||||
ok ( prevcount == 1, "Previous suspend count (%ld) instead of 1, last error : (%ld)\n",
|
||||
prevcount, GetLastError() );
|
||||
|
||||
WaitForSingleObject( thread, INFINITE );
|
||||
ok( test_value == 20, "test_value %d instead of 20\n", test_value );
|
||||
}
|
||||
|
||||
#endif /* __i386__ */
|
||||
|
||||
static HANDLE finish_event;
|
||||
static LONG times_executed;
|
||||
|
||||
static DWORD CALLBACK work_function(void *p)
|
||||
{
|
||||
LONG executed = InterlockedIncrement(×_executed);
|
||||
|
||||
if (executed == 100)
|
||||
SetEvent(finish_event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_QueueUserWorkItem(void)
|
||||
{
|
||||
int i;
|
||||
DWORD wait_result;
|
||||
DWORD before, after;
|
||||
|
||||
/* QueueUserWorkItem not present on win9x */
|
||||
if (!pQueueUserWorkItem) return;
|
||||
|
||||
finish_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
before = GetTickCount();
|
||||
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT);
|
||||
ok(ret, "QueueUserWorkItem failed with error %ld\n", GetLastError());
|
||||
}
|
||||
|
||||
wait_result = WaitForSingleObject(finish_event, 10000);
|
||||
|
||||
after = GetTickCount();
|
||||
trace("100 QueueUserWorkItem calls took %ldms\n", after - before);
|
||||
ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%lx\n", wait_result);
|
||||
|
||||
ok(times_executed == 100, "didn't execute all of the work items\n");
|
||||
}
|
||||
|
||||
START_TEST(thread)
|
||||
{
|
||||
HINSTANCE lib;
|
||||
/* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
|
||||
so that the compile passes
|
||||
*/
|
||||
lib=GetModuleHandleA("kernel32.dll");
|
||||
ok(lib!=NULL,"Couldn't get a handle for kernel32.dll\n");
|
||||
pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
|
||||
pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
|
||||
pQueueUserWorkItem=(QueueUserWorkItem_t)GetProcAddress(lib,"QueueUserWorkItem");
|
||||
pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
|
||||
pSetThreadPriorityBoost=(SetThreadPriorityBoost_t)GetProcAddress(lib,"SetThreadPriorityBoost");
|
||||
test_CreateThread_basic();
|
||||
test_CreateThread_suspended();
|
||||
test_SuspendThread();
|
||||
test_TerminateThread();
|
||||
test_CreateThread_stack();
|
||||
test_thread_priority();
|
||||
test_GetThreadTimes();
|
||||
test_thread_processor();
|
||||
test_GetThreadExitCode();
|
||||
#ifdef __i386__
|
||||
test_SetThreadContext();
|
||||
#endif
|
||||
test_QueueUserWorkItem();
|
||||
}
|
|
@ -1,454 +0,0 @@
|
|||
/*
|
||||
* Unit test suite for time functions
|
||||
*
|
||||
* Copyright 2004 Uwe Bonnes
|
||||
*
|
||||
* 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 "wine/test.h"
|
||||
#include "winbase.h"
|
||||
|
||||
#define SECSPERMIN 60
|
||||
#define SECSPERDAY 86400
|
||||
/* 1601 to 1970 is 369 years plus 89 leap days */
|
||||
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
|
||||
#define TICKSPERSEC 10000000
|
||||
#define TICKSPERMSEC 10000
|
||||
#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
|
||||
|
||||
|
||||
#define NEWYEAR_1980_HI 0x01a8e79f
|
||||
#define NEWYEAR_1980_LO 0xe1d58000
|
||||
|
||||
#define MAYDAY_2002_HI 0x01c1f107
|
||||
#define MAYDAY_2002_LO 0xb82b6000
|
||||
|
||||
#define ATIME_HI 0x1c2349b
|
||||
#define ATIME_LOW 0x580716b0
|
||||
|
||||
#define LOCAL_ATIME_HI 0x01c23471
|
||||
#define LOCAL_ATIME_LOW 0x6f310eb0
|
||||
|
||||
#define DOS_DATE(y,m,d) ( (((y)-1980)<<9) | ((m)<<5) | (d) )
|
||||
#define DOS_TIME(h,m,s) ( ((h)<<11) | ((m)<<5) | ((s)>>1) )
|
||||
|
||||
|
||||
#define SETUP_1980(st) \
|
||||
(st).wYear = 1980; \
|
||||
(st).wMonth = 1; \
|
||||
(st).wDay = 1; \
|
||||
(st).wHour = 0; \
|
||||
(st).wMinute = 0; \
|
||||
(st).wSecond = 0; \
|
||||
(st).wMilliseconds = 0;
|
||||
|
||||
#define SETUP_2002(st) \
|
||||
(st).wYear = 2002; \
|
||||
(st).wMonth = 5; \
|
||||
(st).wDay = 1; \
|
||||
(st).wHour = 12; \
|
||||
(st).wMinute = 0; \
|
||||
(st).wSecond = 0; \
|
||||
(st).wMilliseconds = 0;
|
||||
|
||||
#define SETUP_ATIME(st) \
|
||||
(st).wYear = 2002; \
|
||||
(st).wMonth = 7; \
|
||||
(st).wDay = 26; \
|
||||
(st).wHour = 11; \
|
||||
(st).wMinute = 55; \
|
||||
(st).wSecond = 32; \
|
||||
(st).wMilliseconds = 123;
|
||||
|
||||
|
||||
|
||||
static void test_conversions(void)
|
||||
{
|
||||
FILETIME ft;
|
||||
SYSTEMTIME st;
|
||||
|
||||
memset(&ft,0,sizeof ft);
|
||||
|
||||
SETUP_ATIME(st)
|
||||
ok (SystemTimeToFileTime(&st,&ft), "Conversion Failed ATIME\n");
|
||||
ok( (!((ft.dwHighDateTime != ATIME_HI) || (ft.dwLowDateTime!=ATIME_LOW))),
|
||||
"Wrong time for ATIME: %08lx %08lx (correct %08x %08x)\n",
|
||||
ft.dwLowDateTime, ft.dwHighDateTime, ATIME_LOW, ATIME_HI);
|
||||
|
||||
|
||||
SETUP_2002(st)
|
||||
ok (SystemTimeToFileTime(&st, &ft), "Conversion failed 2002\n");
|
||||
|
||||
ok( (!((ft.dwHighDateTime != MAYDAY_2002_HI) ||
|
||||
(ft.dwLowDateTime!=MAYDAY_2002_LO))),
|
||||
"Wrong time for 2002 %08lx %08lx (correct %08x %08x)\n", ft.dwLowDateTime,
|
||||
ft.dwHighDateTime, MAYDAY_2002_LO, MAYDAY_2002_HI);
|
||||
|
||||
|
||||
SETUP_1980(st)
|
||||
ok((SystemTimeToFileTime(&st, &ft)), "Conversion failed 1980\n");
|
||||
|
||||
ok( (!((ft.dwHighDateTime!=NEWYEAR_1980_HI) ||
|
||||
(ft.dwLowDateTime!=NEWYEAR_1980_LO))) ,
|
||||
"Wrong time for 1980 %08lx %08lx (correct %08x %08x)\n", ft.dwLowDateTime,
|
||||
ft.dwHighDateTime, NEWYEAR_1980_LO,NEWYEAR_1980_HI );
|
||||
|
||||
ok(DosDateTimeToFileTime(DOS_DATE(1980,1,1),DOS_TIME(0,0,0),&ft),
|
||||
"DosDateTimeToFileTime() failed\n");
|
||||
|
||||
ok( (!((ft.dwHighDateTime!=NEWYEAR_1980_HI) ||
|
||||
(ft.dwLowDateTime!=NEWYEAR_1980_LO))),
|
||||
"Wrong time DosDateTimeToFileTime %08lx %08lx (correct %08x %08x)\n",
|
||||
ft.dwHighDateTime, ft.dwLowDateTime, NEWYEAR_1980_HI, NEWYEAR_1980_LO);
|
||||
|
||||
}
|
||||
|
||||
static void test_invalid_arg(void)
|
||||
{
|
||||
FILETIME ft;
|
||||
SYSTEMTIME st;
|
||||
|
||||
|
||||
/* Invalid argument checks */
|
||||
|
||||
memset(&ft,0,sizeof ft);
|
||||
ok( DosDateTimeToFileTime(DOS_DATE(1980,1,1),DOS_TIME(0,0,0),&ft), /* this is 1 Jan 1980 00:00:00 */
|
||||
"DosDateTimeToFileTime() failed\n");
|
||||
|
||||
ok( (ft.dwHighDateTime==NEWYEAR_1980_HI) && (ft.dwLowDateTime==NEWYEAR_1980_LO),
|
||||
"filetime for 1/1/80 00:00:00 was %08lx %08lx\n", ft.dwHighDateTime, ft.dwLowDateTime);
|
||||
|
||||
/* now check SystemTimeToFileTime */
|
||||
memset(&ft,0,sizeof ft);
|
||||
|
||||
|
||||
/* try with a bad month */
|
||||
SETUP_1980(st)
|
||||
st.wMonth = 0;
|
||||
|
||||
ok( !SystemTimeToFileTime(&st, &ft), "bad month\n");
|
||||
|
||||
/* with a bad hour */
|
||||
SETUP_1980(st)
|
||||
st.wHour = 24;
|
||||
|
||||
ok( !SystemTimeToFileTime(&st, &ft), "bad hour\n");
|
||||
|
||||
/* with a bad minute */
|
||||
SETUP_1980(st)
|
||||
st.wMinute = 60;
|
||||
|
||||
ok( !SystemTimeToFileTime(&st, &ft), "bad minute\n");
|
||||
}
|
||||
|
||||
static void test_GetTimeZoneInformation(void)
|
||||
{
|
||||
TIME_ZONE_INFORMATION tzinfo, tzinfo1;
|
||||
DWORD res = GetTimeZoneInformation(&tzinfo);
|
||||
ok(res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
|
||||
ok(SetEnvironmentVariableA("TZ","GMT0") != 0,
|
||||
"SetEnvironmentVariableA failed\n");
|
||||
res = GetTimeZoneInformation(&tzinfo1);
|
||||
ok(res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
|
||||
|
||||
ok(((tzinfo.Bias == tzinfo1.Bias) &&
|
||||
(tzinfo.StandardBias == tzinfo1.StandardBias) &&
|
||||
(tzinfo.DaylightBias == tzinfo1.DaylightBias)),
|
||||
"Bias influenced by TZ variable\n");
|
||||
ok(SetEnvironmentVariableA("TZ",NULL) != 0,
|
||||
"SetEnvironmentVariableA failed\n");
|
||||
|
||||
}
|
||||
|
||||
static void test_FileTimeToSystemTime(void)
|
||||
{
|
||||
FILETIME ft;
|
||||
SYSTEMTIME st;
|
||||
ULONGLONG time = (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
|
||||
BOOL ret;
|
||||
|
||||
ft.dwHighDateTime = 0;
|
||||
ft.dwLowDateTime = 0;
|
||||
ret = FileTimeToSystemTime(&ft, &st);
|
||||
ok( ret,
|
||||
"FileTimeToSystemTime() failed with Error 0x%08lx\n",GetLastError());
|
||||
ok(((st.wYear == 1601) && (st.wMonth == 1) && (st.wDay == 1) &&
|
||||
(st.wHour == 0) && (st.wMinute == 0) && (st.wSecond == 0) &&
|
||||
(st.wMilliseconds == 0)),
|
||||
"Got Year %4d Month %2d Day %2d\n", st.wYear, st.wMonth, st.wDay);
|
||||
|
||||
ft.dwHighDateTime = (UINT)(time >> 32);
|
||||
ft.dwLowDateTime = (UINT)time;
|
||||
ret = FileTimeToSystemTime(&ft, &st);
|
||||
ok( ret,
|
||||
"FileTimeToSystemTime() failed with Error 0x%08lx\n",GetLastError());
|
||||
ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) &&
|
||||
(st.wHour == 0) && (st.wMinute == 0) && (st.wSecond == 1) &&
|
||||
(st.wMilliseconds == 0)),
|
||||
"Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n",
|
||||
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
|
||||
st.wMilliseconds);
|
||||
}
|
||||
|
||||
static void test_FileTimeToLocalFileTime(void)
|
||||
{
|
||||
FILETIME ft, lft;
|
||||
SYSTEMTIME st;
|
||||
TIME_ZONE_INFORMATION tzinfo;
|
||||
DWORD res = GetTimeZoneInformation(&tzinfo);
|
||||
ULONGLONG time = (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970 +
|
||||
(LONGLONG)(tzinfo.Bias +
|
||||
( res == TIME_ZONE_ID_STANDARD ? tzinfo.StandardBias :
|
||||
( res == TIME_ZONE_ID_DAYLIGHT ? tzinfo.DaylightBias : 0 ))) *
|
||||
SECSPERMIN *TICKSPERSEC;
|
||||
BOOL ret;
|
||||
|
||||
ok( res != TIME_ZONE_ID_INVALID , "GetTimeZoneInformation failed\n");
|
||||
ft.dwHighDateTime = (UINT)(time >> 32);
|
||||
ft.dwLowDateTime = (UINT)time;
|
||||
ret = FileTimeToLocalFileTime(&ft, &lft);
|
||||
ok( ret,
|
||||
"FileTimeToLocalFileTime() failed with Error 0x%08lx\n",GetLastError());
|
||||
FileTimeToSystemTime(&lft, &st);
|
||||
ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) &&
|
||||
(st.wHour == 0) && (st.wMinute == 0) && (st.wSecond == 1) &&
|
||||
(st.wMilliseconds == 0)),
|
||||
"Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n",
|
||||
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
|
||||
st.wMilliseconds);
|
||||
|
||||
ok(SetEnvironmentVariableA("TZ","GMT") != 0,
|
||||
"SetEnvironmentVariableA failed\n");
|
||||
ok(res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
|
||||
ret = FileTimeToLocalFileTime(&ft, &lft);
|
||||
ok( ret,
|
||||
"FileTimeToLocalFileTime() failed with Error 0x%08lx\n",GetLastError());
|
||||
FileTimeToSystemTime(&lft, &st);
|
||||
ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) &&
|
||||
(st.wHour == 0) && (st.wMinute == 0) && (st.wSecond == 1) &&
|
||||
(st.wMilliseconds == 0)),
|
||||
"Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n",
|
||||
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
|
||||
st.wMilliseconds);
|
||||
ok(SetEnvironmentVariableA("TZ",NULL) != 0,
|
||||
"SetEnvironmentVariableA failed\n");
|
||||
}
|
||||
|
||||
|
||||
/* test TzSpecificLocalTimeToSystemTime and SystemTimeToTzSpecificLocalTime
|
||||
* these are in winXP and later */
|
||||
typedef HANDLE (WINAPI *fnTzSpecificLocalTimeToSystemTime)( LPTIME_ZONE_INFORMATION, LPSYSTEMTIME, LPSYSTEMTIME);
|
||||
typedef HANDLE (WINAPI *fnSystemTimeToTzSpecificLocalTime)( LPTIME_ZONE_INFORMATION, LPSYSTEMTIME, LPSYSTEMTIME);
|
||||
|
||||
typedef struct {
|
||||
int nr; /* test case number for easier lookup */
|
||||
TIME_ZONE_INFORMATION *ptz; /* ptr to timezone */
|
||||
SYSTEMTIME slt; /* system/local time to convert */
|
||||
WORD ehour; /* expected hour */
|
||||
} TZLT2ST_case;
|
||||
|
||||
static void test_TzSpecificLocalTimeToSystemTime(void)
|
||||
{
|
||||
HMODULE hKernel = GetModuleHandle("kernel32");
|
||||
fnTzSpecificLocalTimeToSystemTime pTzSpecificLocalTimeToSystemTime;
|
||||
fnSystemTimeToTzSpecificLocalTime pSystemTimeToTzSpecificLocalTime = NULL;
|
||||
TIME_ZONE_INFORMATION tzE, tzW, tzS;
|
||||
SYSTEMTIME result;
|
||||
int i, j, year;
|
||||
pTzSpecificLocalTimeToSystemTime = (fnTzSpecificLocalTimeToSystemTime) GetProcAddress( hKernel, "TzSpecificLocalTimeToSystemTime");
|
||||
if(pTzSpecificLocalTimeToSystemTime)
|
||||
pSystemTimeToTzSpecificLocalTime = (fnTzSpecificLocalTimeToSystemTime) GetProcAddress( hKernel, "SystemTimeToTzSpecificLocalTime");
|
||||
if( !pSystemTimeToTzSpecificLocalTime)
|
||||
return;
|
||||
ZeroMemory( &tzE, sizeof(tzE));
|
||||
ZeroMemory( &tzW, sizeof(tzW));
|
||||
ZeroMemory( &tzS, sizeof(tzS));
|
||||
/* timezone Eastern hemisphere */
|
||||
tzE.Bias=-600;
|
||||
tzE.StandardBias=0;
|
||||
tzE.DaylightBias=-60;
|
||||
tzE.StandardDate.wMonth=10;
|
||||
tzE.StandardDate.wDayOfWeek=0; /*sunday */
|
||||
tzE.StandardDate.wDay=5; /* last (sunday) of the month */
|
||||
tzE.StandardDate.wHour=3;
|
||||
tzE.DaylightDate.wMonth=3;
|
||||
tzE.DaylightDate.wDay=5;
|
||||
tzE.DaylightDate.wHour=2;
|
||||
/* timezone Western hemisphere */
|
||||
tzW.Bias=240;
|
||||
tzW.StandardBias=0;
|
||||
tzW.DaylightBias=-60;
|
||||
tzW.StandardDate.wMonth=10;
|
||||
tzW.StandardDate.wDayOfWeek=0; /*sunday */
|
||||
tzW.StandardDate.wDay=4; /* 4th (sunday) of the month */
|
||||
tzW.StandardDate.wHour=2;
|
||||
tzW.DaylightDate.wMonth=4;
|
||||
tzW.DaylightDate.wDay=1;
|
||||
tzW.DaylightDate.wHour=2;
|
||||
/* timezone Eastern hemisphere */
|
||||
tzS.Bias=240;
|
||||
tzS.StandardBias=0;
|
||||
tzS.DaylightBias=-60;
|
||||
tzS.StandardDate.wMonth=4;
|
||||
tzS.StandardDate.wDayOfWeek=0; /*sunday */
|
||||
tzS.StandardDate.wDay=1; /* 1st (sunday) of the month */
|
||||
tzS.StandardDate.wHour=2;
|
||||
tzS.DaylightDate.wMonth=10;
|
||||
tzS.DaylightDate.wDay=4;
|
||||
tzS.DaylightDate.wHour=2;
|
||||
/*tests*/
|
||||
/* TzSpecificLocalTimeToSystemTime */
|
||||
{ TZLT2ST_case cases[] = {
|
||||
/* standard->daylight transition */
|
||||
{ 1, &tzE, {2004,3,-1,28,1,0,0,0}, 15 },
|
||||
{ 2, &tzE, {2004,3,-1,28,1,59,59,999}, 15},
|
||||
{ 3, &tzE, {2004,3,-1,28,2,0,0,0}, 15},
|
||||
/* daylight->standard transition */
|
||||
{ 4, &tzE, {2004,10,-1,31,2,0,0,0} , 15 },
|
||||
{ 5, &tzE, {2004,10,-1,31,2,59,59,999}, 15 },
|
||||
{ 6, &tzE, {2004,10,-1,31,3,0,0,0}, 17 },
|
||||
/* West and with fixed weekday of the month */
|
||||
{ 7, &tzW, {2004,4,-1,4,1,0,0,0}, 5},
|
||||
{ 8, &tzW, {2004,4,-1,4,1,59,59,999}, 5},
|
||||
{ 9, &tzW, {2004,4,-1,4,2,0,0,0}, 5},
|
||||
{ 10, &tzW, {2004,10,-1,24,1,0,0,0}, 4},
|
||||
{ 11, &tzW, {2004,10,-1,24,1,59,59,999}, 4},
|
||||
{ 12, &tzW, {2004,10,-1,24,2,0,0,0 }, 6},
|
||||
/* and now south */
|
||||
{ 13, &tzS, {2004,4,-1,4,1,0,0,0}, 4},
|
||||
{ 14, &tzS, {2004,4,-1,4,1,59,59,999}, 4},
|
||||
{ 15, &tzS, {2004,4,-1,4,2,0,0,0}, 6},
|
||||
{ 16, &tzS, {2004,10,-1,24,1,0,0,0}, 5},
|
||||
{ 17, &tzS, {2004,10,-1,24,1,59,59,999}, 5},
|
||||
{ 18, &tzS, {2004,10,-1,24,2,0,0,0}, 5},
|
||||
{0}
|
||||
};
|
||||
/* days of transitions to put into the cases array */
|
||||
int yeardays[][6]=
|
||||
{
|
||||
{28,31,4,24,4,24} /* 1999 */
|
||||
, {26,29,2,22,2,22} /* 2000 */
|
||||
, {25,28,1,28,1,28} /* 2001 */
|
||||
, {31,27,7,27,7,27} /* 2002 */
|
||||
, {30,26,6,26,6,26} /* 2003 */
|
||||
, {28,31,4,24,4,24} /* 2004 */
|
||||
, {27,30,3,23,3,23} /* 2005 */
|
||||
, {26,29,2,22,2,22} /* 2006 */
|
||||
, {25,28,1,28,1,28} /* 2007 */
|
||||
, {30,26,6,26,6,26} /* 2008 */
|
||||
, {29,25,5,25,5,25} /* 2009 */
|
||||
, {28,31,4,24,4,24} /* 2010 */
|
||||
, {27,30,3,23,3,23} /* 2011 */
|
||||
, {25,28,1,28,1,28} /* 2012 */
|
||||
, {31,27,7,27,7,27} /* 2013 */
|
||||
, {30,26,6,26,6,26} /* 2014 */
|
||||
, {29,25,5,25,5,25} /* 2015 */
|
||||
, {27,30,3,23,3,23} /* 2016 */
|
||||
, {26,29,2,22,2,22} /* 2017 */
|
||||
, {25,28,1,28,1,28} /* 2018 */
|
||||
, {31,27,7,27,7,27} /* 2019 */
|
||||
,{0}
|
||||
};
|
||||
for( j=0 , year = 1999; yeardays[j][0] ; j++, year++) {
|
||||
for (i=0; cases[i].nr; i++) {
|
||||
if(i) cases[i].nr += 18;
|
||||
cases[i].slt.wYear = year;
|
||||
cases[i].slt.wDay = yeardays[j][i/3];
|
||||
pTzSpecificLocalTimeToSystemTime( cases[i].ptz, &(cases[i].slt), &result);
|
||||
ok( result.wHour == cases[i].ehour,
|
||||
"Test TzSpecificLocalTimeToSystemTime #%d. Got %4d-%02d-%02d %02d:%02d. Expect hour = %02d\n",
|
||||
cases[i].nr, result.wYear, result.wMonth, result.wDay,
|
||||
result.wHour, result.wMinute, cases[i].ehour);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* SystemTimeToTzSpecificLocalTime */
|
||||
{ TZLT2ST_case cases[] = {
|
||||
/* standard->daylight transition */
|
||||
{ 1, &tzE, {2004,3,-1,27,15,0,0,0}, 1 },
|
||||
{ 2, &tzE, {2004,3,-1,27,15,59,59,999}, 1},
|
||||
{ 3, &tzE, {2004,3,-1,27,16,0,0,0}, 3},
|
||||
/* daylight->standard transition */
|
||||
{ 4, &tzE, {2004,10,-1,30,15,0,0,0}, 2 },
|
||||
{ 5, &tzE, {2004,10,-1,30,15,59,59,999}, 2 },
|
||||
{ 6, &tzE, {2004,10,-1,30,16,0,0,0}, 2 },
|
||||
/* West and with fixed weekday of the month */
|
||||
{ 7, &tzW, {2004,4,-1,4,5,0,0,0}, 1},
|
||||
{ 8, &tzW, {2004,4,-1,4,5,59,59,999}, 1},
|
||||
{ 9, &tzW, {2004,4,-1,4,6,0,0,0}, 3},
|
||||
{ 10, &tzW, {2004,10,-1,24,4,0,0,0}, 1},
|
||||
{ 11, &tzW, {2004,10,-1,24,4,59,59,999}, 1},
|
||||
{ 12, &tzW, {2004,10,-1,24,5,0,0,0 }, 1},
|
||||
/* and now south */
|
||||
{ 13, &tzS, {2004,4,-1,4,4,0,0,0}, 1},
|
||||
{ 14, &tzS, {2004,4,-1,4,4,59,59,999}, 1},
|
||||
{ 15, &tzS, {2004,4,-1,4,5,0,0,0}, 1},
|
||||
{ 16, &tzS, {2004,10,-1,24,5,0,0,0}, 1},
|
||||
{ 17, &tzS, {2004,10,-1,24,5,59,59,999}, 1},
|
||||
{ 18, &tzS, {2004,10,-1,24,6,0,0,0}, 3},
|
||||
|
||||
{0}
|
||||
};
|
||||
/* days of transitions to put into the cases array */
|
||||
int yeardays[][6]=
|
||||
{
|
||||
{27,30,4,24,4,24} /* 1999 */
|
||||
, {25,28,2,22,2,22} /* 2000 */
|
||||
, {24,27,1,28,1,28} /* 2001 */
|
||||
, {30,26,7,27,7,27} /* 2002 */
|
||||
, {29,25,6,26,6,26} /* 2003 */
|
||||
, {27,30,4,24,4,24} /* 2004 */
|
||||
, {26,29,3,23,3,23} /* 2005 */
|
||||
, {25,28,2,22,2,22} /* 2006 */
|
||||
, {24,27,1,28,1,28} /* 2007 */
|
||||
, {29,25,6,26,6,26} /* 2008 */
|
||||
, {28,24,5,25,5,25} /* 2009 */
|
||||
, {27,30,4,24,4,24} /* 2010 */
|
||||
, {26,29,3,23,3,23} /* 2011 */
|
||||
, {24,27,1,28,1,28} /* 2012 */
|
||||
, {30,26,7,27,7,27} /* 2013 */
|
||||
, {29,25,6,26,6,26} /* 2014 */
|
||||
, {28,24,5,25,5,25} /* 2015 */
|
||||
, {26,29,3,23,3,23} /* 2016 */
|
||||
, {25,28,2,22,2,22} /* 2017 */
|
||||
, {24,27,1,28,1,28} /* 2018 */
|
||||
, {30,26,7,27,7,27} /* 2019 */
|
||||
};
|
||||
for( j=0 , year = 1999; yeardays[j][0] ; j++, year++) {
|
||||
for (i=0; cases[i].nr; i++) {
|
||||
if(i) cases[i].nr += 18;
|
||||
cases[i].slt.wYear = year;
|
||||
cases[i].slt.wDay = yeardays[j][i/3];
|
||||
pSystemTimeToTzSpecificLocalTime( cases[i].ptz, &(cases[i].slt), &result);
|
||||
ok( result.wHour == cases[i].ehour,
|
||||
"Test SystemTimeToTzSpecificLocalTime #%d. Got %4d-%02d-%02d %02d:%02d. Expect hour = %02d\n",
|
||||
cases[i].nr, result.wYear, result.wMonth, result.wDay,
|
||||
result.wHour, result.wMinute, cases[i].ehour);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(time)
|
||||
{
|
||||
test_conversions();
|
||||
test_invalid_arg();
|
||||
test_GetTimeZoneInformation();
|
||||
test_FileTimeToSystemTime();
|
||||
test_FileTimeToLocalFileTime();
|
||||
test_TzSpecificLocalTimeToSystemTime();
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Unit test suite for time functions
|
||||
*
|
||||
* Copyright 2004 Mike McCormack
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define _WIN32_WINNT 0x0501
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "winbase.h"
|
||||
|
||||
typedef HANDLE (WINAPI *fnCreateWaitableTimerA)( SECURITY_ATTRIBUTES*, BOOL, LPSTR );
|
||||
typedef BOOL (WINAPI *fnSetWaitableTimer)(HANDLE, LARGE_INTEGER*, LONG, PTIMERAPCROUTINE, LPVOID, BOOL);
|
||||
|
||||
|
||||
static void test_timer(void)
|
||||
{
|
||||
HMODULE hker = GetModuleHandle("kernel32");
|
||||
fnCreateWaitableTimerA pCreateWaitableTimerA;
|
||||
fnSetWaitableTimer pSetWaitableTimer;
|
||||
HANDLE handle;
|
||||
BOOL r;
|
||||
LARGE_INTEGER due;
|
||||
|
||||
pCreateWaitableTimerA = (fnCreateWaitableTimerA) GetProcAddress( hker, "CreateWaitableTimerA");
|
||||
if( !pCreateWaitableTimerA )
|
||||
return;
|
||||
|
||||
pSetWaitableTimer = (fnSetWaitableTimer) GetProcAddress( hker, "SetWaitableTimer");
|
||||
if( !pSetWaitableTimer )
|
||||
return;
|
||||
|
||||
/* try once with a positive number */
|
||||
handle = pCreateWaitableTimerA( NULL, 0, NULL );
|
||||
ok( handle != NULL, "failed to create waitable timer with no name\n" );
|
||||
|
||||
due.QuadPart = 10000;
|
||||
r = pSetWaitableTimer( handle, &due, 0x1f4, NULL, NULL, FALSE );
|
||||
ok( r, "failed to set timer\n");
|
||||
|
||||
CloseHandle( handle );
|
||||
|
||||
/* try once with a negative number */
|
||||
handle = pCreateWaitableTimerA( NULL, 0, NULL );
|
||||
ok( handle != NULL, "failed to create waitable timer with no name\n" );
|
||||
|
||||
due.QuadPart = -10000;
|
||||
r = pSetWaitableTimer( handle, &due, 0x1f4, NULL, NULL, FALSE );
|
||||
ok( r, "failed to set timer\n");
|
||||
|
||||
CloseHandle( handle );
|
||||
}
|
||||
|
||||
START_TEST(timer)
|
||||
{
|
||||
test_timer();
|
||||
}
|
|
@ -1,341 +0,0 @@
|
|||
/*
|
||||
* Toolhelp
|
||||
*
|
||||
* Copyright 2005 Eric Pouech
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
|
||||
#include "tlhelp32.h"
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
|
||||
static char selfname[MAX_PATH];
|
||||
|
||||
/* Some functions are only in later versions of kernel32.dll */
|
||||
static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD);
|
||||
static BOOL (WINAPI *pModule32First)(HANDLE, LPMODULEENTRY32);
|
||||
static BOOL (WINAPI *pModule32Next)(HANDLE, LPMODULEENTRY32);
|
||||
static BOOL (WINAPI *pProcess32First)(HANDLE, LPPROCESSENTRY32);
|
||||
static BOOL (WINAPI *pProcess32Next)(HANDLE, LPPROCESSENTRY32);
|
||||
static BOOL (WINAPI *pThread32First)(HANDLE, LPTHREADENTRY32);
|
||||
static BOOL (WINAPI *pThread32Next)(HANDLE, LPTHREADENTRY32);
|
||||
|
||||
/* 1 minute should be more than enough */
|
||||
#define WAIT_TIME (60 * 1000)
|
||||
|
||||
static DWORD WINAPI sub_thread(void* pmt)
|
||||
{
|
||||
DWORD w = WaitForSingleObject((HANDLE)pmt, WAIT_TIME);
|
||||
return w;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* init
|
||||
*
|
||||
* generates basic information like:
|
||||
* selfname: the way to reinvoke ourselves
|
||||
* returns:
|
||||
* -1 on error
|
||||
* 0 if parent
|
||||
* doesn't return if child
|
||||
*/
|
||||
static int init(void)
|
||||
{
|
||||
int argc;
|
||||
char** argv;
|
||||
HANDLE ev1, ev2, ev3, hThread;
|
||||
DWORD w;
|
||||
|
||||
argc = winetest_get_mainargs( &argv );
|
||||
strcpy(selfname, argv[0]);
|
||||
|
||||
switch (argc)
|
||||
{
|
||||
case 2: /* the test program */
|
||||
return 0;
|
||||
case 4: /* the sub-process */
|
||||
ev1 = (HANDLE)atoi(argv[2]);
|
||||
ev2 = (HANDLE)atoi(argv[3]);
|
||||
ev3 = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
if (ev3 == NULL) ExitProcess(WAIT_ABANDONED);
|
||||
hThread = CreateThread(NULL, 0, sub_thread, ev3, 0, NULL);
|
||||
if (hThread == NULL) ExitProcess(WAIT_ABANDONED);
|
||||
if (!LoadLibraryA("shell32.dll")) ExitProcess(WAIT_ABANDONED);
|
||||
|
||||
/* signal init of sub-process is done */
|
||||
SetEvent(ev1);
|
||||
/* wait for parent to have done all its queries */
|
||||
w = WaitForSingleObject(ev2, WAIT_TIME);
|
||||
if (w != WAIT_OBJECT_0) ExitProcess(w);
|
||||
/* signal sub-thread to terminate */
|
||||
SetEvent(ev3);
|
||||
w = WaitForSingleObject(hThread, WAIT_TIME);
|
||||
if (w != WAIT_OBJECT_0) ExitProcess(w);
|
||||
GetExitCodeThread(hThread, &w);
|
||||
ExitProcess(w);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_process(DWORD curr_pid, DWORD sub_pcs_pid)
|
||||
{
|
||||
HANDLE hSnapshot;
|
||||
PROCESSENTRY32 pe;
|
||||
THREADENTRY32 te;
|
||||
MODULEENTRY32 me;
|
||||
unsigned found = 0;
|
||||
int num = 0;
|
||||
|
||||
hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
|
||||
ok(hSnapshot != NULL, "Cannot create snapshot\n");
|
||||
|
||||
/* check that this current process is enumerated */
|
||||
pe.dwSize = sizeof(pe);
|
||||
if (pProcess32First( hSnapshot, &pe ))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (pe.th32ProcessID == curr_pid) found++;
|
||||
if (pe.th32ProcessID == sub_pcs_pid) found++;
|
||||
trace("PID=%lx %s\n", pe.th32ProcessID, pe.szExeFile);
|
||||
num++;
|
||||
} while (pProcess32Next( hSnapshot, &pe ));
|
||||
}
|
||||
ok(found == 2, "couldn't find self and/or sub-process in process list\n");
|
||||
|
||||
/* check that first really resets the enumeration */
|
||||
found = 0;
|
||||
if (pProcess32First( hSnapshot, &pe ))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (pe.th32ProcessID == curr_pid) found++;
|
||||
if (pe.th32ProcessID == sub_pcs_pid) found++;
|
||||
trace("PID=%lx %s\n", pe.th32ProcessID, pe.szExeFile);
|
||||
num--;
|
||||
} while (pProcess32Next( hSnapshot, &pe ));
|
||||
}
|
||||
ok(found == 2, "couldn't find self and/or sub-process in process list\n");
|
||||
ok(!num, "mismatch in counting\n");
|
||||
|
||||
te.dwSize = sizeof(te);
|
||||
ok(!pThread32First( hSnapshot, &te ), "shouldn't return a thread\n");
|
||||
|
||||
me.dwSize = sizeof(me);
|
||||
ok(!pModule32First( hSnapshot, &me ), "shouldn't return a module\n");
|
||||
|
||||
CloseHandle(hSnapshot);
|
||||
ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n");
|
||||
}
|
||||
|
||||
static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid)
|
||||
{
|
||||
HANDLE hSnapshot;
|
||||
PROCESSENTRY32 pe;
|
||||
THREADENTRY32 te;
|
||||
MODULEENTRY32 me;
|
||||
int num = 0;
|
||||
unsigned curr_found = 0;
|
||||
unsigned sub_found = 0;
|
||||
|
||||
hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
|
||||
ok(hSnapshot != NULL, "Cannot create snapshot\n");
|
||||
|
||||
/* check that this current process is enumerated */
|
||||
te.dwSize = sizeof(te);
|
||||
if (pThread32First( hSnapshot, &te ))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (te.th32OwnerProcessID == curr_pid) curr_found++;
|
||||
if (te.th32OwnerProcessID == sub_pcs_pid) sub_found++;
|
||||
trace("PID=%lx TID=%lx %ld\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri);
|
||||
num++;
|
||||
} while (pThread32Next( hSnapshot, &te ));
|
||||
}
|
||||
ok(curr_found == 1, "couldn't find self in thread list\n");
|
||||
ok(sub_found == 2, "couldn't find sub-process thread's in thread list\n");
|
||||
|
||||
/* check that first really resets enumeration */
|
||||
curr_found = 0;
|
||||
sub_found = 0;
|
||||
if (pThread32First( hSnapshot, &te ))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (te.th32OwnerProcessID == curr_pid) curr_found++;
|
||||
if (te.th32OwnerProcessID == sub_pcs_pid) sub_found++;
|
||||
trace("PID=%lx TID=%lx %ld\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri);
|
||||
num--;
|
||||
} while (pThread32Next( hSnapshot, &te ));
|
||||
}
|
||||
ok(curr_found == 1, "couldn't find self in thread list\n");
|
||||
ok(sub_found == 2, "couldn't find sub-process thread's in thread list\n");
|
||||
|
||||
pe.dwSize = sizeof(pe);
|
||||
ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n");
|
||||
|
||||
me.dwSize = sizeof(me);
|
||||
ok(!pModule32First( hSnapshot, &me ), "shouldn't return a module\n");
|
||||
|
||||
CloseHandle(hSnapshot);
|
||||
ok(!pThread32First( hSnapshot, &te ), "shouldn't return a thread\n");
|
||||
}
|
||||
|
||||
static const char* curr_expected_modules[] =
|
||||
{
|
||||
"kernel32.dll",
|
||||
"kernel32_test.exe"
|
||||
/* FIXME: could test for ntdll on NT and Wine */
|
||||
};
|
||||
static const char* sub_expected_modules[] =
|
||||
{
|
||||
"kernel32.dll",
|
||||
"kernel32_test.exe",
|
||||
"shell32.dll"
|
||||
/* FIXME: could test for ntdll on NT and Wine */
|
||||
};
|
||||
#define NUM_OF(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
static void test_module(DWORD pid, const char* expected[], unsigned num_expected)
|
||||
{
|
||||
HANDLE hSnapshot;
|
||||
PROCESSENTRY32 pe;
|
||||
THREADENTRY32 te;
|
||||
MODULEENTRY32 me;
|
||||
unsigned found[32];
|
||||
int i, num = 0;
|
||||
|
||||
ok(NUM_OF(found) >= num_expected, "Internal: bump found[] size\n");
|
||||
|
||||
hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pid );
|
||||
ok(hSnapshot != NULL, "Cannot create snapshot\n");
|
||||
|
||||
for (i = 0; i < num_expected; i++) found[i] = 0;
|
||||
me.dwSize = sizeof(me);
|
||||
if (pModule32First( hSnapshot, &me ))
|
||||
{
|
||||
do
|
||||
{
|
||||
trace("PID=%lx base=%p size=%lx %s %s\n",
|
||||
me.th32ProcessID, me.modBaseAddr, me.modBaseSize, me.szExePath, me.szModule);
|
||||
ok(me.th32ProcessID == pid, "wrong returned process id\n");
|
||||
for (i = 0; i < num_expected; i++)
|
||||
if (!lstrcmpi(expected[i], me.szModule)) found[i]++;
|
||||
num++;
|
||||
} while (pModule32Next( hSnapshot, &me ));
|
||||
}
|
||||
for (i = 0; i < num_expected; i++)
|
||||
ok(found[i] == 1, "Module %s is %s\n",
|
||||
expected[i], found[i] ? "listed more than once" : "not listed");
|
||||
|
||||
/* check that first really resets the enumeration */
|
||||
for (i = 0; i < num_expected; i++) found[i] = 0;
|
||||
me.dwSize = sizeof(me);
|
||||
if (pModule32First( hSnapshot, &me ))
|
||||
{
|
||||
do
|
||||
{
|
||||
trace("PID=%lx base=%p size=%lx %s %s\n",
|
||||
me.th32ProcessID, me.modBaseAddr, me.modBaseSize, me.szExePath, me.szModule);
|
||||
for (i = 0; i < num_expected; i++)
|
||||
if (!lstrcmpi(expected[i], me.szModule)) found[i]++;
|
||||
num--;
|
||||
} while (pModule32Next( hSnapshot, &me ));
|
||||
}
|
||||
for (i = 0; i < num_expected; i++)
|
||||
ok(found[i] == 1, "Module %s is %s\n",
|
||||
expected[i], found[i] ? "listed more than once" : "not listed");
|
||||
ok(!num, "mismatch in counting\n");
|
||||
|
||||
pe.dwSize = sizeof(pe);
|
||||
ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n");
|
||||
|
||||
me.dwSize = sizeof(me);
|
||||
ok(!pThread32First( hSnapshot, &te ), "shouldn't return a thread\n");
|
||||
|
||||
CloseHandle(hSnapshot);
|
||||
ok(!pModule32First( hSnapshot, &me ), "shouldn't return a module\n");
|
||||
}
|
||||
|
||||
START_TEST(toolhelp)
|
||||
{
|
||||
DWORD pid = GetCurrentProcessId();
|
||||
int r;
|
||||
char buffer[MAX_PATH];
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
PROCESS_INFORMATION info;
|
||||
STARTUPINFOA startup;
|
||||
HANDLE ev1, ev2;
|
||||
DWORD w;
|
||||
HANDLE hkernel32 = GetModuleHandleA("kernel32");
|
||||
|
||||
pCreateToolhelp32Snapshot = (VOID *) GetProcAddress(hkernel32, "CreateToolhelp32Snapshot");
|
||||
pModule32First = (VOID *) GetProcAddress(hkernel32, "Module32First");
|
||||
pModule32Next = (VOID *) GetProcAddress(hkernel32, "Module32Next");
|
||||
pProcess32First = (VOID *) GetProcAddress(hkernel32, "Process32First");
|
||||
pProcess32Next = (VOID *) GetProcAddress(hkernel32, "Process32Next");
|
||||
pThread32First = (VOID *) GetProcAddress(hkernel32, "Thread32First");
|
||||
pThread32Next = (VOID *) GetProcAddress(hkernel32, "Thread32Next");
|
||||
|
||||
if (!pCreateToolhelp32Snapshot ||
|
||||
!pModule32First || !pModule32Next ||
|
||||
!pProcess32First || !pProcess32Next ||
|
||||
!pThread32First || !pThread32Next) return;
|
||||
|
||||
r = init();
|
||||
ok(r == 0, "Basic init of sub-process test\n");
|
||||
if (r != 0) return;
|
||||
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
sa.bInheritHandle = TRUE;
|
||||
|
||||
ev1 = CreateEvent(&sa, FALSE, FALSE, NULL);
|
||||
ev2 = CreateEvent(&sa, FALSE, FALSE, NULL);
|
||||
ok (ev1 != NULL && ev2 != NULL, "Couldn't create events\n");
|
||||
memset(&startup, 0, sizeof(startup));
|
||||
startup.cb = sizeof(startup);
|
||||
startup.dwFlags = STARTF_USESHOWWINDOW;
|
||||
startup.wShowWindow = SW_SHOWNORMAL;
|
||||
|
||||
sprintf(buffer, "%s tests/toolhelp.c %lu %lu", selfname, (DWORD)ev1, (DWORD)ev2);
|
||||
ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
|
||||
/* wait for child to be initialized */
|
||||
w = WaitForSingleObject(ev1, WAIT_TIME);
|
||||
ok(w == WAIT_OBJECT_0, "Failed to wait on sub-process startup\n");
|
||||
|
||||
test_process(pid, info.dwProcessId);
|
||||
test_thread(pid, info.dwProcessId);
|
||||
test_module(pid, curr_expected_modules, NUM_OF(curr_expected_modules));
|
||||
test_module(info.dwProcessId, sub_expected_modules, NUM_OF(sub_expected_modules));
|
||||
|
||||
SetEvent(ev2);
|
||||
w = WaitForSingleObject(info.hProcess, WAIT_TIME);
|
||||
ok(w == WAIT_OBJECT_0, "Failed to wait on sub-process termination\n");
|
||||
ok(GetExitCodeProcess(info.hProcess, &w), "couldn't get process exit code\n");
|
||||
ok(w == WAIT_OBJECT_0, "Sub-Process failed to terminate properly\n");
|
||||
}
|
|
@ -1,268 +0,0 @@
|
|||
/*
|
||||
* Unit test suite for Virtual* family of APIs.
|
||||
*
|
||||
* Copyright 2004 Dmitry Timoshkov
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/test.h"
|
||||
|
||||
static void test_VirtualAlloc(void)
|
||||
{
|
||||
void *addr1, *addr2;
|
||||
DWORD old_prot;
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
addr1 = VirtualAlloc(0, 0, MEM_RESERVE, PAGE_NOACCESS);
|
||||
ok(addr1 == NULL, "VirtualAlloc should fail on zero-sized allocation\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER /* NT */ ||
|
||||
GetLastError() == ERROR_NOT_ENOUGH_MEMORY, /* Win9x */
|
||||
"got %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
|
||||
|
||||
addr1 = VirtualAlloc(0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
|
||||
ok(addr1 != NULL, "VirtualAlloc failed\n");
|
||||
|
||||
/* test a not committed memory */
|
||||
ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
|
||||
"VirtualQuery failed\n");
|
||||
ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
|
||||
ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
|
||||
ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect);
|
||||
ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
|
||||
ok(info.State == MEM_RESERVE, "%lx != MEM_RESERVE\n", info.State);
|
||||
/* NT reports Protect == 0 for a not committed memory block */
|
||||
ok(info.Protect == 0 /* NT */ ||
|
||||
info.Protect == PAGE_NOACCESS, /* Win9x */
|
||||
"%lx != PAGE_NOACCESS\n", info.Protect);
|
||||
ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ok(!VirtualProtect(addr1, 0xFFFC, PAGE_READONLY, &old_prot),
|
||||
"VirtualProtect should fail on a not committed memory\n");
|
||||
ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
|
||||
GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
|
||||
"got %ld, expected ERROR_INVALID_ADDRESS\n", GetLastError());
|
||||
|
||||
addr2 = VirtualAlloc(addr1, 0x1000, MEM_COMMIT, PAGE_NOACCESS);
|
||||
ok(addr1 == addr2, "VirtualAlloc failed\n");
|
||||
|
||||
/* test a committed memory */
|
||||
ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
|
||||
"VirtualQuery failed\n");
|
||||
ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
|
||||
ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
|
||||
ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect);
|
||||
ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
|
||||
ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
|
||||
/* this time NT reports PAGE_NOACCESS as well */
|
||||
ok(info.Protect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.Protect);
|
||||
ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
|
||||
|
||||
/* this should fail, since not the whole range is committed yet */
|
||||
SetLastError(0xdeadbeef);
|
||||
ok(!VirtualProtect(addr1, 0xFFFC, PAGE_READONLY, &old_prot),
|
||||
"VirtualProtect should fail on a not committed memory\n");
|
||||
ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
|
||||
GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
|
||||
"got %ld, expected ERROR_INVALID_ADDRESS\n", GetLastError());
|
||||
|
||||
ok(VirtualProtect(addr1, 0x1000, PAGE_READONLY, &old_prot), "VirtualProtect failed\n");
|
||||
ok(old_prot == PAGE_NOACCESS,
|
||||
"wrong old protection: got %04lx instead of PAGE_NOACCESS\n", old_prot);
|
||||
|
||||
ok(VirtualProtect(addr1, 0x1000, PAGE_READWRITE, &old_prot), "VirtualProtect failed\n");
|
||||
ok(old_prot == PAGE_READONLY,
|
||||
"wrong old protection: got %04lx instead of PAGE_READONLY\n", old_prot);
|
||||
|
||||
ok(!VirtualFree(addr1, 0x10000, 0), "VirtualFree should fail with type 0\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"got %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
|
||||
|
||||
ok(VirtualFree(addr1, 0x10000, MEM_DECOMMIT), "VirtualFree failed\n");
|
||||
|
||||
/* if the type is MEM_RELEASE, size must be 0 */
|
||||
ok(!VirtualFree(addr1, 1, MEM_RELEASE), "VirtualFree should fail\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"got %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
|
||||
|
||||
ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
|
||||
}
|
||||
|
||||
static void test_MapViewOfFile(void)
|
||||
{
|
||||
static const char testfile[] = "testfile.xxx";
|
||||
HANDLE file, mapping;
|
||||
void *ptr;
|
||||
|
||||
file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
|
||||
ok( file != INVALID_HANDLE_VALUE, "Failed to create test file\n" );
|
||||
SetFilePointer( file, 4096, NULL, FILE_BEGIN );
|
||||
SetEndOfFile( file );
|
||||
|
||||
/* read/write mapping */
|
||||
|
||||
mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
|
||||
ok( mapping != 0, "CreateFileMapping failed\n" );
|
||||
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
|
||||
ok( ptr != NULL, "MapViewOfFile FILE_MAPE_READ failed\n" );
|
||||
UnmapViewOfFile( ptr );
|
||||
|
||||
/* this fails on win9x but succeeds on NT */
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
|
||||
if (ptr) UnmapViewOfFile( ptr );
|
||||
else ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %lx\n", GetLastError() );
|
||||
|
||||
ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
|
||||
ok( ptr != NULL, "MapViewOfFile 0 failed\n" );
|
||||
UnmapViewOfFile( ptr );
|
||||
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
|
||||
ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE failed\n" );
|
||||
UnmapViewOfFile( ptr );
|
||||
CloseHandle( mapping );
|
||||
|
||||
/* read-only mapping */
|
||||
|
||||
mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
|
||||
ok( mapping != 0, "CreateFileMapping failed\n" );
|
||||
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
|
||||
ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ failed\n" );
|
||||
UnmapViewOfFile( ptr );
|
||||
|
||||
/* this fails on win9x but succeeds on NT */
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
|
||||
if (ptr) UnmapViewOfFile( ptr );
|
||||
else ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %lx\n", GetLastError() );
|
||||
|
||||
ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
|
||||
ok( ptr != NULL, "MapViewOfFile 0 failed\n" );
|
||||
UnmapViewOfFile( ptr );
|
||||
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
|
||||
ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_PARAMETER ||
|
||||
GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %lx\n", GetLastError() );
|
||||
CloseHandle( mapping );
|
||||
|
||||
/* copy-on-write mapping */
|
||||
|
||||
mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
|
||||
ok( mapping != 0, "CreateFileMapping failed\n" );
|
||||
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
|
||||
ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ failed\n" );
|
||||
UnmapViewOfFile( ptr );
|
||||
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
|
||||
ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY failed\n" );
|
||||
UnmapViewOfFile( ptr );
|
||||
|
||||
ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
|
||||
ok( ptr != NULL, "MapViewOfFile 0 failed\n" );
|
||||
UnmapViewOfFile( ptr );
|
||||
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
|
||||
ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_PARAMETER ||
|
||||
GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %lx\n", GetLastError() );
|
||||
CloseHandle( mapping );
|
||||
|
||||
/* no access mapping */
|
||||
|
||||
mapping = CreateFileMappingA( file, NULL, PAGE_NOACCESS, 0, 4096, NULL );
|
||||
/* fails on NT but succeeds on win9x */
|
||||
if (!mapping) ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %lx\n", GetLastError() );
|
||||
else
|
||||
{
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
|
||||
ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ failed\n" );
|
||||
UnmapViewOfFile( ptr );
|
||||
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
|
||||
ok( !ptr, "MapViewOfFile FILE_MAP_COPY succeeded\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %lx\n", GetLastError() );
|
||||
|
||||
ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
|
||||
ok( ptr != NULL, "MapViewOfFile 0 failed\n" );
|
||||
UnmapViewOfFile( ptr );
|
||||
|
||||
ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
|
||||
ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %lx\n", GetLastError() );
|
||||
|
||||
CloseHandle( mapping );
|
||||
}
|
||||
|
||||
CloseHandle( file );
|
||||
|
||||
/* now try read-only file */
|
||||
|
||||
file = CreateFileA( testfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 );
|
||||
ok( file != INVALID_HANDLE_VALUE, "Failed to create test file\n" );
|
||||
|
||||
mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
|
||||
ok( !mapping, "CreateFileMapping PAGE_READWRITE succeeded\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_PARAMETER ||
|
||||
GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %lx\n", GetLastError() );
|
||||
|
||||
mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
|
||||
ok( mapping != 0, "CreateFileMapping PAGE_WRITECOPY failed\n" );
|
||||
CloseHandle( mapping );
|
||||
|
||||
mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
|
||||
ok( mapping != 0, "CreateFileMapping PAGE_READONLY failed\n" );
|
||||
CloseHandle( mapping );
|
||||
CloseHandle( file );
|
||||
|
||||
/* now try no access file */
|
||||
|
||||
file = CreateFileA( testfile, 0, 0, NULL, OPEN_EXISTING, 0, 0 );
|
||||
ok( file != INVALID_HANDLE_VALUE, "Failed to create test file\n" );
|
||||
|
||||
mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
|
||||
ok( !mapping, "CreateFileMapping PAGE_READWRITE succeeded\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_PARAMETER ||
|
||||
GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %lx\n", GetLastError() );
|
||||
|
||||
mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
|
||||
ok( !mapping, "CreateFileMapping PAGE_WRITECOPY succeeded\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_PARAMETER ||
|
||||
GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %lx\n", GetLastError() );
|
||||
|
||||
mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
|
||||
ok( !mapping, "CreateFileMapping PAGE_READONLY succeeded\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_PARAMETER ||
|
||||
GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %lx\n", GetLastError() );
|
||||
|
||||
CloseHandle( file );
|
||||
|
||||
CloseHandle( file );
|
||||
DeleteFileA( testfile );
|
||||
}
|
||||
|
||||
START_TEST(virtual)
|
||||
{
|
||||
test_VirtualAlloc();
|
||||
test_MapViewOfFile();
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Unit test suite
|
||||
*
|
||||
* Copyright 2006 Stefan Leichter
|
||||
*
|
||||
* 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 "wine/test.h"
|
||||
#include "winbase.h"
|
||||
|
||||
#define CDROM "CDROM"
|
||||
#define FLOPPY "FLOPPY"
|
||||
#define HARDISK "HARDDISK"
|
||||
#define LANMAN "LANMANREDIRECTOR"
|
||||
#define RAMDISK "RAMDISK"
|
||||
|
||||
static void test_query_dos_deviceA(void)
|
||||
{
|
||||
char drivestr[] = "a:";
|
||||
char *p, buffer[2000];
|
||||
DWORD ret;
|
||||
for (;drivestr[0] <= 'z'; drivestr[0]++) {
|
||||
ret = QueryDosDeviceA( drivestr, buffer, sizeof(buffer));
|
||||
if(ret) {
|
||||
for (p = buffer; *p; p++) *p = toupper(*p);
|
||||
todo_wine
|
||||
ok( strstr( buffer, CDROM) || strstr( buffer, FLOPPY) ||
|
||||
strstr( buffer, HARDISK) || strstr( buffer, LANMAN) ||
|
||||
strstr( buffer, RAMDISK), "expect the string %s contains %s,%s,%s,%s or %s\n",
|
||||
buffer, CDROM, FLOPPY, HARDISK, LANMAN, RAMDISK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(volume)
|
||||
{
|
||||
test_query_dos_deviceA();
|
||||
}
|
Loading…
Reference in a new issue