--- /dev/null
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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();
+}
--- /dev/null
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+
+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 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,'.','.','.'};
+
+ 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 );
+ }
+}
+
+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];
+ WCHAR bufW[10];
+ 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" );
+ }
+
+ /* 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\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 );
+ }
+}
+
+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();
+}
--- /dev/null
+/*
+ * Tests for file change notification functions
+ *
+ * Copyright (c) 2004 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "wine/test.h"
+#include <windef.h>
+#include <winbase.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");
+
+ ret = CreateDirectoryA(dirname1, NULL);
+ ok(ret, "CreateDirectoryA error: %ld\n", GetLastError());
+
+ /* What if we remove the directory we registered notification for? */
+ thread = StartNotificationThread(dirname1, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME);
+ ret = RemoveDirectoryA(dirname1);
+ 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");
+
+ lstrcpyA(dirname2, dirname1);
+ lstrcatA(dirname2, "new");
+
+ /* 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());
+}
+
+START_TEST(change)
+{
+ test_FindFirstChangeNotification();
+}
--- /dev/null
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+
+/* 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_negative_source_length();
+ test_overlapped_buffers();
+}
--- /dev/null
+/* Unit test suite for comm functions
+ *
+ * Copyright 2003 Kevin Groeneveld
+ * Copyright 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "winbase.h"
+#include "winnls.h"
+
+#define TIMEOUT 1000 /* one second for Timeouts*/
+#define SLOWBAUD 150
+#define FASTBAUD 115200
+#define TIMEDELTA 100 /* 100 ms uncertainty allowed */
+
+/* Define the appropriate LOOPBACK(s) TRUE if you have a Loopback cable with
+ * the mentioned shorts connected to your Serial port
+ */
+#define LOOPBACK_TXD_RXD FALSE /* Sub-D 9: Short 2-3 */
+#define LOOPBACK_CTS_RTS FALSE /* Sub-D 9: Short 7-8 */
+#define LOOPBACK_DTR_DSR FALSE /* Sub-D 9: Short 4-6 */
+#define LOOPBACK_DTR_RING FALSE /* Sub-D 9: Short 4-9 */
+#define LOOPBACK_DTR_DCD FALSE /* Sub-D 9: Short 4-1 */
+
+/* SETBREAK seems to give instable results, MSDN mentions possible problems
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcedebug5/\
+ * html/wce50conSerialPortDriverTest.asp
+ * but perhaps it's only a programming error, that causes it... */
+#define BROKEN_SETBREAK TRUE
+
+typedef struct
+{
+ char string[100];
+ BOOL result;
+ BOOL old_style;
+ DCB dcb1, dcb2;
+ COMMTIMEOUTS timeouts1, timeouts2;
+} TEST;
+
+static TEST test[] =
+{
+ {
+ "baud=9600 parity=e data=5 stop=1 xon=on odsr=off octs=off dtr=on rts=on idsr=on",
+ TRUE, FALSE,
+ { 0x00000000, 0x00002580, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x05, 0x02, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x00002580, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x05, 0x02, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "baud=0 parity=M data=6 stop=1.5 xon=off odsr=on octs=ON dtr=off rts=off idsr=OFF",
+ TRUE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x06, 0x03, 0x01, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x00000000, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x06, 0x03, 0x01, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "BAUD=4000000000 parity=n data=7 stop=2 to=off",
+ TRUE, FALSE,
+ { 0x00000000, 0xee6b2800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x00, 0x02, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xee6b2800, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x00, 0x02, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
+ },
+ {
+ "Baud=115200 Parity=O Data=8 To=On",
+ TRUE, FALSE,
+ { 0x00000000, 0x0001c200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x01, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x0001c200, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x01, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 }
+ },
+ {
+ "PaRiTy=s Data=7 DTR=on",
+ TRUE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x04, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x04, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "data=4",
+ FALSE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "data=9",
+ FALSE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "parity=no",
+ FALSE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "stop=0",
+ FALSE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "stop=1.501",
+ FALSE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "stop=3",
+ FALSE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "to=foobar",
+ FALSE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ " baud=9600",
+ FALSE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "baud= 9600",
+ FALSE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "baud=9600,data=8",
+ FALSE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "11,n,8,1",
+ TRUE, TRUE,
+ { 0x00000000, 0x0000006e, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x0000006e, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "30 ,E, 5,1.5",
+ TRUE, TRUE,
+ { 0x00000000, 0x0000012c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x05, 0x02, 0x01, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x0000012c, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x05, 0x02, 0x01, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "60, m, 6, 2 ",
+ TRUE, TRUE,
+ { 0x00000000, 0x00000258, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x06, 0x03, 0x02, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x00000258, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x06, 0x03, 0x02, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "12 , o , 7 , 1",
+ TRUE, TRUE,
+ { 0x00000000, 0x000004b0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x01, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x000004b0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x01, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "24,s,8,1.5",
+ TRUE, TRUE,
+ { 0x00000000, 0x00000960, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x04, 0x01, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x00000960, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x04, 0x01, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "48,n,8,1,p",
+ TRUE, TRUE,
+ { 0x00000000, 0x000012c0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x000012c0, 1, 1, 1, 1, 2, 1, 1, 0, 0, 1, 1, 2, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "96,N,8,1 , x ",
+ TRUE, TRUE,
+ { 0x00000000, 0x00002580, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x00002580, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "19, e, 7, 1, x",
+ TRUE, TRUE,
+ { 0x00000000, 0x00004b00, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x02, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x00004b00, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x02, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "0,M,7,1,P",
+ TRUE, TRUE,
+ { 0x00000000, 0x00000000, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x03, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x00000000, 1, 1, 1, 1, 2, 1, 1, 0, 0, 1, 1, 2, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x03, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "4000000000,O,7,1.5,X",
+ TRUE, TRUE,
+ { 0x00000000, 0xee6b2800, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x01, 0x01, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xee6b2800, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x01, 0x01, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "96,N,8,1 to=on",
+ FALSE, TRUE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "96,NO,8,1",
+ FALSE, TRUE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "96,N,4,1",
+ FALSE, TRUE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "96,N,9,1",
+ FALSE, TRUE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "96,N,8,0",
+ FALSE, TRUE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "96,N,8,3",
+ FALSE, TRUE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "96,N,8,1,K",
+ FALSE, TRUE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "COM0:baud=115200",
+ FALSE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "COMx:baud=38400 data=8",
+ TRUE, FALSE,
+ { 0x00000000, 0x00009600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x00009600, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0xff, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "COMx :to=on stop=1.5",
+ TRUE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x01, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0x01, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 }
+ },
+ {
+ "COMx: baud=12345 data=7",
+ TRUE, FALSE,
+ { 0x00000000, 0x00003039, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x00003039, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0xff, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "COMx : xon=on odsr=off",
+ TRUE, FALSE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 0, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "COM0:9600,N,8,1",
+ FALSE, TRUE,
+ { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "COMx:9600,N,8,1",
+ TRUE, TRUE,
+ { 0x00000000, 0x00002580, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x00002580, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "COMx: 11,E,7,2",
+ TRUE, TRUE,
+ { 0x00000000, 0x0000006e, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x02, 0x02, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x0000006e, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x02, 0x02, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "COMx :19,M,5,1",
+ TRUE, TRUE,
+ { 0x00000000, 0x00004b00, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x05, 0x03, 0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x00004b00, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x05, 0x03, 0x00, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+ {
+ "COMx : 57600,S,6,2,x",
+ TRUE, TRUE,
+ { 0x00000000, 0x0000e100, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x06, 0x04, 0x02, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 0x0000 },
+ { 0xffffffff, 0x0000e100, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x06, 0x04, 0x02, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, 0xffff },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+ },
+};
+
+#define TEST_COUNT (sizeof(test) / sizeof(TEST))
+
+/* This function can be useful if you are modifiying the test cases and want to
+ output the contents of a DCB structure. */
+/*static print_dcb(DCB *pdcb)
+{
+ printf("0x%08x, 0x%08x, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, 0x%05x, 0x%04x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x, (char)0x%02x, (char)0x%02x, (char)0x%02x, (char)0x%02x, (char)0x%02x, 0x%04x\n",
+ pdcb->DCBlength,
+ pdcb->BaudRate,
+ pdcb->fBinary,
+ pdcb->fParity,
+ pdcb->fOutxCtsFlow,
+ pdcb->fOutxDsrFlow,
+ pdcb->fDtrControl,
+ pdcb->fDsrSensitivity,
+ pdcb->fTXContinueOnXoff,
+ pdcb->fOutX,
+ pdcb->fInX,
+ pdcb->fErrorChar,
+ pdcb->fNull,
+ pdcb->fRtsControl,
+ pdcb->fAbortOnError,
+ pdcb->fDummy2,
+ pdcb->wReserved,
+ pdcb->XonLim,
+ pdcb->XoffLim,
+ pdcb->ByteSize,
+ pdcb->Parity,
+ pdcb->StopBits,
+ pdcb->XonChar & 0xff,
+ pdcb->XoffChar & 0xff,
+ pdcb->ErrorChar & 0xff,
+ pdcb->EofChar & 0xff,
+ pdcb->EvtChar & 0xff,
+ pdcb->wReserved1 & 0xffff );
+} */
+
+static void check_result(const char *function, TEST *ptest, int initial_value, BOOL result)
+{
+ DWORD LastError = GetLastError();
+ DWORD CorrectError = (ptest->result ? 0xdeadbeef : ERROR_INVALID_PARAMETER);
+
+ ok(LastError == CorrectError, "%s(\"%s\"), 0x%02x: GetLastError() returned 0x%08lx, should be 0x%08lx\n", function, ptest->string, initial_value, LastError, CorrectError);
+ ok(result == ptest->result, "%s(\"%s\"), 0x%02x: return value should be %s\n", function, ptest->string, initial_value, ptest->result ? "TRUE" : "FALSE");
+}
+
+#define check_dcb_member(a,b) ok(pdcb1->a == pdcb2->a, "%s(\"%s\"), 0x%02x: "#a" is "b", should be "b"\n", function, ptest->string, initial_value, pdcb1->a, pdcb2->a)
+#define check_dcb_member2(a,c,b) if(pdcb2->a == c) { check_dcb_member(a,b); } else { ok(pdcb1->a == pdcb2->a || pdcb1->a == c, "%s(\"%s\"), 0x%02x: "#a" is "b", should be "b" or "b"\n", function, ptest->string, initial_value, pdcb1->a, pdcb2->a, c); }
+
+static void check_dcb(const char *function, TEST *ptest, int initial_value, DCB *pdcb1, DCB *pdcb2)
+{
+ /* DCBlength is a special case since Win 9x sets it but NT does not.
+ We will accept either as correct. */
+ check_dcb_member2(DCBlength, (DWORD)sizeof(DCB), "%lu");
+
+ /* For old style control strings Win 9x does not set the next five members, NT does. */
+ if(ptest->old_style && ptest->result)
+ {
+ check_dcb_member2(fOutxCtsFlow, ((unsigned int)initial_value & 1), "%u");
+ check_dcb_member2(fDtrControl, ((unsigned int)initial_value & 3), "%u");
+ check_dcb_member2(fOutX, ((unsigned int)initial_value & 1), "%u");
+ check_dcb_member2(fInX, ((unsigned)initial_value & 1), "%u");
+ check_dcb_member2(fRtsControl, ((unsigned)initial_value & 3), "%u");
+ }
+ else
+ {
+ check_dcb_member(fOutxCtsFlow, "%u");
+ check_dcb_member(fDtrControl, "%u");
+ check_dcb_member(fOutX, "%u");
+ check_dcb_member(fInX, "%u");
+ check_dcb_member(fRtsControl, "%u");
+ }
+
+ if(ptest->result)
+ {
+ /* For the idsr=xxx parameter, NT sets fDsrSensitivity, 9x sets
+ fOutxDsrFlow. */
+ if(!ptest->old_style)
+ {
+ check_dcb_member2(fOutxDsrFlow, pdcb2->fDsrSensitivity, "%u");
+ check_dcb_member2(fDsrSensitivity, pdcb2->fOutxDsrFlow, "%u");
+ }
+ else
+ {
+ /* For old style control strings Win 9x does not set the
+ fOutxDsrFlow member, NT does. */
+ check_dcb_member2(fOutxDsrFlow, ((unsigned int)initial_value & 1), "%u");
+ check_dcb_member(fDsrSensitivity, "%u");
+ }
+ }
+ else
+ {
+ check_dcb_member(fOutxDsrFlow, "%u");
+ check_dcb_member(fDsrSensitivity, "%u");
+ }
+
+ /* Check the result of the DCB members. */
+ check_dcb_member(BaudRate, "%lu");
+ check_dcb_member(fBinary, "%u");
+ check_dcb_member(fParity, "%u");
+ check_dcb_member(fTXContinueOnXoff, "%u");
+ check_dcb_member(fErrorChar, "%u");
+ check_dcb_member(fNull, "%u");
+ check_dcb_member(fAbortOnError, "%u");
+ check_dcb_member(fDummy2, "%u");
+ check_dcb_member(wReserved, "%u");
+ check_dcb_member(XonLim, "%u");
+ check_dcb_member(XoffLim, "%u");
+ check_dcb_member(ByteSize, "%u");
+ check_dcb_member(Parity, "%u");
+ check_dcb_member(StopBits, "%u");
+ check_dcb_member(XonChar, "%d");
+ check_dcb_member(XoffChar, "%d");
+ check_dcb_member(ErrorChar, "%d");
+ check_dcb_member(EofChar, "%d");
+ check_dcb_member(EvtChar, "%d");
+ check_dcb_member(wReserved1, "%u");
+}
+
+#define check_timeouts_member(a) ok(ptimeouts1->a == ptimeouts2->a, "%s(\"%s\"), 0x%02x: "#a" is %lu, should be %lu\n", function, ptest->string, initial_value, ptimeouts1->a, ptimeouts2->a);
+
+static void check_timeouts(const char *function, TEST *ptest, int initial_value, COMMTIMEOUTS *ptimeouts1, COMMTIMEOUTS *ptimeouts2)
+{
+ check_timeouts_member(ReadIntervalTimeout);
+ check_timeouts_member(ReadTotalTimeoutMultiplier);
+ check_timeouts_member(ReadTotalTimeoutConstant);
+ check_timeouts_member(WriteTotalTimeoutMultiplier);
+ check_timeouts_member(WriteTotalTimeoutConstant);
+}
+
+static void test_BuildCommDCBA(TEST *ptest, int initial_value, DCB *pexpected_dcb)
+{
+ BOOL result;
+ DCB dcb;
+
+ /* set initial conditions */
+ memset(&dcb, initial_value, sizeof(DCB));
+ SetLastError(0xdeadbeef);
+
+ result = BuildCommDCBA(ptest->string, &dcb);
+
+ /* check results */
+ check_result("BuildCommDCBA", ptest, initial_value, result);
+ check_dcb("BuildCommDCBA", ptest, initial_value, &dcb, pexpected_dcb);
+}
+
+static void test_BuildCommDCBAndTimeoutsA(TEST *ptest, int initial_value, DCB *pexpected_dcb, COMMTIMEOUTS *pexpected_timeouts)
+{
+ BOOL result;
+ DCB dcb;
+ COMMTIMEOUTS timeouts;
+
+ /* set initial conditions */
+ memset(&dcb, initial_value, sizeof(DCB));
+ memset(&timeouts, initial_value, sizeof(COMMTIMEOUTS));
+ SetLastError(0xdeadbeef);
+
+ result = BuildCommDCBAndTimeoutsA(ptest->string, &dcb, &timeouts);
+
+ /* check results */
+ check_result("BuildCommDCBAndTimeoutsA", ptest, initial_value, result);
+ check_dcb("BuildCommDCBAndTimeoutsA", ptest, initial_value, &dcb, pexpected_dcb);
+ check_timeouts("BuildCommDCBAndTimeoutsA", ptest, initial_value, &timeouts, pexpected_timeouts);
+}
+
+static void test_BuildCommDCBW(TEST *ptest, int initial_value, DCB *pexpected_dcb)
+{
+ BOOL result;
+ DCB dcb;
+ WCHAR wide_string[sizeof(ptest->string)];
+
+ MultiByteToWideChar(CP_ACP, 0, ptest->string, -1, wide_string, sizeof(wide_string) / sizeof(WCHAR));
+
+ /* set initial conditions */
+ memset(&dcb, initial_value, sizeof(DCB));
+ SetLastError(0xdeadbeef);
+
+ result = BuildCommDCBW(wide_string, &dcb);
+
+ if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+ return;
+
+ /* check results */
+ check_result("BuildCommDCBW", ptest, initial_value, result);
+ check_dcb("BuildCommDCBW", ptest, initial_value, &dcb, pexpected_dcb);
+}
+
+static void test_BuildCommDCBAndTimeoutsW(TEST *ptest, int initial_value, DCB *pexpected_dcb, COMMTIMEOUTS *pexpected_timeouts)
+{
+ BOOL result;
+ DCB dcb;
+ COMMTIMEOUTS timeouts;
+ WCHAR wide_string[sizeof(ptest->string)];
+
+ MultiByteToWideChar(CP_ACP, 0, ptest->string, -1, wide_string, sizeof(wide_string) / sizeof(WCHAR));
+
+ /* set initial conditions */
+ memset(&dcb, initial_value, sizeof(DCB));
+ memset(&timeouts, initial_value, sizeof(COMMTIMEOUTS));
+ SetLastError(0xdeadbeef);
+
+ result = BuildCommDCBAndTimeoutsW(wide_string, &dcb, &timeouts);
+
+ if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+ return;
+
+ /* check results */
+ check_result("BuildCommDCBAndTimeoutsA", ptest, initial_value, result);
+ check_dcb("BuildCommDCBAndTimeoutsA", ptest, initial_value, &dcb, pexpected_dcb);
+ check_timeouts("BuildCommDCBAndTimeoutsA", ptest, initial_value, &timeouts, pexpected_timeouts);
+}
+
+static void test_BuildCommDCB(void)
+{
+ char port_name[] = "COMx";
+ char port = 0;
+ unsigned int i;
+ char *ptr;
+
+ /* Some of these tests require a valid COM port. This loop will try to find
+ a valid port. */
+ for(port_name[3] = '1'; port_name[3] <= '9'; port_name[3]++)
+ {
+ COMMCONFIG commconfig;
+ DWORD size = sizeof(COMMCONFIG);
+
+ if(GetDefaultCommConfig(port_name, &commconfig, &size))
+ {
+ port = port_name[3];
+ break;
+ }
+ }
+
+ if(!port)
+ trace("Could not find a valid COM port. Some tests will be skipped.\n");
+
+ for(i = 0; i < TEST_COUNT; i++)
+ {
+ /* Check if this test case needs a valid COM port. */
+ ptr = strstr(test[i].string, "COMx");
+
+ /* If required, substitute valid port number into device control string. */
+ if(ptr)
+ {
+ if(port)
+ ptr[3] = port;
+ else
+ continue;
+ }
+
+ test_BuildCommDCBA(&test[i], 0x00, &test[i].dcb1);
+ test_BuildCommDCBA(&test[i], 0xff, &test[i].dcb2);
+ test_BuildCommDCBAndTimeoutsA(&test[i], 0x00, &test[i].dcb1, &test[i].timeouts1);
+ test_BuildCommDCBAndTimeoutsA(&test[i], 0xff, &test[i].dcb2, &test[i].timeouts2);
+
+ test_BuildCommDCBW(&test[i], 0x00, &test[i].dcb1);
+ test_BuildCommDCBW(&test[i], 0xff, &test[i].dcb2);
+ test_BuildCommDCBAndTimeoutsW(&test[i], 0x00, &test[i].dcb1, &test[i].timeouts1);
+ test_BuildCommDCBAndTimeoutsW(&test[i], 0xff, &test[i].dcb2, &test[i].timeouts2);
+ }
+}
+
+static HANDLE test_OpenComm(BOOL doOverlap)
+{
+ HANDLE hcom = INVALID_HANDLE_VALUE;
+ char port_name[] = "COMx";
+ static BOOL shown = FALSE;
+
+ /* Try to find a port */
+ for(port_name[3] = '1'; port_name[3] <= '9'; port_name[3]++)
+ {
+ hcom = CreateFile( port_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ (doOverlap)?FILE_FLAG_OVERLAPPED:0, NULL );
+ if (hcom != INVALID_HANDLE_VALUE)
+ break;
+ }
+ if(!shown)
+ {
+ if (hcom == INVALID_HANDLE_VALUE)
+ trace("Could not find a valid COM port. Skipping test_ReadTimeOut\n");
+ else
+ trace("Found Com port %s. Connected devices may disturbe results\n", port_name);
+ /*shown = TRUE; */
+ }
+ return hcom;
+}
+
+static void test_GetModemStatus(HANDLE hcom)
+{
+ DWORD ModemStat;
+
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ trace("GetCommModemStatus returned 0x%08lx->%s%s%s%s\n", ModemStat,
+ (ModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
+ (ModemStat &MS_RING_ON)?"MS_RING_ON ":"",
+ (ModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
+ (ModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
+}
+
+/* When we don't write anything, Read should time out even on a loopbacked port */
+static void test_ReadTimeOut(HANDLE hcom)
+{
+ DCB dcb;
+ COMMTIMEOUTS timeouts;
+ char rbuf[32];
+ DWORD before, after, read, timediff, LastError;
+ BOOL res;
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ dcb.BaudRate = FASTBAUD;
+ dcb.ByteSize = 8;
+ dcb.Parity = NOPARITY;
+ dcb.StopBits = ONESTOPBIT;
+ ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
+
+ ZeroMemory( &timeouts, sizeof(timeouts));
+ timeouts.ReadTotalTimeoutConstant = TIMEOUT;
+ ok(SetCommTimeouts(hcom, &timeouts),"SetCommTimeouts failed\n");
+
+ before = GetTickCount();
+ SetLastError(0xdeadbeef);
+ res = ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL);
+ LastError = GetLastError();
+ after = GetTickCount();
+ todo_wine ok( res == TRUE, "A timed-out read should return TRUE\n");
+ todo_wine ok( LastError == 0xdeadbeef, "err=%ld\n", LastError);
+ timediff = after - before;
+ ok( timediff > TIMEOUT>>2 && timediff < TIMEOUT *2,
+ "Unexpected TimeOut %ld, expected %d\n", timediff, TIMEOUT);
+}
+
+static void test_waittxempty(HANDLE hcom)
+{
+ DCB dcb;
+ COMMTIMEOUTS timeouts;
+ char tbuf[]="Some Characters\n";
+ DWORD before, after, written, timediff, evtmask = 0;
+ BOOL res_write, res;
+ DWORD baud = SLOWBAUD;
+
+ /* set a low baud rate to have ample time*/
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ dcb.BaudRate = baud;
+ dcb.ByteSize = 8;
+ dcb.Parity = NOPARITY;
+ dcb.StopBits = ONESTOPBIT;
+ ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
+
+ ZeroMemory( &timeouts, sizeof(timeouts));
+ timeouts.ReadTotalTimeoutConstant = TIMEOUT;
+ ok(SetCommTimeouts(hcom, &timeouts),"SetCommTimeouts failed\n");
+
+ ok(SetupComm(hcom,1024,1024),"SetUpComm failed\n");
+ ok(SetCommMask(hcom, EV_TXEMPTY), "SetCommMask failed\n");
+
+ before = GetTickCount();
+ res_write=WriteFile(hcom, tbuf, sizeof(tbuf), &written, NULL);
+ after = GetTickCount();
+ ok(res_write == TRUE, "WriteFile failed\n");
+ ok(written == sizeof(tbuf),
+ "WriteFile: Unexpected write_size %ld , expected %d\n", written, sizeof(tbuf));
+
+ trace("WriteFile succeeded, took %ld ms to write %d Bytes at %ld Baud\n",
+ after - before, sizeof(tbuf), baud);
+
+ before = GetTickCount();
+ res = WaitCommEvent(hcom, &evtmask, NULL);
+ after = GetTickCount();
+
+ todo_wine ok(res == TRUE, "WaitCommEvent failed\n");
+ todo_wine ok(evtmask == EV_TXEMPTY,
+ "WaitCommEvent: Unexpected EvtMask 0x%08lx, expected 0x%08x\n",
+ evtmask, EV_TXEMPTY);
+
+ timediff = after - before;
+
+ trace("WaitCommEvent for EV_TXEMPTY took %ld ms\n", timediff);
+ /* 050604: This shows a difference between XP (tested with mingw compiled crosstest):
+ XP returns Writefile only after everything went out of the Serial port,
+ while wine returns immedate.
+ Thus on XP, WaintCommEvent after setting the CommMask for EV_TXEMPTY
+ nearly return immediate,
+ while on wine the most time is spent here
+ */
+
+}
+
+/* A new open handle should not return error or have bytes in the Queues */
+static void test_ClearCommErrors(HANDLE hcom)
+{
+ DWORD errors;
+ COMSTAT lpStat;
+
+ ok(ClearCommError(hcom, &errors, &lpStat), "ClearCommError failed\n");
+ ok(lpStat.cbInQue == 0, "Unexpected %ld Bytes in InQueue\n", lpStat.cbInQue);
+ ok(lpStat.cbOutQue == 0, "Unexpected %ld Bytes in OutQueue\n", lpStat.cbOutQue);
+ ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08lx\n", errors);
+}
+
+/**/
+static void test_LoopbackRead(HANDLE hcom)
+{
+ DCB dcb;
+ COMMTIMEOUTS timeouts;
+ char rbuf[32];
+ DWORD before, after, diff, read, written, evtmask=0;
+ BOOL res;
+ char tbuf[]="Some Characters\n";
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ dcb.BaudRate = FASTBAUD;
+ dcb.ByteSize = 8;
+ dcb.Parity = NOPARITY;
+ dcb.StopBits = ONESTOPBIT;
+ ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
+
+ ZeroMemory( &timeouts, sizeof(timeouts));
+ timeouts.ReadTotalTimeoutConstant = TIMEOUT;
+ ok(SetCommTimeouts(hcom, &timeouts),"SetCommTimeouts failed\n");
+
+ ok(SetCommMask(hcom, EV_TXEMPTY), "SetCommMask failed\n");
+
+ ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n");
+ ok(written == sizeof(tbuf),"WriteFile %ld bytes written, expected %d\n",
+ written, sizeof(tbuf));
+
+ /* make sure all bytes are written, so Readfile will succeed in one call*/
+ todo_wine ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n");
+ todo_wine ok(evtmask == EV_TXEMPTY,
+ "WaitCommEvent: Unexpected EvtMask 0x%08lx, expected 0x%08x\n",
+ evtmask, EV_TXEMPTY);
+
+ read=0;
+ todo_wine ok(ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL), "Readfile failed\n");
+ todo_wine ok(read == sizeof(tbuf),"ReadFile read %ld bytes, expected %d\n", read, sizeof(tbuf));
+
+ /* Now do the same withe a slow Baud rate.
+ On XP, nothing should change, as WriteFile only returns
+ after all Bytes have gone to the physical line
+ */
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ dcb.BaudRate = 9600;
+ dcb.ByteSize = 8;
+ dcb.Parity = NOPARITY;
+ dcb.StopBits = ONESTOPBIT;
+ ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
+
+ ok(SetCommMask(hcom, EV_RXCHAR), "SetCommMask failed\n");
+ ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n");
+ ok(written == sizeof(tbuf),"WriteFile %ld bytes written, expected %d\n",
+ written, sizeof(tbuf));
+
+ todo_wine ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n");
+ todo_wine ok(evtmask == EV_RXCHAR, "WaitCommEvent: Unexpected EvtMask 0x%08lx, expected 0x%08x\n",
+ evtmask, EV_RXCHAR);
+
+ before = GetTickCount();
+ res = ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL);
+ after = GetTickCount();
+ todo_wine ok(res, "Readfile failed\n");
+ todo_wine ok(read == sizeof(tbuf),"ReadFile read %ld bytes, expected %d\n", read, sizeof(tbuf));
+ diff = after - before;
+ trace("Readfile for %d chars with %d avail took %ld ms\n",
+ sizeof(rbuf), sizeof(tbuf), diff);
+ ok( (diff > TIMEOUT - TIMEDELTA) && (diff < TIMEOUT + TIMEDELTA),
+ "Timedout Wait took %ld ms, expected around %d\n", diff, TIMEOUT);
+}
+
+static void test_LoopbackCtsRts(HANDLE hcom)
+{
+ DWORD ModemStat, defaultStat;
+ DCB dcb;
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ if (dcb.fRtsControl == RTS_CONTROL_HANDSHAKE)
+ {
+ trace("RTS_CONTROL_HANDSHAKE is set, so don't manipulate RTS\n");
+ return;
+ }
+ ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
+ /* XP returns some values in the low nibble, so mask them out*/
+ defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
+ if(defaultStat & MS_CTS_ON)
+ {
+ ok(EscapeCommFunction(hcom, CLRRTS), "EscapeCommFunction failed to clear RTS\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ ok ((ModemStat & MS_CTS_ON) == 0, "CTS didn't react: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, (defaultStat & ~MS_CTS_ON));
+ ok(EscapeCommFunction(hcom, SETRTS), "EscapeCommFunction failed to clear RTS\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ ok (ModemStat == defaultStat, "Failed to restore CTS: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, defaultStat);
+ }
+ else
+ {
+ ok(EscapeCommFunction(hcom, SETRTS), "EscapeCommFunction failed to set RTS\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ todo_wine ok ((ModemStat & MS_CTS_ON) == MS_CTS_ON,
+ "CTS didn't react: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, (defaultStat | MS_CTS_ON));
+ ok(EscapeCommFunction(hcom, CLRRTS), "EscapeCommFunction failed to clear RTS\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ ok (ModemStat == defaultStat, "Failed to restore CTS: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, defaultStat);
+ }
+}
+
+static void test_LoopbackDtrDcd(HANDLE hcom)
+{
+ DWORD ModemStat, defaultStat;
+ DCB dcb;
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ if (dcb.fDtrControl == DTR_CONTROL_HANDSHAKE)
+ {
+ trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
+ return;
+ }
+ ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
+ /* XP returns some values in the low nibble, so mask them out*/
+ defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
+ if(defaultStat & MS_RLSD_ON)
+ {
+ ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ ok ((ModemStat & MS_RLSD_ON) == 0, "RLSD didn't react: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, (defaultStat & ~MS_RLSD_ON));
+ ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ ok (ModemStat == defaultStat, "Failed to restore RLSD: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, defaultStat);
+ }
+ else
+ {
+ ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ todo_wine ok ((ModemStat & MS_RLSD_ON) == MS_RLSD_ON,
+ "RLSD didn't react: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, (defaultStat | MS_RLSD_ON));
+ ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ ok (ModemStat == defaultStat, "Failed to restore RLSD: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, defaultStat);
+ }
+}
+
+static void test_LoopbackDtrDsr(HANDLE hcom)
+{
+ DWORD ModemStat, defaultStat;
+ DCB dcb;
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
+ {
+ trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
+ return;
+ }
+ ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
+ /* XP returns some values in the low nibble, so mask them out*/
+ defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
+ if(defaultStat & MS_DSR_ON)
+ {
+ ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ ok ((ModemStat & MS_DSR_ON) == 0, "CTS didn't react: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, (defaultStat & ~MS_DSR_ON));
+ ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to clear DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ todo_wine ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, defaultStat);
+ }
+ else
+ {
+ ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ todo_wine ok ((ModemStat & MS_DSR_ON) == MS_DSR_ON,
+ "CTS didn't react: 0x%04lx,expected 0x%04lx\n",
+ ModemStat, (defaultStat | MS_DSR_ON));
+ ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, defaultStat);
+ }
+}
+
+static void test_LoopbackDtrRing(HANDLE hcom)
+{
+ DWORD ModemStat, defaultStat;
+ DCB dcb;
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ if (dcb.fDtrControl == DTR_CONTROL_HANDSHAKE)
+ {
+ trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
+ return;
+ }
+ ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
+ /* XP returns some values in the low nibble, so mask them out*/
+ defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
+ if(defaultStat & MS_RING_ON)
+ {
+ ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ ok ((ModemStat & MS_RING_ON) == 0, "RING didn't react: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, (defaultStat & ~MS_RING_ON));
+ ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ ok (ModemStat == defaultStat, "Failed to restore RING: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, defaultStat);
+ }
+ else
+ {
+ ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ todo_wine ok ((ModemStat & MS_RING_ON) == MS_RING_ON,
+ "RING didn't react: 0x%04lx,expected 0x%04lx\n",
+ ModemStat, (defaultStat | MS_RING_ON));
+ ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
+ ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
+ ok (ModemStat == defaultStat, "Failed to restore RING: 0x%04lx, expected 0x%04lx\n",
+ ModemStat, defaultStat);
+ }
+}
+
+/*
+ Set up a WaitCommEvent for anything in the receive buffer,
+ then write to TX to put a character
+ into the RX buffer via the Loopback
+*/
+
+static void test_WaitRx(HANDLE hcom)
+{
+ OVERLAPPED overlapped, overlapped_w;
+ HANDLE hComPortEvent, hComWriteEvent;
+ DWORD before, after, after1, diff, success_wait = FALSE, success_write;
+ DWORD err_wait, err_write, written, evtmask=0;
+
+ ok(SetCommMask(hcom, EV_RXCHAR), "SetCommMask failed\n");
+ hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ ok(hComPortEvent != 0, "CreateEvent failed\n");
+ ZeroMemory( &overlapped, sizeof(overlapped));
+ overlapped.hEvent = hComPortEvent;
+
+ ok((hComWriteEvent = CreateEvent( NULL, TRUE, FALSE, NULL )) !=0,
+ "CreateEvent res 0x%08lx\n",
+ GetLastError());
+ ZeroMemory( &overlapped_w, sizeof(overlapped_w));
+ overlapped_w.hEvent = hComWriteEvent;
+
+ before = GetTickCount();
+ todo_wine {success_wait = WaitCommEvent(hcom, &evtmask, &overlapped);}
+ err_wait = GetLastError();
+ after = GetTickCount();
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success_wait, err_wait, evtmask);
+ todo_wine ok(success_wait || err_wait == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ trace("overlapped WriteCommEvent returned.\n");
+
+ success_write= WriteFile(hcom, "X", 1, &written, &overlapped_w);
+ err_write = GetLastError();
+ ok(success_write || err_write == ERROR_IO_PENDING,
+ "overlapped WriteFile failed, err 0x%08lx\n",
+ err_write);
+
+ if (!success_write && (err_write == ERROR_IO_PENDING)) {
+ success_write = WaitForSingleObjectEx(hComWriteEvent, TIMEOUT, TRUE);
+ err_write = GetLastError();
+ ok(success_write == WAIT_OBJECT_0, "WaitForSingleObjectEx, res 0x%08lx, err 0x%08lx\n",
+ success_write, err_write);
+ }
+ Sleep(TIMEOUT >>1);
+ success_write = GetOverlappedResult(hcom, &overlapped_w, &written, FALSE);
+ err_write = GetLastError();
+
+ trace("Write after Wait res 0x%08lx err 0x%08lx\n",success_write, err_write);
+ ok(success_write && written ==1, "Write after Wait res 0x%08lx err 0x%08lx\n",
+ success_write, err_write);
+
+ if (!success_wait && (err_wait == ERROR_IO_PENDING)) {
+ success_wait = WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE);
+ err_wait = GetLastError();
+ ok(success_wait == WAIT_OBJECT_0, "wait hComPortEvent, res 0x%08lx, err 0x%08lx\n",
+ success_wait, err_wait);
+ }
+ success_wait = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
+ err_wait = GetLastError();
+ after1 = GetTickCount();
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
+ success_wait, err_wait, evtmask, after-before, after1-before);
+
+ todo_wine ok(evtmask & EV_RXCHAR, "Detect EV_RXCHAR: 0x%08lx, expected 0x%08x\n",
+ evtmask, EV_RXCHAR);
+ diff = after1 - before;
+ ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
+ "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
+
+}
+
+/* Change the controling line after the given timeout to the given state
+ By the loopback, this should trigger the WaitCommEvent
+*/
+static DWORD CALLBACK toggle_ctlLine(LPVOID arg)
+{
+ DWORD *args = (DWORD *) arg;
+ DWORD timeout = args[0];
+ DWORD ctl = args[1];
+ HANDLE hcom = (HANDLE) args[2];
+ HANDLE hComPortEvent = (HANDLE) args[3];
+ DWORD success, err;
+
+ trace("toggle_ctlLine timeout %ld clt 0x%08lx handle 0x%08lx\n",
+ args[0], args[1], args[2]);
+ Sleep(timeout);
+ ok(EscapeCommFunction(hcom, ctl),"EscapeCommFunction 0x%08lx failed\n", ctl);
+ trace("toggle_ctline done\n");
+ success = WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE);
+ err = GetLastError();
+ trace("toggle_ctline WaitForSingleObjectEx res 0x%08lx err 0x%08lx\n",
+ success, err);
+ return 0;
+}
+
+static void test_WaitCts(HANDLE hcom)
+{
+ DCB dcb;
+ OVERLAPPED overlapped;
+ HANDLE hComPortEvent;
+ HANDLE alarmThread;
+ DWORD args[4], defaultStat;
+ DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0;
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ if (dcb.fDtrControl == RTS_CONTROL_DISABLE)
+ {
+ trace("RTS_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
+ return;
+ }
+ args[0]= TIMEOUT >>1;
+ ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
+ if(defaultStat & MS_CTS_ON)
+ args[1] = CLRRTS;
+ else
+ args[1] = SETRTS;
+ args[2]=(DWORD) hcom;
+
+ trace("test_WaitCts timeout %ld clt 0x%08lx handle 0x%08lx\n",args[0], args[1], args[2]);
+
+ ok(SetCommMask(hcom, EV_CTS), "SetCommMask failed\n");
+ hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ ok(hComPortEvent != 0, "CreateEvent failed\n");
+ args[3] = (DWORD) hComPortEvent;
+ alarmThread = CreateThread(NULL, 0, toggle_ctlLine, (void *) &args, 0, &alarmThreadId);
+ Sleep(100);
+ trace("Thread created\n");
+ ok(alarmThread !=0 , "CreateThread Failed\n");
+
+ ZeroMemory( &overlapped, sizeof(overlapped));
+ overlapped.hEvent = hComPortEvent;
+ before = GetTickCount();
+ success = WaitCommEvent(hcom, &evtmask, &overlapped);
+ err = GetLastError();
+ after = GetTickCount();
+
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success, err, evtmask);
+ todo_wine ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ trace("overlapped WriteCommEvent returned.\n");
+ if (!success && (err == ERROR_IO_PENDING))
+ todo_wine ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
+ "wait hComPortEvent failed\n");
+ success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
+ err = GetLastError();
+ after1 = GetTickCount();
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
+ success, err, evtmask, after-before, after1-before);
+
+ todo_wine ok(evtmask & EV_CTS, "Failed to detect EV_CTS: 0x%08lx, expected 0x%08x\n",
+ evtmask, EV_CTS);
+ ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
+ if(defaultStat & MS_CTS_ON)
+ todo_wine ok((evtmask & MS_CTS_ON) == 0,"CTS didn't change state!\n");
+ else
+ todo_wine ok((evtmask & MS_CTS_ON), "CTS didn't change state!\n");
+
+ diff = after1 - before;
+ todo_wine ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
+ "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
+
+ /*restore RTS Settings*/
+ if(defaultStat & MS_CTS_ON)
+ args[1] = SETRTS;
+ else
+ args[1] = CLRRTS;
+}
+
+static void test_WaitDsr(HANDLE hcom)
+{
+ DCB dcb;
+ OVERLAPPED overlapped;
+ HANDLE hComPortEvent;
+ HANDLE alarmThread;
+ DWORD args[3], defaultStat;
+ DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0;
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
+ {
+ trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
+ return;
+ }
+ args[0]= TIMEOUT >>1;
+ ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
+ if(defaultStat & MS_DSR_ON)
+ args[1] = CLRDTR;
+ else
+ args[1] = SETDTR;
+ args[2]=(DWORD) hcom;
+
+ trace("test_WaitDsr timeout %ld clt 0x%08lx handle 0x%08lx\n",args[0], args[1], args[2]);
+
+ ok(SetCommMask(hcom, EV_DSR), "SetCommMask failed\n");
+ hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ ok(hComPortEvent != 0, "CreateEvent failed\n");
+ alarmThread = CreateThread(NULL, 0, toggle_ctlLine, (void *) &args, 0, &alarmThreadId);
+ ok(alarmThread !=0 , "CreateThread Failed\n");
+
+ ZeroMemory( &overlapped, sizeof(overlapped));
+ overlapped.hEvent = hComPortEvent;
+ before = GetTickCount();
+ success = WaitCommEvent(hcom, &evtmask, &overlapped);
+ err = GetLastError();
+ after = GetTickCount();
+
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success, err, evtmask);
+ todo_wine ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ trace("overlapped WriteCommEvent returned.\n");
+ if (!success && (err == ERROR_IO_PENDING))
+ todo_wine ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
+ "wait hComPortEvent failed\n");
+ success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
+ err = GetLastError();
+ after1 = GetTickCount();
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
+ success, err, evtmask, after-before, after1-before);
+
+ todo_wine ok(evtmask & EV_DSR, "Failed to detect EV_DSR: 0x%08lx, expected 0x%08x\n",
+ evtmask, EV_CTS);
+ ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
+ if(defaultStat & MS_DSR_ON)
+ todo_wine ok((evtmask & MS_DSR_ON) == 0,"DTR didn't change state!\n");
+ else
+ todo_wine ok((evtmask & MS_DSR_ON), "DTR didn't change state!\n");
+
+ diff = after1 - before;
+ todo_wine ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
+ "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
+
+ /*restore RTS Settings*/
+ if(defaultStat & MS_DSR_ON)
+ args[1] = SETDTR;
+ else
+ args[1] = CLRDTR;
+}
+
+static void test_WaitRing(HANDLE hcom)
+{
+ DCB dcb;
+ OVERLAPPED overlapped;
+ HANDLE hComPortEvent;
+ HANDLE alarmThread;
+ DWORD args[3], defaultStat;
+ DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0;
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
+ {
+ trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
+ return;
+ }
+ args[0]= TIMEOUT >>1;
+ ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
+ if(defaultStat & MS_RING_ON)
+ args[1] = CLRDTR;
+ else
+ args[1] = SETDTR;
+ args[2]=(DWORD) hcom;
+
+ trace("test_WaitRing timeout %ld clt 0x%08lx handle 0x%08lx\n",args[0], args[1], args[2]);
+
+ ok(SetCommMask(hcom, EV_RING), "SetCommMask failed\n");
+ hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ ok(hComPortEvent != 0, "CreateEvent failed\n");
+ alarmThread = CreateThread(NULL, 0, toggle_ctlLine, (void *) &args, 0, &alarmThreadId);
+ ok(alarmThread !=0 , "CreateThread Failed\n");
+
+ ZeroMemory( &overlapped, sizeof(overlapped));
+ overlapped.hEvent = hComPortEvent;
+ before = GetTickCount();
+ success = WaitCommEvent(hcom, &evtmask, &overlapped);
+ err = GetLastError();
+ after = GetTickCount();
+
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success, err, evtmask);
+ todo_wine ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ trace("overlapped WriteCommEvent returned.\n");
+ if (!success && (err == ERROR_IO_PENDING))
+ todo_wine ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
+ "wait hComPortEvent failed\n");
+ success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
+ err = GetLastError();
+ after1 = GetTickCount();
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
+ success, err, evtmask, after-before, after1-before);
+
+ todo_wine ok(evtmask & EV_RING, "Failed to detect EV_RING: 0x%08lx, expected 0x%08x\n",
+ evtmask, EV_CTS);
+ ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
+ if(defaultStat & MS_RING_ON)
+ todo_wine ok((evtmask & MS_RING_ON) == 0,"DTR didn't change state!\n");
+ else
+ todo_wine ok((evtmask & MS_RING_ON), "DTR didn't change state!\n");
+
+ diff = after1 - before;
+ todo_wine ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
+ "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
+
+ /*restore RTS Settings*/
+ if(defaultStat & MS_RING_ON)
+ args[1] = SETDTR;
+ else
+ args[1] = CLRDTR;
+}
+
+static void test_WaitDcd(HANDLE hcom)
+{
+ DCB dcb;
+ OVERLAPPED overlapped;
+ HANDLE hComPortEvent;
+ HANDLE alarmThread;
+ DWORD args[3], defaultStat;
+ DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0;
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
+ {
+ trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
+ return;
+ }
+ args[0]= TIMEOUT >>1;
+ ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
+ if(defaultStat & MS_RLSD_ON)
+ args[1] = CLRDTR;
+ else
+ args[1] = SETDTR;
+ args[2]=(DWORD) hcom;
+
+ trace("test_WaitDcd timeout %ld clt 0x%08lx handle 0x%08lx\n",args[0], args[1], args[2]);
+
+ ok(SetCommMask(hcom, EV_RLSD), "SetCommMask failed\n");
+ hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ ok(hComPortEvent != 0, "CreateEvent failed\n");
+ alarmThread = CreateThread(NULL, 0, toggle_ctlLine, (void *) &args, 0, &alarmThreadId);
+ ok(alarmThread !=0 , "CreateThread Failed\n");
+
+ ZeroMemory( &overlapped, sizeof(overlapped));
+ overlapped.hEvent = hComPortEvent;
+ before = GetTickCount();
+ success = WaitCommEvent(hcom, &evtmask, &overlapped);
+ err = GetLastError();
+ after = GetTickCount();
+
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success, err, evtmask);
+ todo_wine ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ trace("overlapped WriteCommEvent returned.\n");
+ if (!success && (err == ERROR_IO_PENDING))
+ todo_wine ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
+ "wait hComPortEvent failed\n");
+ success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
+ err = GetLastError();
+ after1 = GetTickCount();
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
+ success, err, evtmask, after-before, after1-before);
+
+ todo_wine ok(evtmask & EV_RLSD, "Failed to detect EV_RLSD: 0x%08lx, expected 0x%08x\n",
+ evtmask, EV_CTS);
+ ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
+ if(defaultStat & MS_RLSD_ON)
+ todo_wine ok((evtmask & MS_RLSD_ON) == 0,"DTR didn't change state!\n");
+ else
+ todo_wine ok((evtmask & MS_RLSD_ON), "DTR didn't change state!\n");
+
+ diff = after1 - before;
+ todo_wine ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
+ "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
+
+ /*restore RTS Settings*/
+ if(defaultStat & MS_RLSD_ON)
+ args[1] = SETDTR;
+ else
+ args[1] = CLRDTR;
+}
+
+/*
+ Set the Break status after the given timeout to the given state
+*/
+static void test_WaitBreak(HANDLE hcom)
+{
+ OVERLAPPED overlapped;
+ HANDLE hComPortEvent;
+ DWORD before, after, after1, diff, success, err, written, evtmask=0;
+
+ ok(SetCommMask(hcom, EV_BREAK), "SetCommMask failed\n");
+ hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ ok(hComPortEvent != 0, "CreateEvent failed\n");
+
+ ZeroMemory( &overlapped, sizeof(overlapped));
+ overlapped.hEvent = hComPortEvent;
+ before = GetTickCount();
+ success = WaitCommEvent(hcom, &evtmask, &overlapped);
+ err = GetLastError();
+ after = GetTickCount();
+
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success, err, evtmask);
+ ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ trace("overlapped WriteCommEvent returned.\n");
+
+ Sleep(TIMEOUT >>1);
+
+ ok(SetCommBreak(hcom), "SetCommBreak err 0x%08lx\n", GetLastError());
+ trace("Break set\n");
+ ok(ClearCommError(hcom, &err, NULL),"ClearCommError err 0x%08lx\n", GetLastError());
+ ok((err & CE_BREAK)!= 0, "Break condition should be reported\n");
+ ok(ClearCommBreak(hcom), "ClearCommBreak err 0x%08lx\n", GetLastError());
+ trace("Break cleared\n");
+ ok(ClearCommError(hcom, &err, NULL),"ClearCommError err 0x%08lx\n", GetLastError());
+ ok((err & CE_BREAK)== 0, "Break should be cleared now\n");
+
+ if (!success && (err == ERROR_IO_PENDING))
+ ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
+ "wait hComPortEvent res 0x%08lx\n", GetLastError());
+ success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
+ err = GetLastError();
+ after1 = GetTickCount();
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
+ success, err, evtmask, after-before, after1-before);
+
+ ok(evtmask & EV_BREAK, "Failed to detect EV_BREAK: 0x%08lx, expected 0x%08x\n",
+ evtmask, EV_BREAK);
+ ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
+
+ diff = after1 - before;
+ ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
+ "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
+
+}
+
+START_TEST(comm)
+{
+ HANDLE hcom;
+ /* use variabel and not #define to compile the code */
+ BOOL loopback_txd_rxd = LOOPBACK_TXD_RXD;
+ BOOL loopback_rts_cts = LOOPBACK_CTS_RTS;
+ BOOL loopback_dtr_dsr = LOOPBACK_DTR_DSR;
+ BOOL loopback_dtr_ring = LOOPBACK_DTR_RING;
+ BOOL loopback_dtr_dcd = LOOPBACK_DTR_DCD;
+ BOOL broken_setbreak = BROKEN_SETBREAK;
+
+#if 1
+ test_BuildCommDCB();
+ hcom = test_OpenComm(FALSE);
+ if (hcom != INVALID_HANDLE_VALUE)
+ {
+ test_GetModemStatus(hcom);
+ test_ReadTimeOut(hcom);
+ test_waittxempty(hcom);
+ CloseHandle(hcom);
+ }
+ hcom = test_OpenComm(FALSE);
+ if (hcom != INVALID_HANDLE_VALUE)
+ {
+ test_ClearCommErrors(hcom);
+ CloseHandle(hcom);
+ }
+ if((loopback_txd_rxd) && ((hcom = test_OpenComm(FALSE))!=INVALID_HANDLE_VALUE))
+ {
+ test_LoopbackRead(hcom);
+ CloseHandle(hcom);
+ }
+ if((loopback_rts_cts) && ((hcom = test_OpenComm(FALSE))!=INVALID_HANDLE_VALUE))
+ {
+ test_LoopbackCtsRts(hcom);
+ CloseHandle(hcom);
+ }
+ if((loopback_dtr_dsr) && ((hcom = test_OpenComm(FALSE))!=INVALID_HANDLE_VALUE))
+ {
+ test_LoopbackDtrDsr(hcom);
+ CloseHandle(hcom);
+ }
+ if((loopback_dtr_ring) && ((hcom = test_OpenComm(FALSE))!=INVALID_HANDLE_VALUE))
+ {
+ test_LoopbackDtrRing(hcom);
+ CloseHandle(hcom);
+ }
+ if((loopback_dtr_dcd) && ((hcom = test_OpenComm(FALSE))!=INVALID_HANDLE_VALUE))
+ {
+ test_LoopbackDtrDcd(hcom);
+ CloseHandle(hcom);
+ }
+#endif
+ if((loopback_txd_rxd) && ((hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE))
+ {
+ test_WaitRx(hcom);
+ CloseHandle(hcom);
+ }
+#if 1
+ if((loopback_rts_cts) && ((hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE))
+ {
+ test_WaitCts(hcom);
+ CloseHandle(hcom);
+ }
+ if((loopback_dtr_dsr) && ((hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE))
+ {
+ test_WaitDsr(hcom);
+ CloseHandle(hcom);
+ }
+ if((loopback_dtr_ring) && ((hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE))
+ {
+ test_WaitRing(hcom);
+ CloseHandle(hcom);
+ }
+ if((loopback_dtr_dcd) && ((hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE))
+ {
+ test_WaitDcd(hcom);
+ CloseHandle(hcom);
+ }
+ if(!broken_setbreak && (hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE)
+ {
+ test_WaitBreak(hcom);
+ CloseHandle(hcom);
+ }
+#endif
+}
--- /dev/null
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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);
+ ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
+ mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
+ mch_count = 0;
+ 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();
+ AllocConsole();
+ 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 */
+ /* this one is disabled for now, Wine's result are way too bad */
+ testScroll(hConOut, sbi.dwSize);
+ /* will test sb creation / modification... */
+ /* testScreenBuffer() */
+ testCtrlHandler();
+ /* still to be done: access rights & access on objects */
+}
--- /dev/null
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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();
+}
--- /dev/null
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+
+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());
+ }
+ 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)
+{
+ test_GetDriveTypeA();
+ test_GetDriveTypeW();
+
+ test_GetDiskFreeSpaceA();
+ test_GetDiskFreeSpaceW();
+}
--- /dev/null
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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();
+}
--- /dev/null
+/*
+ * Unit tests for file functions in Wine
+ *
+ * Copyright (c) 2002, 2004 Jakob Eriksson
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+
+static int dll_capable(const char *dll, const char *function)
+{
+ HMODULE module = GetModuleHandleA(dll);
+ if (!module) return 0;
+
+ return (GetProcAddress(module, function) != NULL);
+}
+
+
+LPCSTR filename = "testfile.xxx";
+LPCSTR sillytext =
+"en larvig liten text dx \033 gx hej 84 hej 4484 ! \001\033 bla bl\na.. bla bla."
+"1234 43 4kljf lf &%%%&&&&&& 34 4 34 3############# 33 3 3 3 # 3## 3"
+"1234 43 4kljf lf &%%%&&&&&& 34 4 34 3############# 33 3 3 3 # 3## 3"
+"1234 43 4kljf lf &%%%&&&&&& 34 4 34 3############# 33 3 3 3 # 3## 3"
+"1234 43 4kljf lf &%%%&&&&&& 34 4 34 3############# 33 3 3 3 # 3## 3"
+"1234 43 4kljf lf &%%%&&&&&& 34 4 34 3############# 33 3 3 3 # 3## 3"
+"1234 43 4kljf lf &%%%&&&&&& 34 4 34 3############# 33 3 3 3 # 3## 3"
+"1234 43 4kljf lf &%%%&&&&&& 34 4 34 3############# 33 3 3 3 # 3## 3"
+"1234 43 4kljf lf &%%%&&&&&& 34 4 34 3############# 33 3 3 3 # 3## 3"
+"sdlkfjasdlkfj a dslkj adsklf \n \nasdklf askldfa sdlkf \nsadklf asdklf asdf ";
+
+
+static void test__hread( void )
+{
+ HFILE filehandle;
+ char buffer[10000];
+ long bytes_read;
+ long bytes_wanted;
+ long i;
+ BOOL ret;
+
+ SetFileAttributesA(filename,FILE_ATTRIBUTE_NORMAL); /* be sure to remove stale files */
+ DeleteFileA( filename );
+ filehandle = _lcreat( filename, 0 );
+ if (filehandle == HFILE_ERROR)
+ {
+ ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError());
+ return;
+ }
+
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite complains\n" );
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ filehandle = _lopen( filename, OF_READ );
+
+ ok( HFILE_ERROR != filehandle, "couldn't open file \"%s\" again (err=%ld)\n", filename, GetLastError( ) );
+
+ bytes_read = _hread( filehandle, buffer, 2 * strlen( sillytext ) );
+
+ ok( lstrlenA( sillytext ) == bytes_read, "file read size error\n" );
+
+ for (bytes_wanted = 0; bytes_wanted < lstrlenA( sillytext ); bytes_wanted++)
+ {
+ ok( 0 == _llseek( filehandle, 0, FILE_BEGIN ), "_llseek complains\n" );
+ ok( _hread( filehandle, buffer, bytes_wanted ) == bytes_wanted, "erratic _hread return value\n" );
+ for (i = 0; i < bytes_wanted; i++)
+ {
+ ok( buffer[i] == sillytext[i], "that's not what's written\n" );
+ }
+ }
+
+ ok( HFILE_ERROR != _lclose( filehandle ), "_lclose complains\n" );
+
+ ret = DeleteFileA( filename );
+ ok( ret != 0, "DeleteFile failed (%ld)\n", GetLastError( ) );
+}
+
+
+static void test__hwrite( void )
+{
+ HFILE filehandle;
+ char buffer[10000];
+ long bytes_read;
+ long bytes_written;
+ long blocks;
+ long i;
+ char *contents;
+ HLOCAL memory_object;
+ char checksum[1];
+ BOOL ret;
+
+ filehandle = _lcreat( filename, 0 );
+ if (filehandle == HFILE_ERROR)
+ {
+ ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError());
+ return;
+ }
+
+ ok( HFILE_ERROR != _hwrite( filehandle, "", 0 ), "_hwrite complains\n" );
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ filehandle = _lopen( filename, OF_READ );
+
+ bytes_read = _hread( filehandle, buffer, 1);
+
+ ok( 0 == bytes_read, "file read size error\n" );
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ filehandle = _lopen( filename, OF_READWRITE );
+
+ bytes_written = 0;
+ checksum[0] = '\0';
+ srand( (unsigned)time( NULL ) );
+ for (blocks = 0; blocks < 100; blocks++)
+ {
+ for (i = 0; i < (long)sizeof( buffer ); i++)
+ {
+ buffer[i] = rand( );
+ checksum[0] = checksum[0] + buffer[i];
+ }
+ ok( HFILE_ERROR != _hwrite( filehandle, buffer, sizeof( buffer ) ), "_hwrite complains\n" );
+ bytes_written = bytes_written + sizeof( buffer );
+ }
+
+ ok( HFILE_ERROR != _hwrite( filehandle, checksum, 1 ), "_hwrite complains\n" );
+ bytes_written++;
+
+ ok( HFILE_ERROR != _lclose( filehandle ), "_lclose complains\n" );
+
+ memory_object = LocalAlloc( LPTR, bytes_written );
+
+ ok( 0 != memory_object, "LocalAlloc fails. (Could be out of memory.)\n" );
+
+ contents = LocalLock( memory_object );
+
+ filehandle = _lopen( filename, OF_READ );
+
+ contents = LocalLock( memory_object );
+
+ ok( NULL != contents, "LocalLock whines\n" );
+
+ ok( bytes_written == _hread( filehandle, contents, bytes_written), "read length differ from write length\n" );
+
+ checksum[0] = '\0';
+ i = 0;
+ do
+ {
+ checksum[0] = checksum[0] + contents[i];
+ i++;
+ }
+ while (i < bytes_written - 1);
+
+ ok( checksum[0] == contents[i], "stored checksum differ from computed checksum\n" );
+
+ ok( HFILE_ERROR != _lclose( filehandle ), "_lclose complains\n" );
+
+ ret = DeleteFileA( filename );
+ ok( ret != 0, "DeleteFile failed (%ld)\n", GetLastError( ) );
+}
+
+
+static void test__lclose( void )
+{
+ HFILE filehandle;
+ BOOL ret;
+
+ filehandle = _lcreat( filename, 0 );
+ if (filehandle == HFILE_ERROR)
+ {
+ ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError());
+ return;
+ }
+
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite complains\n" );
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ ret = DeleteFileA( filename );
+ ok( ret != 0, "DeleteFile failed (%ld)\n", GetLastError( ) );
+}
+
+
+static void test__lcreat( void )
+{
+ HFILE filehandle;
+ char buffer[10000];
+ WIN32_FIND_DATAA search_results;
+ char slashname[] = "testfi/";
+ int err;
+ HANDLE find;
+ BOOL ret;
+
+ filehandle = _lcreat( filename, 0 );
+ if (filehandle == HFILE_ERROR)
+ {
+ ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError());
+ return;
+ }
+
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite complains\n" );
+
+ ok( 0 == _llseek( filehandle, 0, FILE_BEGIN ), "_llseek complains\n" );
+
+ ok( _hread( filehandle, buffer, strlen( sillytext ) ) == lstrlenA( sillytext ), "erratic _hread return value\n" );
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ ok( INVALID_HANDLE_VALUE != FindFirstFileA( filename, &search_results ), "should be able to find file\n" );
+
+ ret = DeleteFileA(filename);
+ ok( ret != 0, "DeleteFile failed (%ld)\n", GetLastError());
+
+ filehandle = _lcreat( filename, 1 ); /* readonly */
+ ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%ld)\n", filename, GetLastError( ) );
+
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite shouldn't be able to write never the less\n" );
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ ok( INVALID_HANDLE_VALUE != FindFirstFileA( filename, &search_results ), "should be able to find file\n" );
+
+ ok( 0 == DeleteFileA( filename ), "shouldn't be able to delete a readonly file\n" );
+
+ ok( SetFileAttributesA(filename, FILE_ATTRIBUTE_NORMAL ) != 0, "couldn't change attributes on file\n" );
+
+ ok( DeleteFileA( filename ) != 0, "now it should be possible to delete the file!\n" );
+
+ filehandle = _lcreat( filename, 2 );
+ ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%ld)\n", filename, GetLastError( ) );
+
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite complains\n" );
+
+ ok( 0 == _llseek( filehandle, 0, FILE_BEGIN ), "_llseek complains\n" );
+
+ ok( _hread( filehandle, buffer, strlen( sillytext ) ) == lstrlenA( sillytext ), "erratic _hread return value\n" );
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ ok( INVALID_HANDLE_VALUE != FindFirstFileA( filename, &search_results ), "should STILL be able to find file\n" );
+
+ ret = DeleteFileA( filename );
+ ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) );
+
+ filehandle = _lcreat( filename, 4 ); /* SYSTEM file */
+ ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%ld)\n", filename, GetLastError( ) );
+
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite complains\n" );
+
+ ok( 0 == _llseek( filehandle, 0, FILE_BEGIN ), "_llseek complains\n" );
+
+ ok( _hread( filehandle, buffer, strlen( sillytext ) ) == lstrlenA( sillytext ), "erratic _hread return value\n" );
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ ok( INVALID_HANDLE_VALUE != FindFirstFileA( filename, &search_results ), "should STILL be able to find file\n" );
+
+ ret = DeleteFileA( filename );
+ ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) );
+
+ filehandle=_lcreat (slashname, 0); /* illegal name */
+ if (HFILE_ERROR==filehandle) {
+ err=GetLastError ();
+ ok (err==ERROR_INVALID_NAME || err==ERROR_PATH_NOT_FOUND,
+ "creating file \"%s\" failed with error %d\n", slashname, err);
+ } else { /* only NT succeeds */
+ _lclose(filehandle);
+ find=FindFirstFileA (slashname, &search_results);
+ if (INVALID_HANDLE_VALUE!=find)
+ {
+ ret = FindClose (find);
+ ok (0 != ret, "FindClose complains (%ld)\n", GetLastError ());
+ slashname[strlen(slashname)-1]=0;
+ ok (!strcmp (slashname, search_results.cFileName),
+ "found unexpected name \"%s\"\n", search_results.cFileName);
+ ok (FILE_ATTRIBUTE_ARCHIVE==search_results.dwFileAttributes,
+ "attributes of file \"%s\" are 0x%04lx\n", search_results.cFileName,
+ search_results.dwFileAttributes);
+ }
+ ret = DeleteFileA( slashname );
+ ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) );
+ }
+
+ filehandle=_lcreat (filename, 8); /* illegal attribute */
+ if (HFILE_ERROR==filehandle)
+ ok (0, "couldn't create volume label \"%s\"\n", filename);
+ else {
+ _lclose(filehandle);
+ find=FindFirstFileA (filename, &search_results);
+ if (INVALID_HANDLE_VALUE==find)
+ ok (0, "file \"%s\" not found\n", filename);
+ else {
+ ret = FindClose(find);
+ ok ( 0 != ret, "FindClose complains (%ld)\n", GetLastError ());
+ ok (!strcmp (filename, search_results.cFileName),
+ "found unexpected name \"%s\"\n", search_results.cFileName);
+ ok (FILE_ATTRIBUTE_ARCHIVE==search_results.dwFileAttributes,
+ "attributes of file \"%s\" are 0x%04lx\n", search_results.cFileName,
+ search_results.dwFileAttributes);
+ }
+ ret = DeleteFileA( filename );
+ ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) );
+ }
+}
+
+
+static void test__llseek( void )
+{
+ INT i;
+ HFILE filehandle;
+ char buffer[1];
+ long bytes_read;
+ BOOL ret;
+
+ filehandle = _lcreat( filename, 0 );
+ if (filehandle == HFILE_ERROR)
+ {
+ ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError());
+ return;
+ }
+
+ for (i = 0; i < 400; i++)
+ {
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite complains\n" );
+ }
+ ok( HFILE_ERROR != _llseek( filehandle, 400 * strlen( sillytext ), FILE_CURRENT ), "should be able to seek\n" );
+ ok( HFILE_ERROR != _llseek( filehandle, 27 + 35 * strlen( sillytext ), FILE_BEGIN ), "should be able to seek\n" );
+
+ bytes_read = _hread( filehandle, buffer, 1);
+ ok( 1 == bytes_read, "file read size error\n" );
+ ok( buffer[0] == sillytext[27], "_llseek error, it got lost seeking\n" );
+ ok( HFILE_ERROR != _llseek( filehandle, -400 * strlen( sillytext ), FILE_END ), "should be able to seek\n" );
+
+ bytes_read = _hread( filehandle, buffer, 1);
+ ok( 1 == bytes_read, "file read size error\n" );
+ ok( buffer[0] == sillytext[0], "_llseek error, it got lost seeking\n" );
+ ok( HFILE_ERROR != _llseek( filehandle, 1000000, FILE_END ), "should be able to seek past file; poor, poor Windows programmers\n" );
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ ret = DeleteFileA( filename );
+ ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) );
+}
+
+
+static void test__llopen( void )
+{
+ HFILE filehandle;
+ UINT bytes_read;
+ char buffer[10000];
+ BOOL ret;
+
+ filehandle = _lcreat( filename, 0 );
+ if (filehandle == HFILE_ERROR)
+ {
+ ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError());
+ return;
+ }
+
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite complains\n" );
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ filehandle = _lopen( filename, OF_READ );
+ ok( HFILE_ERROR == _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite shouldn't be able to write!\n" );
+ bytes_read = _hread( filehandle, buffer, strlen( sillytext ) );
+ ok( strlen( sillytext ) == bytes_read, "file read size error\n" );
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ filehandle = _lopen( filename, OF_READWRITE );
+ bytes_read = _hread( filehandle, buffer, 2 * strlen( sillytext ) );
+ ok( strlen( sillytext ) == bytes_read, "file read size error\n" );
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite should write just fine\n" );
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ filehandle = _lopen( filename, OF_WRITE );
+ ok( HFILE_ERROR == _hread( filehandle, buffer, 1 ), "you should only be able to write this file\n" );
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite should write just fine\n" );
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ ret = DeleteFileA( filename );
+ ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) );
+ /* TODO - add tests for the SHARE modes - use two processes to pull this one off */
+}
+
+
+static void test__lread( void )
+{
+ HFILE filehandle;
+ char buffer[10000];
+ long bytes_read;
+ UINT bytes_wanted;
+ UINT i;
+ BOOL ret;
+
+ filehandle = _lcreat( filename, 0 );
+ if (filehandle == HFILE_ERROR)
+ {
+ ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError());
+ return;
+ }
+
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite complains\n" );
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ filehandle = _lopen( filename, OF_READ );
+
+ ok( HFILE_ERROR != filehandle, "couldn't open file \"%s\" again (err=%ld)\n", filename, GetLastError());
+
+ bytes_read = _lread( filehandle, buffer, 2 * strlen( sillytext ) );
+
+ ok( lstrlenA( sillytext ) == bytes_read, "file read size error\n" );
+
+ for (bytes_wanted = 0; bytes_wanted < strlen( sillytext ); bytes_wanted++)
+ {
+ ok( 0 == _llseek( filehandle, 0, FILE_BEGIN ), "_llseek complains\n" );
+ ok( _lread( filehandle, buffer, bytes_wanted ) == bytes_wanted, "erratic _hread return value\n" );
+ for (i = 0; i < bytes_wanted; i++)
+ {
+ ok( buffer[i] == sillytext[i], "that's not what's written\n" );
+ }
+ }
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ ret = DeleteFileA( filename );
+ ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) );
+}
+
+
+static void test__lwrite( void )
+{
+ HFILE filehandle;
+ char buffer[10000];
+ long bytes_read;
+ long bytes_written;
+ long blocks;
+ long i;
+ char *contents;
+ HLOCAL memory_object;
+ char checksum[1];
+ BOOL ret;
+
+ filehandle = _lcreat( filename, 0 );
+ if (filehandle == HFILE_ERROR)
+ {
+ ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError());
+ return;
+ }
+
+ ok( HFILE_ERROR != _lwrite( filehandle, "", 0 ), "_hwrite complains\n" );
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ filehandle = _lopen( filename, OF_READ );
+
+ bytes_read = _hread( filehandle, buffer, 1);
+
+ ok( 0 == bytes_read, "file read size error\n" );
+
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ filehandle = _lopen( filename, OF_READWRITE );
+
+ bytes_written = 0;
+ checksum[0] = '\0';
+ srand( (unsigned)time( NULL ) );
+ for (blocks = 0; blocks < 100; blocks++)
+ {
+ for (i = 0; i < (long)sizeof( buffer ); i++)
+ {
+ buffer[i] = rand( );
+ checksum[0] = checksum[0] + buffer[i];
+ }
+ ok( HFILE_ERROR != _lwrite( filehandle, buffer, sizeof( buffer ) ), "_hwrite complains\n" );
+ bytes_written = bytes_written + sizeof( buffer );
+ }
+
+ ok( HFILE_ERROR != _lwrite( filehandle, checksum, 1 ), "_hwrite complains\n" );
+ bytes_written++;
+
+ ok( HFILE_ERROR != _lclose( filehandle ), "_lclose complains\n" );
+
+ memory_object = LocalAlloc( LPTR, bytes_written );
+
+ ok( 0 != memory_object, "LocalAlloc fails, could be out of memory\n" );
+
+ contents = LocalLock( memory_object );
+
+ filehandle = _lopen( filename, OF_READ );
+
+ contents = LocalLock( memory_object );
+
+ ok( NULL != contents, "LocalLock whines\n" );
+
+ ok( bytes_written == _hread( filehandle, contents, bytes_written), "read length differ from write length\n" );
+
+ checksum[0] = '\0';
+ i = 0;
+ do
+ {
+ checksum[0] += contents[i];
+ i++;
+ }
+ while (i < bytes_written - 1);
+
+ ok( checksum[0] == contents[i], "stored checksum differ from computed checksum\n" );
+
+ ok( HFILE_ERROR != _lclose( filehandle ), "_lclose complains\n" );
+
+ ret = DeleteFileA( filename );
+ ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) );
+}
+
+static void test_CopyFileA(void)
+{
+ char temp_path[MAX_PATH];
+ char source[MAX_PATH], dest[MAX_PATH];
+ static const char prefix[] = "pfx";
+ HANDLE hfile;
+ FILETIME ft1, ft2;
+ char buf[10];
+ DWORD ret;
+ BOOL retok;
+
+ ret = GetTempPathA(MAX_PATH, temp_path);
+ ok(ret != 0, "GetTempPathA error %ld\n", GetLastError());
+ ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
+
+ ret = GetTempFileNameA(temp_path, prefix, 0, source);
+ ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError());
+
+ /* make the source have not zero size */
+ hfile = CreateFileA(source, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0 );
+ ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file\n");
+ retok = WriteFile(hfile, prefix, sizeof(prefix), &ret, NULL );
+ ok( retok && ret == sizeof(prefix),
+ "WriteFile error %ld\n", GetLastError());
+ ok(GetFileSize(hfile, NULL) == sizeof(prefix), "source file has wrong size\n");
+ /* get the file time and change it to prove the difference */
+ ret = GetFileTime(hfile, NULL, NULL, &ft1);
+ ok( ret, "GetFileTime error %ld\n", GetLastError());
+ ft1.dwLowDateTime -= 600000000; /* 60 second */
+ ret = SetFileTime(hfile, NULL, NULL, &ft1);
+ ok( ret, "SetFileTime error %ld\n", GetLastError());
+ GetFileTime(hfile, NULL, NULL, &ft1); /* get the actual time back */
+ CloseHandle(hfile);
+
+ ret = GetTempFileNameA(temp_path, prefix, 0, dest);
+ ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = CopyFileA(source, dest, TRUE);
+ ok(!ret && GetLastError() == ERROR_FILE_EXISTS,
+ "CopyFileA: unexpected error %ld\n", GetLastError());
+
+ ret = CopyFileA(source, dest, FALSE);
+ ok(ret, "CopyFileA: error %ld\n", GetLastError());
+
+ /* make sure that destination has correct size */
+ hfile = CreateFileA(dest, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+ ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file\n");
+ ret = GetFileSize(hfile, NULL);
+ ok(ret == sizeof(prefix), "destination file has wrong size %ld\n", ret);
+
+ /* make sure that destination has the same filetime */
+ ret = GetFileTime(hfile, NULL, NULL, &ft2);
+ ok( ret, "GetFileTime error %ld\n", GetLastError());
+ ok(CompareFileTime(&ft1, &ft2) == 0, "destination file has wrong filetime\n");
+
+ SetLastError(0xdeadbeef);
+ ret = CopyFileA(source, dest, FALSE);
+ ok(!ret && GetLastError() == ERROR_SHARING_VIOLATION,
+ "CopyFileA: ret = %ld, unexpected error %ld\n", ret, GetLastError());
+
+ /* make sure that destination still has correct size */
+ ret = GetFileSize(hfile, NULL);
+ ok(ret == sizeof(prefix), "destination file has wrong size %ld\n", ret);
+ retok = ReadFile(hfile, buf, sizeof(buf), &ret, NULL);
+ ok( retok && ret == sizeof(prefix),
+ "ReadFile: error %ld\n", GetLastError());
+ ok(!memcmp(prefix, buf, sizeof(prefix)), "buffer contents mismatch\n");
+ CloseHandle(hfile);
+
+ ret = DeleteFileA(source);
+ ok(ret, "DeleteFileA: error %ld\n", GetLastError());
+ ret = DeleteFileA(dest);
+ ok(ret, "DeleteFileA: error %ld\n", GetLastError());
+}
+
+static void test_CopyFileW(void)
+{
+ WCHAR temp_path[MAX_PATH];
+ WCHAR source[MAX_PATH], dest[MAX_PATH];
+ static const WCHAR prefix[] = {'p','f','x',0};
+ DWORD ret;
+
+ ret = GetTempPathW(MAX_PATH, temp_path);
+ if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+ return;
+ ok(ret != 0, "GetTempPathW error %ld\n", GetLastError());
+ ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
+
+ ret = GetTempFileNameW(temp_path, prefix, 0, source);
+ ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError());
+
+ ret = GetTempFileNameW(temp_path, prefix, 0, dest);
+ ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError());
+
+ ret = CopyFileW(source, dest, TRUE);
+ ok(!ret && GetLastError() == ERROR_FILE_EXISTS,
+ "CopyFileW: unexpected error %ld\n", GetLastError());
+
+ ret = CopyFileW(source, dest, FALSE);
+ ok(ret, "CopyFileW: error %ld\n", GetLastError());
+
+ ret = DeleteFileW(source);
+ ok(ret, "DeleteFileW: error %ld\n", GetLastError());
+ ret = DeleteFileW(dest);
+ ok(ret, "DeleteFileW: error %ld\n", GetLastError());
+}
+
+static void test_CreateFileA(void)
+{
+ HANDLE hFile;
+ char temp_path[MAX_PATH];
+ char filename[MAX_PATH];
+ static const char prefix[] = "pfx";
+ DWORD ret;
+
+ ret = GetTempPathA(MAX_PATH, temp_path);
+ ok(ret != 0, "GetTempPathA error %ld\n", GetLastError());
+ ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
+
+ ret = GetTempFileNameA(temp_path, prefix, 0, filename);
+ ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError());
+
+ hFile = CreateFileA(filename, GENERIC_READ, 0, NULL,
+ CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0);
+ ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_EXISTS,
+ "CREATE_NEW should fail if file exists and last error value should be ERROR_FILE_EXISTS\n");
+
+ ret = DeleteFileA(filename);
+ ok(ret, "DeleteFileA: error %ld\n", GetLastError());
+}
+
+static void test_CreateFileW(void)
+{
+ HANDLE hFile;
+ WCHAR temp_path[MAX_PATH];
+ WCHAR filename[MAX_PATH];
+ static const WCHAR emptyW[]={'\0'};
+ static const WCHAR prefix[] = {'p','f','x',0};
+ static const WCHAR bogus[] = { '\\', '\\', '.', '\\', 'B', 'O', 'G', 'U', 'S', 0 };
+ DWORD ret;
+
+ ret = GetTempPathW(MAX_PATH, temp_path);
+ if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+ return;
+ ok(ret != 0, "GetTempPathW error %ld\n", GetLastError());
+ ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
+
+ ret = GetTempFileNameW(temp_path, prefix, 0, filename);
+ ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError());
+
+ hFile = CreateFileW(filename, GENERIC_READ, 0, NULL,
+ CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0);
+ ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_EXISTS,
+ "CREATE_NEW should fail if file exists and last error value should be ERROR_FILE_EXISTS\n");
+
+ ret = DeleteFileW(filename);
+ ok(ret, "DeleteFileW: error %ld\n", GetLastError());
+
+#if 0 /* this test crashes on NT4.0 */
+ hFile = CreateFileW(NULL, GENERIC_READ, 0, NULL,
+ CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0);
+ ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND,
+ "CreateFileW(NULL) returned ret=%p error=%ld\n",hFile,GetLastError());
+#endif
+
+ hFile = CreateFileW(emptyW, GENERIC_READ, 0, NULL,
+ CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0);
+ ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND,
+ "CreateFileW(\"\") returned ret=%p error=%ld\n",hFile,GetLastError());
+
+ /* test the result of opening a nonexistent driver name */
+ hFile = CreateFileW(bogus, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND,
+ "CreateFileW on invalid VxD name returned ret=%p error=%ld\n",hFile,GetLastError());
+}
+
+static void test_GetTempFileNameA(void)
+{
+ UINT result;
+ char out[MAX_PATH];
+ char expected[MAX_PATH + 10];
+ char windowsdir[MAX_PATH + 10];
+ char windowsdrive[3];
+
+ result = GetWindowsDirectory(windowsdir, sizeof(windowsdir));
+ ok(result < sizeof(windowsdir), "windowsdir is abnormally long!\n");
+ ok(result != 0, "GetWindowsDirectory: error %ld\n", GetLastError());
+
+ /* If the Windows directory is the root directory, it ends in backslash, not else. */
+ if (strlen(windowsdir) != 3) /* As in "C:\" or "F:\" */
+ {
+ strcat(windowsdir, "\\");
+ }
+
+ windowsdrive[0] = windowsdir[0];
+ windowsdrive[1] = windowsdir[1];
+ windowsdrive[2] = '\0';
+
+ result = GetTempFileNameA(windowsdrive, "abc", 1, out);
+ ok(result != 0, "GetTempFileNameA: error %ld\n", GetLastError());
+ ok(((out[0] == windowsdrive[0]) && (out[1] == ':')) && (out[2] == '\\'),
+ "GetTempFileNameA: first three characters should be %c:\\, string was actually %s\n",
+ windowsdrive[0], out);
+
+ result = GetTempFileNameA(windowsdir, "abc", 2, out);
+ ok(result != 0, "GetTempFileNameA: error %ld\n", GetLastError());
+ expected[0] = '\0';
+ strcat(expected, windowsdir);
+ strcat(expected, "abc2.tmp");
+ ok(lstrcmpiA(out, expected) == 0, "GetTempFileNameA: Unexpected output \"%s\" vs \"%s\"\n",
+ out, expected);
+}
+
+static void test_DeleteFileA( void )
+{
+ BOOL ret;
+
+ ret = DeleteFileA(NULL);
+ ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER ||
+ GetLastError() == ERROR_PATH_NOT_FOUND),
+ "DeleteFileA(NULL) returned ret=%d error=%ld\n",ret,GetLastError());
+
+ ret = DeleteFileA("");
+ ok(!ret && (GetLastError() == ERROR_PATH_NOT_FOUND ||
+ GetLastError() == ERROR_BAD_PATHNAME),
+ "DeleteFileA(\"\") returned ret=%d error=%ld\n",ret,GetLastError());
+
+ ret = DeleteFileA("nul");
+ ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND ||
+ GetLastError() == ERROR_INVALID_PARAMETER ||
+ GetLastError() == ERROR_ACCESS_DENIED ||
+ GetLastError() == ERROR_INVALID_FUNCTION),
+ "DeleteFileA(\"nul\") returned ret=%d error=%ld\n",ret,GetLastError());
+}
+
+static void test_DeleteFileW( void )
+{
+ BOOL ret;
+ static const WCHAR emptyW[]={'\0'};
+
+ ret = DeleteFileW(NULL);
+ if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+ return;
+ ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND,
+ "DeleteFileW(NULL) returned ret=%d error=%ld\n",ret,GetLastError());
+
+ ret = DeleteFileW(emptyW);
+ ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND,
+ "DeleteFileW(\"\") returned ret=%d error=%ld\n",ret,GetLastError());
+}
+
+#define IsDotDir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
+
+static void test_MoveFileA(void)
+{
+ char tempdir[MAX_PATH];
+ char source[MAX_PATH], dest[MAX_PATH];
+ static const char prefix[] = "pfx";
+ DWORD ret;
+
+ ret = GetTempPathA(MAX_PATH, tempdir);
+ ok(ret != 0, "GetTempPathA error %ld\n", GetLastError());
+ ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
+
+ ret = GetTempFileNameA(tempdir, prefix, 0, source);
+ ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError());
+
+ ret = GetTempFileNameA(tempdir, prefix, 0, dest);
+ ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError());
+
+ ret = MoveFileA(source, dest);
+ ok(!ret && GetLastError() == ERROR_ALREADY_EXISTS,
+ "MoveFileA: unexpected error %ld\n", GetLastError());
+
+ ret = DeleteFileA(dest);
+ ok(ret, "DeleteFileA: error %ld\n", GetLastError());
+
+ ret = MoveFileA(source, dest);
+ ok(ret, "MoveFileA: failed, error %ld\n", GetLastError());
+
+ lstrcatA(tempdir, "Remove Me");
+ ret = CreateDirectoryA(tempdir, NULL);
+ ok(ret == TRUE, "CreateDirectoryA failed\n");
+
+ lstrcpyA(source, dest);
+ lstrcpyA(dest, tempdir);
+ lstrcatA(dest, "\\wild?.*");
+ /* FIXME: if we create a file with wildcards we can't delete it now that DeleteFile works correctly */
+ ret = MoveFileA(source, dest);
+ ok(!ret, "MoveFileA: shouldn't move to wildcard file\n");
+ ok(GetLastError() == ERROR_INVALID_NAME || /* NT */
+ GetLastError() == ERROR_FILE_NOT_FOUND, /* Win9x */
+ "MoveFileA: with wildcards, unexpected error %ld\n", GetLastError());
+ if (ret || (GetLastError() != ERROR_INVALID_NAME))
+ {
+ WIN32_FIND_DATAA fd;
+ char temppath[MAX_PATH];
+ HANDLE hFind;
+
+ lstrcpyA(temppath, tempdir);
+ lstrcatA(temppath, "\\*.*");
+ hFind = FindFirstFileA(temppath, &fd);
+ if (INVALID_HANDLE_VALUE != hFind)
+ {
+ LPSTR lpName;
+ do
+ {
+ lpName = fd.cAlternateFileName;
+ if (!lpName[0])
+ lpName = fd.cFileName;
+ ok(IsDotDir(lpName), "MoveFileA: wildcards file created!\n");
+ }
+ while (FindNextFileA(hFind, &fd));
+ FindClose(hFind);
+ }
+ }
+ ret = DeleteFileA(source);
+ ok(ret, "DeleteFileA: error %ld\n", GetLastError());
+ ret = DeleteFileA(dest);
+ ok(!ret, "DeleteFileA: error %ld\n", GetLastError());
+ ret = RemoveDirectoryA(tempdir);
+ ok(ret, "DeleteDirectoryA: error %ld\n", GetLastError());
+}
+
+static void test_MoveFileW(void)
+{
+ WCHAR temp_path[MAX_PATH];
+ WCHAR source[MAX_PATH], dest[MAX_PATH];
+ static const WCHAR prefix[] = {'p','f','x',0};
+ DWORD ret;
+
+ ret = GetTempPathW(MAX_PATH, temp_path);
+ if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+ return;
+ ok(ret != 0, "GetTempPathW error %ld\n", GetLastError());
+ ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
+
+ ret = GetTempFileNameW(temp_path, prefix, 0, source);
+ ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError());
+
+ ret = GetTempFileNameW(temp_path, prefix, 0, dest);
+ ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError());
+
+ ret = MoveFileW(source, dest);
+ ok(!ret && GetLastError() == ERROR_ALREADY_EXISTS,
+ "CopyFileW: unexpected error %ld\n", GetLastError());
+
+ ret = DeleteFileW(source);
+ ok(ret, "DeleteFileW: error %ld\n", GetLastError());
+ ret = DeleteFileW(dest);
+ ok(ret, "DeleteFileW: error %ld\n", GetLastError());
+}
+
+#define PATTERN_OFFSET 0x10
+
+static void test_offset_in_overlapped_structure(void)
+{
+ HANDLE hFile;
+ OVERLAPPED ov;
+ DWORD done;
+ BOOL rc;
+ BYTE buf[256], pattern[] = "TeSt";
+ UINT i;
+ char temp_path[MAX_PATH], temp_fname[MAX_PATH];
+ BOOL ret;
+
+ ret =GetTempPathA(MAX_PATH, temp_path);
+ ok( ret, "GetTempPathA error %ld\n", GetLastError());
+ ret =GetTempFileNameA(temp_path, "pfx", 0, temp_fname);
+ ok( ret, "GetTempFileNameA error %ld\n", GetLastError());
+
+ /*** Write File *****************************************************/
+
+ hFile = CreateFileA(temp_fname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+ ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA error %ld\n", GetLastError());
+
+ for(i = 0; i < sizeof(buf); i++) buf[i] = i;
+ ret = WriteFile(hFile, buf, sizeof(buf), &done, NULL);
+ ok( ret, "WriteFile error %ld\n", GetLastError());
+ ok(done == sizeof(buf), "expected number of bytes written %lu\n", done);
+
+ memset(&ov, 0, sizeof(ov));
+ ov.Offset = PATTERN_OFFSET;
+ ov.OffsetHigh = 0;
+ rc=WriteFile(hFile, pattern, sizeof(pattern), &done, &ov);
+ /* Win 9x does not support the overlapped I/O on files */
+ if (rc || GetLastError()!=ERROR_INVALID_PARAMETER) {
+ ok(rc, "WriteFile error %ld\n", GetLastError());
+ ok(done == sizeof(pattern), "expected number of bytes written %lu\n", done);
+ /*trace("Current offset = %04lx\n", SetFilePointer(hFile, 0, NULL, FILE_CURRENT));*/
+ ok(SetFilePointer(hFile, 0, NULL, FILE_CURRENT) == (PATTERN_OFFSET + sizeof(pattern)),
+ "expected file offset %d\n", PATTERN_OFFSET + sizeof(pattern));
+
+ ov.Offset = sizeof(buf) * 2;
+ ov.OffsetHigh = 0;
+ ret = WriteFile(hFile, pattern, sizeof(pattern), &done, &ov);
+ ok( ret, "WriteFile error %ld\n", GetLastError());
+ ok(done == sizeof(pattern), "expected number of bytes written %lu\n", done);
+ /*trace("Current offset = %04lx\n", SetFilePointer(hFile, 0, NULL, FILE_CURRENT));*/
+ ok(SetFilePointer(hFile, 0, NULL, FILE_CURRENT) == (sizeof(buf) * 2 + sizeof(pattern)),
+ "expected file offset %d\n", sizeof(buf) * 2 + sizeof(pattern));
+ }
+
+ CloseHandle(hFile);
+
+ /*** Read File *****************************************************/
+
+ hFile = CreateFileA(temp_fname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
+ ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA error %ld\n", GetLastError());
+
+ memset(buf, 0, sizeof(buf));
+ memset(&ov, 0, sizeof(ov));
+ ov.Offset = PATTERN_OFFSET;
+ ov.OffsetHigh = 0;
+ rc=ReadFile(hFile, buf, sizeof(pattern), &done, &ov);
+ /* Win 9x does not support the overlapped I/O on files */
+ if (rc || GetLastError()!=ERROR_INVALID_PARAMETER) {
+ ok(rc, "ReadFile error %ld\n", GetLastError());
+ ok(done == sizeof(pattern), "expected number of bytes read %lu\n", done);
+ /*trace("Current offset = %04lx\n", SetFilePointer(hFile, 0, NULL, FILE_CURRENT));*/
+ ok(SetFilePointer(hFile, 0, NULL, FILE_CURRENT) == (PATTERN_OFFSET + sizeof(pattern)),
+ "expected file offset %d\n", PATTERN_OFFSET + sizeof(pattern));
+ ok(!memcmp(buf, pattern, sizeof(pattern)), "pattern match failed\n");
+ }
+
+ CloseHandle(hFile);
+
+ ret = DeleteFileA(temp_fname);
+ ok( ret, "DeleteFileA error %ld\n", GetLastError());
+}
+
+static void test_LockFile(void)
+{
+ HANDLE handle;
+ DWORD written;
+ OVERLAPPED overlapped;
+ int limited_LockFile;
+ int limited_UnLockFile;
+ int lockfileex_capable;
+
+ handle = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ CREATE_ALWAYS, 0, 0 );
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError());
+ return;
+ }
+ ok( WriteFile( handle, sillytext, strlen(sillytext), &written, NULL ), "write failed\n" );
+
+ ok( LockFile( handle, 0, 0, 0, 0 ), "LockFile failed\n" );
+ ok( UnlockFile( handle, 0, 0, 0, 0 ), "UnlockFile failed\n" );
+
+ limited_UnLockFile = 0;
+ if (UnlockFile( handle, 0, 0, 0, 0 ))
+ {
+ limited_UnLockFile = 1;
+ }
+
+ ok( LockFile( handle, 10, 0, 20, 0 ), "LockFile 10,20 failed\n" );
+ /* overlapping locks must fail */
+ ok( !LockFile( handle, 12, 0, 10, 0 ), "LockFile 12,10 succeeded\n" );
+ ok( !LockFile( handle, 5, 0, 6, 0 ), "LockFile 5,6 succeeded\n" );
+ /* non-overlapping locks must succeed */
+ ok( LockFile( handle, 5, 0, 5, 0 ), "LockFile 5,5 failed\n" );
+
+ ok( !UnlockFile( handle, 10, 0, 10, 0 ), "UnlockFile 10,10 succeeded\n" );
+ ok( UnlockFile( handle, 10, 0, 20, 0 ), "UnlockFile 10,20 failed\n" );
+ ok( !UnlockFile( handle, 10, 0, 20, 0 ), "UnlockFile 10,20 again succeeded\n" );
+ ok( UnlockFile( handle, 5, 0, 5, 0 ), "UnlockFile 5,5 failed\n" );
+
+ overlapped.Offset = 100;
+ overlapped.OffsetHigh = 0;
+ overlapped.hEvent = 0;
+
+ lockfileex_capable = dll_capable("kernel32", "LockFileEx");
+ if (lockfileex_capable)
+ {
+ /* Test for broken LockFileEx a la Windows 95 OSR2. */
+ if (LockFileEx( handle, 0, 0, 100, 0, &overlapped ))
+ {
+ /* LockFileEx is probably OK, test it more. */
+ ok( LockFileEx( handle, 0, 0, 100, 0, &overlapped ),
+ "LockFileEx 100,100 failed\n" );
+ }
+ }
+
+ /* overlapping shared locks are OK */
+ overlapped.Offset = 150;
+ limited_UnLockFile || ok( LockFileEx( handle, 0, 0, 100, 0, &overlapped ), "LockFileEx 150,100 failed\n" );
+
+ /* but exclusive is not */
+ if (lockfileex_capable)
+ {
+ ok( !LockFileEx( handle, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
+ 0, 50, 0, &overlapped ),
+ "LockFileEx exclusive 150,50 succeeded\n" );
+ if (dll_capable("kernel32.dll", "UnlockFileEx"))
+ {
+ if (!UnlockFileEx( handle, 0, 100, 0, &overlapped ))
+ { /* UnLockFile is capable. */
+ overlapped.Offset = 100;
+ ok( !UnlockFileEx( handle, 0, 100, 0, &overlapped ),
+ "UnlockFileEx 150,100 again succeeded\n" );
+ }
+ }
+ }
+
+ ok( LockFile( handle, 0, 0x10000000, 0, 0xf0000000 ), "LockFile failed\n" );
+ ok( !LockFile( handle, ~0, ~0, 1, 0 ), "LockFile ~0,1 succeeded\n" );
+ ok( !LockFile( handle, 0, 0x20000000, 20, 0 ), "LockFile 0x20000000,20 succeeded\n" );
+ ok( UnlockFile( handle, 0, 0x10000000, 0, 0xf0000000 ), "UnlockFile failed\n" );
+
+ /* wrap-around lock should not do anything */
+ /* (but still succeeds on NT4 so we don't check result) */
+ LockFile( handle, 0, 0x10000000, 0, 0xf0000001 );
+
+ limited_LockFile = 0;
+ if (!LockFile( handle, ~0, ~0, 1, 0 ))
+ {
+ limited_LockFile = 1;
+ }
+
+ limited_UnLockFile || ok( UnlockFile( handle, ~0, ~0, 1, 0 ), "Unlockfile ~0,1 failed\n" );
+
+ /* zero-byte lock */
+ ok( LockFile( handle, 100, 0, 0, 0 ), "LockFile 100,0 failed\n" );
+ limited_LockFile || ok( !LockFile( handle, 98, 0, 4, 0 ), "LockFile 98,4 succeeded\n" );
+ ok( LockFile( handle, 90, 0, 10, 0 ), "LockFile 90,10 failed\n" );
+ limited_LockFile || ok( !LockFile( handle, 100, 0, 10, 0 ), "LockFile 100,10 failed\n" );
+
+ ok( UnlockFile( handle, 90, 0, 10, 0 ), "UnlockFile 90,10 failed\n" );
+ !ok( UnlockFile( handle, 100, 0, 10, 0 ), "UnlockFile 100,10 failed\n" );
+
+ ok( UnlockFile( handle, 100, 0, 0, 0 ), "UnlockFile 100,0 failed\n" );
+
+ CloseHandle( handle );
+ DeleteFileA( filename );
+}
+
+static inline int is_sharing_compatible( DWORD access1, DWORD sharing1, DWORD access2, DWORD sharing2 )
+{
+ if (!access1 || !access2) return 1;
+ if ((access1 & GENERIC_READ) && !(sharing2 & FILE_SHARE_READ)) return 0;
+ if ((access1 & GENERIC_WRITE) && !(sharing2 & FILE_SHARE_WRITE)) return 0;
+ if ((access2 & GENERIC_READ) && !(sharing1 & FILE_SHARE_READ)) return 0;
+ if ((access2 & GENERIC_WRITE) && !(sharing1 & FILE_SHARE_WRITE)) return 0;
+ return 1;
+}
+
+static void test_file_sharing(void)
+{
+ static const DWORD access_modes[4] = { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ|GENERIC_WRITE };
+ static const DWORD sharing_modes[4] = { 0, FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE };
+ int a1, s1, a2, s2;
+ int ret;
+ HANDLE h, h2;
+
+ /* make sure the file exists */
+ h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ ok(0, "couldn't create file \"%s\" (err=%ld)\n", filename, GetLastError());
+ return;
+ }
+ CloseHandle( h );
+
+ for (a1 = 0; a1 < 4; a1++)
+ {
+ for (s1 = 0; s1 < 4; s1++)
+ {
+ h = CreateFileA( filename, access_modes[a1], sharing_modes[s1],
+ NULL, OPEN_EXISTING, 0, 0 );
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError());
+ return;
+ }
+ for (a2 = 0; a2 < 4; a2++)
+ {
+ for (s2 = 0; s2 < 4; s2++)
+ {
+ SetLastError(0xdeadbeef);
+ h2 = CreateFileA( filename, access_modes[a2], sharing_modes[s2],
+ NULL, OPEN_EXISTING, 0, 0 );
+ if (is_sharing_compatible( access_modes[a1], sharing_modes[s1],
+ access_modes[a2], sharing_modes[s2] ))
+ {
+ ret = GetLastError();
+ ok( ERROR_SHARING_VIOLATION == ret || 0 == ret,
+ "Windows 95 sets GetLastError() = ERROR_SHARING_VIOLATION and\n"
+ " Windows XP GetLastError() = 0, but now it is %d.\n"
+ " indexes = %d, %d, %d, %d\n"
+ " modes =\n %lx/%lx/%lx/%lx\n",
+ ret,
+ a1, s1, a2, s2,
+ access_modes[a1], sharing_modes[s1],
+ access_modes[a2], sharing_modes[s2]
+ );
+ }
+ else
+ {
+ ok( h2 == INVALID_HANDLE_VALUE,
+ "open succeeded for modes %lx/%lx/%lx/%lx\n",
+ access_modes[a1], sharing_modes[s1],
+ access_modes[a2], sharing_modes[s2] );
+ if (h2 == INVALID_HANDLE_VALUE)
+ ok( GetLastError() == ERROR_SHARING_VIOLATION,
+ "wrong error code %ld\n", GetLastError() );
+ }
+ if (h2 != INVALID_HANDLE_VALUE) CloseHandle( h2 );
+ }
+ }
+ CloseHandle( h );
+ }
+ }
+
+ SetLastError(0xdeadbeef);
+ h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, 0 );
+ ok( h != INVALID_HANDLE_VALUE, "CreateFileA error %ld\n", GetLastError() );
+
+ SetLastError(0xdeadbeef);
+ h2 = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
+ ok( h2 == INVALID_HANDLE_VALUE, "CreateFileA should fail\n");
+ ok( GetLastError() == ERROR_SHARING_VIOLATION, "wrong error code %ld\n", GetLastError() );
+
+ h2 = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
+ ok( h2 != INVALID_HANDLE_VALUE, "CreateFileA error %ld\n", GetLastError() );
+
+ CloseHandle(h);
+ CloseHandle(h2);
+
+ DeleteFileA( filename );
+}
+
+static char get_windows_drive(void)
+{
+ char windowsdir[MAX_PATH];
+ GetWindowsDirectory(windowsdir, sizeof(windowsdir));
+ return windowsdir[0];
+}
+
+static void test_FindFirstFileA(void)
+{
+ HANDLE handle;
+ WIN32_FIND_DATAA search_results;
+ int err;
+ char buffer[5] = "C:\\";
+
+ /* try FindFirstFileA on "C:\" */
+ buffer[0] = get_windows_drive();
+ handle = FindFirstFileA(buffer,&search_results);
+ err = GetLastError();
+ ok ( handle == INVALID_HANDLE_VALUE , "FindFirstFile on root directory should Fail\n");
+ if (handle == INVALID_HANDLE_VALUE)
+ ok ( err == ERROR_FILE_NOT_FOUND, "Bad Error number %d\n", err);
+
+ /* try FindFirstFileA on "C:\*" */
+ strcat(buffer, "*");
+ handle = FindFirstFileA(buffer,&search_results);
+ ok ( handle != INVALID_HANDLE_VALUE, "FindFirstFile on %s should succeed\n", buffer );
+ ok ( FindClose(handle) == TRUE, "Failed to close handle\n");
+}
+
+static void test_FindNextFileA(void)
+{
+ HANDLE handle;
+ WIN32_FIND_DATAA search_results;
+ int err;
+ char buffer[5] = "C:\\*";
+
+ buffer[0] = get_windows_drive();
+ handle = FindFirstFileA(buffer,&search_results);
+ ok ( handle != INVALID_HANDLE_VALUE, "FindFirstFile on C:\\* should succeed\n" );
+ while (FindNextFile(handle, &search_results))
+ {
+ /* get to the end of the files */
+ }
+ ok ( FindClose(handle) == TRUE, "Failed to close handle\n");
+ err = GetLastError();
+ ok ( err == ERROR_NO_MORE_FILES, "GetLastError should return ERROR_NO_MORE_FILES\n");
+}
+
+static int test_Mapfile_createtemp(HANDLE *handle)
+{
+ SetFileAttributesA(filename,FILE_ATTRIBUTE_NORMAL);
+ DeleteFile(filename);
+ *handle = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, 0,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (*handle != INVALID_HANDLE_VALUE) {
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static void test_MapFile(void)
+{
+ HANDLE handle;
+ HANDLE hmap;
+
+ ok(test_Mapfile_createtemp(&handle), "Couldn't create test file.\n");
+
+ hmap = CreateFileMapping( handle, NULL, PAGE_READWRITE, 0, 0x1000, "named_file_map" );
+ ok( hmap != NULL, "mapping should work, I named it!\n" );
+
+ ok( CloseHandle( hmap ), "can't close mapping handle\n");
+
+ /* We have to close file before we try new stuff with mapping again.
+ Else we would always succeed on XP or block descriptors on 95. */
+ hmap = CreateFileMapping( handle, NULL, PAGE_READWRITE, 0, 0, NULL );
+ ok( hmap != NULL, "We should still be able to map!\n" );
+ ok( CloseHandle( hmap ), "can't close mapping handle\n");
+ ok( CloseHandle( handle ), "can't close file handle\n");
+ handle = NULL;
+
+ ok(test_Mapfile_createtemp(&handle), "Couldn't create test file.\n");
+
+ hmap = CreateFileMapping( handle, NULL, PAGE_READWRITE, 0, 0, NULL );
+ ok( hmap == NULL, "mapped zero size file\n");
+ ok( GetLastError() == ERROR_FILE_INVALID, "not ERROR_FILE_INVALID\n");
+
+ hmap = CreateFileMapping( handle, NULL, PAGE_READWRITE, 0x1000, 0, NULL );
+ ok( hmap == NULL, "mapping should fail\n");
+ /* GetLastError() varies between win9x and WinNT and also depends on the filesystem */
+
+ hmap = CreateFileMapping( handle, NULL, PAGE_READWRITE, 0x1000, 0x10000, NULL );
+ ok( hmap == NULL, "mapping should fail\n");
+ /* GetLastError() varies between win9x and WinNT and also depends on the filesystem */
+
+ /* On XP you can now map again, on Win 95 you cannot. */
+
+ ok( CloseHandle( handle ), "can't close file handle\n");
+ ok( DeleteFileA( filename ), "DeleteFile failed after map\n" );
+}
+
+static void test_GetFileType(void)
+{
+ DWORD type;
+ HANDLE h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( h != INVALID_HANDLE_VALUE, "open %s failed\n", filename );
+ type = GetFileType(h);
+ ok( type == FILE_TYPE_DISK, "expected type disk got %ld\n", type );
+ CloseHandle( h );
+ h = CreateFileA( "nul", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0 );
+ ok( h != INVALID_HANDLE_VALUE, "open nul failed\n" );
+ type = GetFileType(h);
+ ok( type == FILE_TYPE_CHAR, "expected type char for nul got %ld\n", type );
+ CloseHandle( h );
+ DeleteFileA( filename );
+}
+
+static int completion_count;
+
+static void CALLBACK FileIOComplete(DWORD dwError, DWORD dwBytes, LPOVERLAPPED ovl)
+{
+/* printf("(%ld, %ld, %p { %ld, %ld, %ld, %ld, %p })\n", dwError, dwBytes, ovl, ovl->Internal, ovl->InternalHigh, ovl->Offset, ovl->OffsetHigh, ovl->hEvent);*/
+ ReleaseSemaphore(ovl->hEvent, 1, NULL);
+ completion_count++;
+}
+
+static void test_async_file_errors(void)
+{
+ char szFile[MAX_PATH];
+ HANDLE hSem = CreateSemaphoreW(NULL, 1, 1, NULL);
+ HANDLE hFile;
+ LPVOID lpBuffer = HeapAlloc(GetProcessHeap(), 0, 4096);
+ OVERLAPPED ovl;
+ ovl.Offset = 0;
+ ovl.OffsetHigh = 0;
+ ovl.hEvent = hSem;
+ completion_count = 0;
+ szFile[0] = '\0';
+ GetWindowsDirectoryA(szFile, sizeof(szFile)/sizeof(szFile[0])-1-strlen("\\win.ini"));
+ strcat(szFile, "\\win.ini");
+ hFile = CreateFileA(szFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL);
+ ok(hFile != NULL, "CreateFileA(%s ...) failed\n", szFile);
+ while (TRUE)
+ {
+ BOOL res;
+ while (WaitForSingleObjectEx(hSem, INFINITE, TRUE) == WAIT_IO_COMPLETION)
+ ;
+ res = ReadFileEx(hFile, lpBuffer, 4096, &ovl, FileIOComplete);
+ /*printf("Offset = %ld, result = %s\n", ovl.Offset, res ? "TRUE" : "FALSE");*/
+ if (!res)
+ break;
+ ovl.Offset += 4096;
+ /* i/o completion routine only called if ReadFileEx returned success.
+ * we only care about violations of this rule so undo what should have
+ * been done */
+ completion_count--;
+ }
+ ok(completion_count == 0, "completion routine should only be called when ReadFileEx succeeds (this rule was violated %d times)\n", completion_count);
+ /*printf("Error = %ld\n", GetLastError());*/
+}
+
+static void test_read_write(void)
+{
+ DWORD bytes, ret;
+ HANDLE hFile;
+ char temp_path[MAX_PATH];
+ char filename[MAX_PATH];
+ static const char prefix[] = "pfx";
+
+ ret = GetTempPathA(MAX_PATH, temp_path);
+ ok(ret != 0, "GetTempPathA error %ld\n", GetLastError());
+ ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
+
+ ret = GetTempFileNameA(temp_path, prefix, 0, filename);
+ ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError());
+
+ hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0);
+ ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %ld\n", GetLastError());
+
+ SetLastError(12345678);
+ bytes = 12345678;
+ ret = WriteFile(hFile, NULL, 0, &bytes, NULL);
+ ok(ret && GetLastError() == 12345678,
+ "ret = %ld, error %ld\n", ret, GetLastError());
+ ok(!bytes, "bytes = %ld\n", bytes);
+
+ SetLastError(12345678);
+ bytes = 12345678;
+ ret = WriteFile(hFile, NULL, 10, &bytes, NULL);
+ ok((!ret && GetLastError() == ERROR_INVALID_USER_BUFFER) || /* Win2k */
+ (ret && GetLastError() == 12345678), /* Win9x */
+ "ret = %ld, error %ld\n", ret, GetLastError());
+ ok(!bytes || /* Win2k */
+ bytes == 10, /* Win9x */
+ "bytes = %ld\n", bytes);
+
+ SetLastError(12345678);
+ bytes = 12345678;
+ ret = ReadFile(hFile, NULL, 0, &bytes, NULL);
+ ok(ret && GetLastError() == 12345678,
+ "ret = %ld, error %ld\n", ret, GetLastError());
+ ok(!bytes, "bytes = %ld\n", bytes);
+
+ SetLastError(12345678);
+ bytes = 12345678;
+ ret = ReadFile(hFile, NULL, 10, &bytes, NULL);
+ ok(!ret && (GetLastError() == ERROR_NOACCESS || /* Win2k */
+ GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
+ "ret = %ld, error %ld\n", ret, GetLastError());
+ ok(!bytes, "bytes = %ld\n", bytes);
+
+ ret = CloseHandle(hFile);
+ ok( ret, "CloseHandle: error %ld\n", GetLastError());
+ ret = DeleteFileA(filename);
+ ok( ret, "DeleteFileA: error %ld\n", GetLastError());
+}
+
+START_TEST(file)
+{
+ test__hread( );
+ test__hwrite( );
+ test__lclose( );
+ test__lcreat( );
+ test__llseek( );
+ test__llopen( );
+ test__lread( );
+ test__lwrite( );
+ test_GetTempFileNameA();
+ test_CopyFileA();
+ test_CopyFileW();
+ test_CreateFileA();
+ test_CreateFileW();
+ test_DeleteFileA();
+ test_DeleteFileW();
+ test_MoveFileA();
+ test_MoveFileW();
+ test_FindFirstFileA();
+ test_FindNextFileA();
+ test_LockFile();
+ test_file_sharing();
+ test_offset_in_overlapped_structure();
+ test_MapFile();
+ test_GetFileType();
+ test_async_file_errors();
+ test_read_write();
+}
--- /dev/null
+/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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();
+}
--- /dev/null
+/*
+ * Unit test suite for heap functions
+ *
+ * Copyright 2003 Dimitrie O. Paun
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wine/test.h"
+
+START_TEST(heap)
+{
+ void *mem;
+ HGLOBAL gbl;
+ 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(size == heap_size, "HeapSize returned %lu instead of %lu\n", heap_size, 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);
+
+ todo_wine
+ {
+ 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");
+
+ /* 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);
+
+ todo_wine
+ {
+ 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");
+
+}
--- /dev/null
+<module name="kernel32_test" type="win32cui" installbase="bin" installname="kernel32_test.exe" warnings="true">
+ <include base="kernel32_test">.</include>
+ <define name="__USE_W32API" />
+ <library>ntdll</library>
+ <library>kernel32</library>
+ <file>alloc.c</file>
+ <file>atom.c</file>
+ <file>change.c</file>
+ <file>codepage.c</file>
+ <file>comm.c</file>
+ <file>console.c</file>
+ <file>directory.c</file>
+ <file>drive.c</file>
+ <file>environ.c</file>
+ <file>file.c</file>
+ <file>format_msg.c</file>
+ <file>heap.c</file>
+ <file>locale.c</file>
+ <file>mailslot.c</file>
+ <file>module.c</file>
+ <file>path.c</file>
+ <file>pipe.c</file>
+ <file>process.c</file>
+ <file>profile.c</file>
+ <file>sync.c</file>
+ <file>thread.c</file>
+ <file>time.c</file>
+ <file>timer.c</file>
+ <file>virtual.c</file>
+ <file>testlist.c</file>
+</module>
--- /dev/null
+/*
+ * Unit tests for locale functions
+ *
+ * Copyright 2002 YASAR Mehmet
+ * Copyright 2003 Dmitry Timoshkov
+ * Copyright 2003 Jon Griffiths
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * NOTES
+ * We must pass LOCALE_NOUSEROVERRIDE (NUO) to formatting functions so that
+ * even when the user has overridden their default i8n settings (e.g. in
+ * the control panel i8n page), we will still get the expected results.
+ */
+
+#define WINVER 0x0500
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winnls.h"
+
+static inline unsigned int strlenW( const WCHAR *str )
+{
+ const WCHAR *s = str;
+ while (*s) s++;
+ return s - str;
+}
+
+static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
+{
+ if (n <= 0) return 0;
+ while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
+ return *str1 - *str2;
+}
+
+static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
+{
+ do { if (*str == ch) return (WCHAR *)str; } while (*str++);
+ return NULL;
+}
+
+inline static int isdigitW( WCHAR wc )
+{
+ WORD type;
+ GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
+ return type & C1_DIGIT;
+}
+
+/* Some functions are only in later versions of kernel32.dll */
+static HMODULE hKernel32;
+static WORD enumCount;
+
+typedef BOOL (WINAPI *EnumSystemLanguageGroupsAFn)(LANGUAGEGROUP_ENUMPROC,
+ DWORD, LONG_PTR);
+static EnumSystemLanguageGroupsAFn pEnumSystemLanguageGroupsA;
+typedef BOOL (WINAPI *EnumLanguageGroupLocalesAFn)(LANGGROUPLOCALE_ENUMPROC,
+ LGRPID, DWORD, LONG_PTR);
+static EnumLanguageGroupLocalesAFn pEnumLanguageGroupLocalesA;
+typedef BOOL (WINAPI *EnumUILanguagesAFn)(UILANGUAGE_ENUMPROC,
+ DWORD, LONG_PTR);
+static EnumUILanguagesAFn pEnumUILanguagesA;
+
+typedef INT (WINAPI *FoldStringAFn)(DWORD, LPCSTR, INT, LPSTR, INT);
+static FoldStringAFn pFoldStringA;
+typedef INT (WINAPI *FoldStringWFn)(DWORD, LPCWSTR, INT, LPWSTR, INT);
+static FoldStringWFn pFoldStringW;
+
+typedef BOOL (WINAPI *IsValidLanguageGroupFn)(LGRPID, DWORD);
+static IsValidLanguageGroupFn pIsValidLanguageGroup;
+
+static void InitFunctionPointers(void)
+{
+ hKernel32 = GetModuleHandleA("kernel32");
+
+ if (hKernel32)
+ {
+ pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
+ pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
+ pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
+ pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
+ pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
+ pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
+ }
+}
+
+#define eq(received, expected, label, type) \
+ ok((received) == (expected), "%s: got " type " instead of " type "\n", \
+ (label), (received), (expected))
+
+#define BUFFER_SIZE 128
+#define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
+
+#define EXPECT_LEN(len) ok(ret == (len), "Expected Len %d, got %d\n", (len), ret)
+#define EXPECT_INVALID ok(GetLastError() == ERROR_INVALID_PARAMETER, \
+ "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError())
+#define EXPECT_BUFFER ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, \
+ "Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError())
+#define EXPECT_FLAGS ok(GetLastError() == ERROR_INVALID_FLAGS, \
+ "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError())
+#define EXPECT_INVALIDFLAGS ok(GetLastError() == ERROR_INVALID_FLAGS || \
+ GetLastError() == ERROR_INVALID_PARAMETER, \
+ "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError())
+#define EXPECT_VALID ok(GetLastError() == 0, \
+ "Expected GetLastError() == 0, got %ld\n", GetLastError())
+
+#define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0); buffer[0] = '\0'
+#define EXPECT_LENA EXPECT_LEN((int)strlen(Expected)+1)
+#define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
+ "Expected '%s', got '%s'\n", Expected, buffer)
+
+#define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
+ MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
+ SetLastError(0); buffer[0] = '\0'
+#define EXPECT_LENW EXPECT_LEN((int)strlenW(Expected)+1)
+#define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
+#define EXPECT_FALSE ok(FALSE == ret, "Expected return value FALSE, got TRUE\n")
+#define EXPECT_TRUE ok(FALSE != ret, "Expected return value TRUE, got FALSE\n")
+
+#define NUO LOCALE_NOUSEROVERRIDE
+
+static void test_GetLocaleInfoA(void)
+{
+ int ret;
+ LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ char buffer[BUFFER_SIZE];
+
+ ok(lcid == 0x409, "wrong LCID calculated - %ld\n", lcid);
+
+ /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
+ * partially fill the buffer even if it is too short. See bug 637.
+ */
+ SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
+ ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
+ ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
+
+ SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
+ ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
+ EXPECT_BUFFER; EXPECT_LEN(0);
+ ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
+
+ SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
+ ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
+ EXPECT_VALID; EXPECT_LEN(7);
+ ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
+}
+
+static void test_GetTimeFormatA(void)
+{
+ int ret;
+ SYSTEMTIME curtime;
+ LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
+
+ memset(&curtime, 2, sizeof(SYSTEMTIME));
+ STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
+ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ curtime.wHour = 8;
+ curtime.wMinute = 56;
+ curtime.wSecond = 13;
+ curtime.wMilliseconds = 22;
+ STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
+ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficent buffer */
+ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
+ EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
+ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
+ EXPECT_VALID; EXPECT_LENA;
+
+ STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
+ ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
+ ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
+ ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
+ strcpy(Expected, "8:56 AM");
+ ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
+ ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("s1s2s3", ""); /* Duplicate tokens */
+ ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("t/tt", "A/AM"); /* AM time marker */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ curtime.wHour = 13;
+ STRINGSA("t/tt", "P/PM"); /* PM time marker */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
+ ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
+ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
+ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ curtime.wHour = 14; /* change this to 14 or 2pm */
+ curtime.wMinute = 5;
+ curtime.wSecond = 3;
+ STRINGSA("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ curtime.wHour = 0;
+ STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ /* try to convert formatting strings with more than two letters
+ * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
+ * NOTE: We expect any letter for which there is an upper case value
+ * we should see a replacement. For letters that DO NOT have
+ * upper case values we should see NO REPLACEMENT.
+ */
+ curtime.wHour = 8;
+ curtime.wMinute = 56;
+ curtime.wSecond = 13;
+ curtime.wMilliseconds = 22;
+ STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
+ "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
+ strcpy(buffer, "text");
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
+ EXPECT_VALID; EXPECT_LEN(2); EXPECT_EQA;
+
+ STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
+ "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("'''", "'"); /* invalid quoted string */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ /* test that msdn suggested single quotation usage works as expected */
+ STRINGSA("''''", "'"); /* single quote mark */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("''HHHHHH", "08"); /* Normal use */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ /* and test for normal use of the single quotation mark */
+ STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
+ ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ curtime.wHour = 25;
+ STRINGSA("'123'tt", ""); /* Invalid time */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ curtime.wHour = 12;
+ curtime.wMonth = 60; /* Invalid */
+ STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
+ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+}
+
+static void test_GetDateFormatA(void)
+{
+ int ret;
+ SYSTEMTIME curtime;
+ LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
+
+ memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
+ STRINGSA("ddd',' MMM dd yy","");
+ ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ curtime.wYear = 2002;
+ curtime.wMonth = 5;
+ curtime.wDay = 4;
+ curtime.wDayOfWeek = 3;
+ STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
+ ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
+ ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ curtime.wHour = 36; /* Invalid */
+ STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
+ ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
+ ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
+ EXPECT_VALID; EXPECT_LEN(16); EXPECT_EQA;
+
+ STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
+ ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
+ EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
+ ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA;
+ if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
+ ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
+
+ STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
+ ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ /* test for expected DATE_YEARMONTH behavior with null format */
+ /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
+ STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
+ ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
+
+ /* Test that using invalid DATE_* flags results in the correct error */
+ /* and return values */
+ STRINGSA("m/d/y", ""); /* Invalid flags */
+ ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
+ &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
+}
+
+static void test_GetDateFormatW(void)
+{
+ int ret;
+ SYSTEMTIME curtime;
+ WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
+ LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+
+ STRINGSW("",""); /* If flags is not zero then format must be NULL */
+ ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
+ input, buffer, COUNTOF(buffer));
+ if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+ return;
+ EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQW;
+
+ STRINGSW("",""); /* NULL buffer, len > 0 */
+ ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQW;
+
+ STRINGSW("",""); /* NULL buffer, len == 0 */
+ ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
+ EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
+
+ curtime.wYear = 2002;
+ curtime.wMonth = 10;
+ curtime.wDay = 23;
+ curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
+ curtime.wHour = 65432; /* Invalid */
+ curtime.wMinute = 34512; /* Invalid */
+ curtime.wSecond = 65535; /* Invalid */
+ curtime.wMilliseconds = 12345;
+ STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
+ ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
+}
+
+
+#define CY_POS_LEFT 0
+#define CY_POS_RIGHT 1
+#define CY_POS_LEFT_SPACE 2
+#define CY_POS_RIGHT_SPACE 3
+
+static void test_GetCurrencyFormatA(void)
+{
+ static char szDot[] = { '.', '\0' };
+ static char szComma[] = { ',', '\0' };
+ static char szDollar[] = { '$', '\0' };
+ int ret;
+ LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
+ CURRENCYFMTA format;
+
+ memset(&format, 0, sizeof(format));
+
+ STRINGSA("23",""); /* NULL output, length > 0 --> Error */
+ ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("23,53",""); /* Invalid character --> Error */
+ ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("--",""); /* Double '-' --> Error */
+ ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("0-",""); /* Trailing '-' --> Error */
+ ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("0..",""); /* Double '.' --> Error */
+ ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA(" 0.1",""); /* Leading space --> Error */
+ ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
+ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
+ EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("2353",""); /* Format and flags given --> Error */
+ ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("2353",""); /* Invalid format --> Error */
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("2353","$2,353.00"); /* Valid number */
+ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
+ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("2353.1","$2,353.10"); /* Valid real number */
+ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
+ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
+ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NumDigits = 0; /* No decimal separator */
+ format.LeadingZero = 0;
+ format.Grouping = 0; /* No grouping char */
+ format.NegativeOrder = 0;
+ format.PositiveOrder = CY_POS_LEFT;
+ format.lpDecimalSep = szDot;
+ format.lpThousandSep = szComma;
+ format.lpCurrencySymbol = szDollar;
+
+ STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
+ STRINGSA("2353","$2353.0");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.Grouping = 2; /* Group by 100's */
+ STRINGSA("2353","$23,53.0");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.LeadingZero = 1; /* Always provide leading zero */
+ STRINGSA(".5","$0.5");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.PositiveOrder = CY_POS_RIGHT;
+ STRINGSA("1","1.0$");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.PositiveOrder = CY_POS_LEFT_SPACE;
+ STRINGSA("1","$ 1.0");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.PositiveOrder = CY_POS_RIGHT_SPACE;
+ STRINGSA("1","1.0 $");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 0;
+ STRINGSA("-1","($1.0)");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 1;
+ STRINGSA("-1","-$1.0");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 2;
+ STRINGSA("-1","$-1.0");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 3;
+ STRINGSA("-1","$1.0-");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 4;
+ STRINGSA("-1","(1.0$)");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 5;
+ STRINGSA("-1","-1.0$");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 6;
+ STRINGSA("-1","1.0-$");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 7;
+ STRINGSA("-1","1.0$-");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 8;
+ STRINGSA("-1","-1.0 $");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 9;
+ STRINGSA("-1","-$ 1.0");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 10;
+ STRINGSA("-1","1.0 $-");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 11;
+ STRINGSA("-1","$ 1.0-");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 12;
+ STRINGSA("-1","$ -1.0");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 13;
+ STRINGSA("-1","1.0- $");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 14;
+ STRINGSA("-1","($ 1.0)");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = 15;
+ STRINGSA("-1","(1.0 $)");
+ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+}
+
+#define NEG_PARENS 0 /* "(1.1)" */
+#define NEG_LEFT 1 /* "-1.1" */
+#define NEG_LEFT_SPACE 2 /* "- 1.1" */
+#define NEG_RIGHT 3 /* "1.1-" */
+#define NEG_RIGHT_SPACE 4 /* "1.1 -" */
+
+static void test_GetNumberFormatA(void)
+{
+ static char szDot[] = { '.', '\0' };
+ static char szComma[] = { ',', '\0' };
+ int ret;
+ LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
+ NUMBERFMTA format;
+
+ memset(&format, 0, sizeof(format));
+
+ STRINGSA("23",""); /* NULL output, length > 0 --> Error */
+ ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("23,53",""); /* Invalid character --> Error */
+ ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("--",""); /* Double '-' --> Error */
+ ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("0-",""); /* Trailing '-' --> Error */
+ ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("0..",""); /* Double '.' --> Error */
+ ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA(" 0.1",""); /* Leading space --> Error */
+ ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
+ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
+ EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("2353",""); /* Format and flags given --> Error */
+ ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("2353",""); /* Invalid format --> Error */
+ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
+
+ STRINGSA("2353","2,353.00"); /* Valid number */
+ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("-2353","-2,353.00"); /* Valid negative number */
+ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
+ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("2353.1","2,353.10"); /* Valid real number */
+ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
+ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
+ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NumDigits = 0; /* No decimal separator */
+ format.LeadingZero = 0;
+ format.Grouping = 0; /* No grouping char */
+ format.NegativeOrder = 0;
+ format.lpDecimalSep = szDot;
+ format.lpThousandSep = szComma;
+
+ STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
+ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
+ STRINGSA("2353","2353.0");
+ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.Grouping = 2; /* Group by 100's */
+ STRINGSA("2353","23,53.0");
+ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.LeadingZero = 1; /* Always provide leading zero */
+ STRINGSA(".5","0.5");
+ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = NEG_PARENS;
+ STRINGSA("-1","(1.0)");
+ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = NEG_LEFT;
+ STRINGSA("-1","-1.0");
+ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = NEG_LEFT_SPACE;
+ STRINGSA("-1","- 1.0");
+ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = NEG_RIGHT;
+ STRINGSA("-1","1.0-");
+ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ format.NegativeOrder = NEG_RIGHT_SPACE;
+ STRINGSA("-1","1.0 -");
+ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+
+ lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
+
+ if (IsValidLocale(lcid, 0))
+ {
+ STRINGSA("-12345","-12 345,00"); /* Try French formatting */
+ Expected[3] = 160; /* Non breaking space */
+ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
+ EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
+ }
+}
+
+
+static void test_CompareStringA(void)
+{
+ int ret;
+ LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
+
+ ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
+ ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
+
+ ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
+ ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
+
+ ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
+ ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
+
+ ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
+ ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
+
+ lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+
+ ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
+ ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
+
+ ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
+ ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
+
+ ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
+ ok (ret == 2, "(Salut/saLuT) Expected 2, got %d\n", ret);
+
+ /* test for CompareStringA flags */
+ SetLastError(0xdeadbeef);
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x10, "NULL", -1, "NULL", -1);
+ ok(GetLastError() == ERROR_INVALID_FLAGS,
+ "unexpected error code %ld\n", GetLastError());
+ ok(!ret, "CompareStringA must fail with invalid flag\n");
+
+ SetLastError(0xdeadbeef);
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
+ ok(GetLastError() == 0xdeadbeef, "unexpected error code %ld\n", GetLastError());
+ ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
+ /* end of test for CompareStringA flags */
+
+ ret = lstrcmpA("", "");
+ ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
+
+ ret = lstrcmpA(NULL, NULL);
+ ok (ret == 0, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
+
+ ret = lstrcmpA("", NULL);
+ ok (ret == 1, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
+
+ ret = lstrcmpA(NULL, "");
+ ok (ret == -1, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"EndDialog",-1,"_Property",-1);
+ ok( ret == 3, "EndDialog vs _Property ... expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0070",-1,"_IEWWBrowserComp",-1);
+ ok( ret == 3, "osp_vba.sreg0070 vs _IEWWBrowserComp ... expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"r",-1,"\\",-1);
+ ok( ret == 3, "r vs \\ ... expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0031", -1, "OriginalDatabase", -1 );
+ ok( ret == 3, "osp_vba.sreg0031 vs OriginalDatabase ... expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1 );
+ ok( ret == 3, "AAA vs aaa expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1 );
+ ok( ret == 1, "AAA vs aab expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1 );
+ ok( ret == 1, "AAA vs Aab expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1 );
+ ok( ret == 1, ".AAA vs Aab expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1 );
+ ok( ret == 1, ".AAA vs A.ab expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1 );
+ ok( ret == 1, "aa vs AB expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1 );
+ ok( ret == 1, "aa vs Aab expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1 );
+ ok( ret == 3, "aB vs Aab expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1 );
+ ok( ret == 1, "Ba vs bab expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1 );
+ ok( ret == 1, "{100}{83}{71}{71}{71} vs Global_DataAccess_JRO expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1 );
+ ok( ret == 3, "a vs { expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1 );
+ ok( ret == 3, "A vs { expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1 );
+ ok(ret == 1, "3.5/0 vs 4.0/-1 expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1 );
+ ok(ret == 1, "3.5 vs 4.0 expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1 );
+ ok(ret == 1, "3.520.4403.2 vs 4.0.2927.10 expected 1, got %d\n", ret);
+
+ /* hyphen and apostrophe are treated differently depending on
+ * whether SORT_STRINGSORT specified or not
+ */
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1 );
+ ok(ret == 3, "-o vs /m expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1 );
+ ok(ret == 1, "/m vs -o expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1 );
+ ok(ret == 1, "-o vs /m expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1 );
+ ok(ret == 3, "/m vs -o expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1 );
+ ok(ret == 3, "'o vs /m expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1 );
+ ok(ret == 1, "/m vs 'o expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1 );
+ ok(ret == 1, "'o vs /m expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1 );
+ ok(ret == 3, "/m vs 'o expected 3, got %d\n", ret);
+
+ if (0) { /* this requires collation table patch to make it MS compatible */
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
+ ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
+ ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
+ ok(ret == 1, "' vs - expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
+ ok(ret == 1, "' vs - expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
+ ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
+ ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
+ ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
+ ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
+ ok(ret == 1, "`o vs -m expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
+ ok(ret == 3, "-m vs `o expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
+ ok(ret == 3, "`o vs -m expected 3, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
+ ok(ret == 1, "-m vs `o expected 1, got %d\n", ret);
+ }
+
+ ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9);
+ ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0 expected 2, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10);
+ ok(ret == 1, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
+ ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0A expected 2, got %d\n", ret);
+
+ ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
+ ok(ret == 2, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected 2, got %d\n", ret);
+}
+
+static void test_LCMapStringA(void)
+{
+ int ret, ret2;
+ char buf[256], buf2[256];
+ static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
+ static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
+ static const char symbols_stripped[] = "justateststring1";
+
+ SetLastError(0xdeadbeef);
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
+ lower_case, -1, buf, sizeof(buf));
+ ok(ret == lstrlenA(lower_case) + 1,
+ "ret %d, error %ld, expected value %d\n",
+ ret, GetLastError(), lstrlenA(lower_case) + 1);
+ ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
+
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
+ upper_case, -1, buf, sizeof(buf));
+ ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
+ ok(GetLastError() == ERROR_INVALID_FLAGS,
+ "unexpected error code %ld\n", GetLastError());
+
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
+ upper_case, -1, buf, sizeof(buf));
+ ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
+ ok(GetLastError() == ERROR_INVALID_FLAGS,
+ "unexpected error code %ld\n", GetLastError());
+
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
+ upper_case, -1, buf, sizeof(buf));
+ ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
+ ok(GetLastError() == ERROR_INVALID_FLAGS,
+ "unexpected error code %ld\n", GetLastError());
+
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
+ upper_case, -1, buf, sizeof(buf));
+ ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
+ ok(GetLastError() == ERROR_INVALID_FLAGS,
+ "unexpected error code %ld\n", GetLastError());
+
+ /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
+ SetLastError(0xdeadbeef);
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
+ upper_case, -1, buf, sizeof(buf));
+ ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
+ ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
+
+ /* test LCMAP_LOWERCASE */
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
+ upper_case, -1, buf, sizeof(buf));
+ ok(ret == lstrlenA(upper_case) + 1,
+ "ret %d, error %ld, expected value %d\n",
+ ret, GetLastError(), lstrlenA(upper_case) + 1);
+ ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
+
+ /* test LCMAP_UPPERCASE */
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
+ lower_case, -1, buf, sizeof(buf));
+ ok(ret == lstrlenA(lower_case) + 1,
+ "ret %d, error %ld, expected value %d\n",
+ ret, GetLastError(), lstrlenA(lower_case) + 1);
+ ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
+
+ /* test buffer overflow */
+ SetLastError(0xdeadbeef);
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
+ lower_case, -1, buf, 4);
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
+
+ /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
+ lstrcpyA(buf, lower_case);
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
+ buf, -1, buf, sizeof(buf));
+ if (!ret) /* Win9x */
+ trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
+ else
+ {
+ ok(ret == lstrlenA(lower_case) + 1,
+ "ret %d, error %ld, expected value %d\n",
+ ret, GetLastError(), lstrlenA(lower_case) + 1);
+ ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
+ }
+ lstrcpyA(buf, upper_case);
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
+ buf, -1, buf, sizeof(buf));
+ if (!ret) /* Win9x */
+ trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
+ else
+ {
+ ok(ret == lstrlenA(upper_case) + 1,
+ "ret %d, error %ld, expected value %d\n",
+ ret, GetLastError(), lstrlenA(lower_case) + 1);
+ ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
+ }
+
+ /* otherwise src == dst should fail */
+ SetLastError(0xdeadbeef);
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
+ buf, 10, buf, sizeof(buf));
+ ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
+ GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
+ "unexpected error code %ld\n", GetLastError());
+ ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
+
+ /* test whether '\0' is always appended */
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
+ upper_case, -1, buf, sizeof(buf));
+ ok(ret, "LCMapStringA must succeed\n");
+ ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
+ upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
+ ok(ret, "LCMapStringA must succeed\n");
+ ok(ret == ret2, "lengths of sort keys must be equal\n");
+ ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
+
+ /* test LCMAP_SORTKEY | NORM_IGNORECASE */
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
+ upper_case, -1, buf, sizeof(buf));
+ ok(ret, "LCMapStringA must succeed\n");
+ ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
+ lower_case, -1, buf2, sizeof(buf2));
+ ok(ret2, "LCMapStringA must succeed\n");
+ ok(ret == ret2, "lengths of sort keys must be equal\n");
+ ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
+
+ /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
+ lower_case, -1, buf, sizeof(buf));
+ ok(ret, "LCMapStringA must succeed\n");
+ ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
+ lower_case, -1, buf2, sizeof(buf2));
+ ok(ret2, "LCMapStringA must succeed\n");
+ ok(ret == ret2, "lengths of sort keys must be equal\n");
+ ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
+
+ /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
+ lower_case, -1, buf, sizeof(buf));
+ ok(ret, "LCMapStringA must succeed\n");
+ ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
+ symbols_stripped, -1, buf2, sizeof(buf2));
+ ok(ret2, "LCMapStringA must succeed\n");
+ ok(ret == ret2, "lengths of sort keys must be equal\n");
+ ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
+
+ /* test NORM_IGNORENONSPACE */
+ lstrcpyA(buf, "foo");
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
+ lower_case, -1, buf, sizeof(buf));
+ ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
+ lstrlenA(lower_case) + 1, ret);
+ ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
+
+ /* test NORM_IGNORESYMBOLS */
+ lstrcpyA(buf, "foo");
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
+ lower_case, -1, buf, sizeof(buf));
+ ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
+ lstrlenA(symbols_stripped) + 1, ret);
+ ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
+
+ /* test srclen = 0 */
+ SetLastError(0xdeadbeef);
+ ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
+ ok(!ret, "LCMapStringA should fail with srclen = 0\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "unexpected error code %ld\n", GetLastError());
+}
+
+static void test_LCMapStringW(void)
+{
+ int ret, ret2;
+ WCHAR buf[256], buf2[256];
+ char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
+ static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
+ static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
+ static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
+ static const WCHAR fooW[] = {'f','o','o',0};
+
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
+ upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+ {
+ trace("Skipping LCMapStringW tests on Win9x\n");
+ return;
+ }
+ ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
+ ok(GetLastError() == ERROR_INVALID_FLAGS,
+ "unexpected error code %ld\n", GetLastError());
+
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
+ upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
+ ok(GetLastError() == ERROR_INVALID_FLAGS,
+ "unexpected error code %ld\n", GetLastError());
+
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
+ upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
+ ok(GetLastError() == ERROR_INVALID_FLAGS,
+ "unexpected error code %ld\n", GetLastError());
+
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
+ upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
+ ok(GetLastError() == ERROR_INVALID_FLAGS,
+ "unexpected error code %ld\n", GetLastError());
+
+ /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
+ SetLastError(0xdeadbeef);
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
+ upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
+ ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
+
+ /* test LCMAP_LOWERCASE */
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
+ upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ ok(ret == lstrlenW(upper_case) + 1,
+ "ret %d, error %ld, expected value %d\n",
+ ret, GetLastError(), lstrlenW(upper_case) + 1);
+ ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
+
+ /* test LCMAP_UPPERCASE */
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
+ lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ ok(ret == lstrlenW(lower_case) + 1,
+ "ret %d, error %ld, expected value %d\n",
+ ret, GetLastError(), lstrlenW(lower_case) + 1);
+ ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
+
+ /* test buffer overflow */
+ SetLastError(0xdeadbeef);
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
+ lower_case, -1, buf, 4);
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
+
+ /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
+ lstrcpyW(buf, lower_case);
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
+ buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ ok(ret == lstrlenW(lower_case) + 1,
+ "ret %d, error %ld, expected value %d\n",
+ ret, GetLastError(), lstrlenW(lower_case) + 1);
+ ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
+
+ lstrcpyW(buf, upper_case);
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
+ buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ ok(ret == lstrlenW(upper_case) + 1,
+ "ret %d, error %ld, expected value %d\n",
+ ret, GetLastError(), lstrlenW(lower_case) + 1);
+ ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
+
+ /* otherwise src == dst should fail */
+ SetLastError(0xdeadbeef);
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
+ buf, 10, buf, sizeof(buf));
+ ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
+ GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
+ "unexpected error code %ld\n", GetLastError());
+ ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
+
+ /* test whether '\0' is always appended */
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
+ upper_case, -1, buf, sizeof(buf));
+ ok(ret, "LCMapStringW must succeed\n");
+ ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
+ upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
+ ok(ret, "LCMapStringW must succeed\n");
+ ok(ret == ret2, "lengths of sort keys must be equal\n");
+ ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
+
+ /* test LCMAP_SORTKEY | NORM_IGNORECASE */
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
+ upper_case, -1, buf, sizeof(buf));
+ ok(ret, "LCMapStringW must succeed\n");
+ ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
+ lower_case, -1, buf2, sizeof(buf2));
+ ok(ret2, "LCMapStringW must succeed\n");
+ ok(ret == ret2, "lengths of sort keys must be equal\n");
+ ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
+
+ /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
+ lower_case, -1, buf, sizeof(buf));
+ ok(ret, "LCMapStringW must succeed\n");
+ ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
+ lower_case, -1, buf2, sizeof(buf2));
+ ok(ret2, "LCMapStringW must succeed\n");
+ ok(ret == ret2, "lengths of sort keys must be equal\n");
+ ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
+
+ /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
+ lower_case, -1, buf, sizeof(buf));
+ ok(ret, "LCMapStringW must succeed\n");
+ ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
+ symbols_stripped, -1, buf2, sizeof(buf2));
+ ok(ret2, "LCMapStringW must succeed\n");
+ ok(ret == ret2, "lengths of sort keys must be equal\n");
+ ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
+
+ /* test NORM_IGNORENONSPACE */
+ lstrcpyW(buf, fooW);
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
+ lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
+ lstrlenW(lower_case) + 1, ret);
+ ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
+
+ /* test NORM_IGNORESYMBOLS */
+ lstrcpyW(buf, fooW);
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
+ lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
+ lstrlenW(symbols_stripped) + 1, ret);
+ ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
+
+ /* test srclen = 0 */
+ SetLastError(0xdeadbeef);
+ ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
+ ok(!ret, "LCMapStringW should fail with srclen = 0\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "unexpected error code %ld\n", GetLastError());
+}
+
+/* this requires collation table patch to make it MS compatible */
+const char *strings_sorted[] =
+{
+"'",
+"-",
+"!",
+"\"",
+".",
+":",
+"\\",
+"_",
+"`",
+"{",
+"}",
+"+",
+"0",
+"1",
+"2",
+"3",
+"4",
+"5",
+"6",
+"7",
+"8",
+"9",
+"a",
+"A",
+"b",
+"B",
+"c",
+"C"
+};
+
+const char *strings[] =
+{
+"C",
+"\"",
+"9",
+"'",
+"}",
+"-",
+"7",
+"+",
+"`",
+"1",
+"a",
+"5",
+"\\",
+"8",
+"B",
+"3",
+"_",
+"6",
+"{",
+"2",
+"c",
+"4",
+"!",
+"0",
+"A",
+":",
+"b",
+"."
+};
+
+static int compare_string1(const void *e1, const void *e2)
+{
+ const char *s1 = *(const char **)e1;
+ const char *s2 = *(const char **)e2;
+
+ return lstrcmpA(s1, s2);
+}
+
+static int compare_string2(const void *e1, const void *e2)
+{
+ const char *s1 = *(const char **)e1;
+ const char *s2 = *(const char **)e2;
+
+ return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
+}
+
+static int compare_string3(const void *e1, const void *e2)
+{
+ const char *s1 = *(const char **)e1;
+ const char *s2 = *(const char **)e2;
+ char key1[256], key2[256];
+
+ LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
+ LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
+ return strcmp(key1, key2);
+}
+
+static void test_sorting(void)
+{
+ char buf[256];
+ char **str_buf = (char **)buf;
+ int i;
+
+ assert(sizeof(buf) >= sizeof(strings));
+
+ /* 1. sort using lstrcmpA */
+ memcpy(buf, strings, sizeof(strings));
+ qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
+ for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
+ {
+ ok(!strcmp(strings_sorted[i], str_buf[i]),
+ "qsort using lstrcmpA failed for element %d\n", i);
+ }
+ /* 2. sort using CompareStringA */
+ memcpy(buf, strings, sizeof(strings));
+ qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
+ for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
+ {
+ ok(!strcmp(strings_sorted[i], str_buf[i]),
+ "qsort using CompareStringA failed for element %d\n", i);
+ }
+ /* 3. sort using sort keys */
+ memcpy(buf, strings, sizeof(strings));
+ qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
+ for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
+ {
+ ok(!strcmp(strings_sorted[i], str_buf[i]),
+ "qsort using sort keys failed for element %d\n", i);
+ }
+}
+
+static void test_FoldStringA(void)
+{
+ int ret, i;
+ char src[256], dst[256];
+ static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
+ static const char digits_dst[] = { '1','2','3','\0' };
+ static const char composite_src[] =
+ {
+ 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
+ 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
+ 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
+ 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
+ 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
+ 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
+ 0xfb,0xfc,0xfd,0xff,'\0'
+ };
+ static const char composite_dst[] =
+ {
+ 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
+ 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
+ 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
+ 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
+ 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
+ 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
+ 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
+ 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
+ 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
+ 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
+ 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
+ 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
+ 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
+ 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
+ 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
+ };
+ static const char ligatures_src[] =
+ {
+ 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
+ };
+ static const char ligatures_dst[] =
+ {
+ 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
+ };
+
+ if (!pFoldStringA)
+ return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
+
+ /* these tests are locale specific */
+ if (GetACP() != 1252)
+ {
+ trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
+ return;
+ }
+
+ /* MAP_FOLDDIGITS */
+ SetLastError(0);
+ ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
+ if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+ return;
+ EXPECT_LEN(4); EXPECT_VALID;
+ ok(strcmp(dst, digits_dst) == 0,
+ "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
+ for (i = 1; i < 256; i++)
+ {
+ if (!strchr(digits_src, i))
+ {
+ src[0] = i;
+ src[1] = '\0';
+ SetLastError(0);
+ ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
+ EXPECT_LEN(2); EXPECT_VALID;
+ ok(dst[0] == src[0],
+ "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
+ }
+ }
+
+ /* MAP_EXPAND_LIGATURES */
+ SetLastError(0);
+ ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
+ /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
+ if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
+ EXPECT_LEN(sizeof(ligatures_dst)); EXPECT_VALID;
+ ok(strcmp(dst, ligatures_dst) == 0,
+ "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
+ for (i = 1; i < 256; i++)
+ {
+ if (!strchr(ligatures_src, i))
+ {
+ src[0] = i;
+ src[1] = '\0';
+ SetLastError(0);
+ ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
+ EXPECT_LEN(2); EXPECT_VALID;
+ ok(dst[0] == src[0],
+ "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
+ }
+ }
+ }
+
+ /* MAP_COMPOSITE */
+ SetLastError(0);
+ ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
+ EXPECT_VALID;
+ todo_wine
+ {
+ /* Wine gets close, but doesn't produce quite the same result as native */
+ EXPECT_LEN(121);
+ ok(strcmp(dst, composite_dst) == 0,
+ "MAP_COMPOSITE: Expected '%s', got '%s'\n", composite_dst, dst);
+ }
+
+ for (i = 1; i < 256; i++)
+ {
+ if (!strchr(composite_src, i))
+ {
+ src[0] = i;
+ src[1] = '\0';
+ SetLastError(0);
+ ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
+ EXPECT_LEN(2); EXPECT_VALID;
+ ok(dst[0] == src[0],
+ "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
+ (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
+ }
+ }
+
+ /* MAP_FOLDCZONE */
+ for (i = 1; i < 256; i++)
+ {
+ src[0] = i;
+ src[1] = '\0';
+ SetLastError(0);
+ ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
+ EXPECT_LEN(2); EXPECT_VALID;
+ ok(src[0] == dst[0],
+ "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
+ (unsigned char)src[0], (unsigned char)dst[0]);
+ }
+
+ /* MAP_PRECOMPOSED */
+ for (i = 1; i < 256; i++)
+ {
+ src[0] = i;
+ src[1] = '\0';
+ SetLastError(0);
+ ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
+ EXPECT_LEN(2); EXPECT_VALID;
+ ok(src[0] == dst[0],
+ "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
+ (unsigned char)src[0], (unsigned char)dst[0]);
+ }
+}
+
+static void test_FoldStringW(void)
+{
+ int ret;
+ size_t i, j;
+ WCHAR src[256], dst[256], ch, prev_ch = 1;
+ static const DWORD badFlags[] =
+ {
+ 0,
+ MAP_PRECOMPOSED|MAP_COMPOSITE,
+ MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
+ MAP_COMPOSITE|MAP_EXPAND_LIGATURES
+ };
+ /* Ranges of digits 0-9 : Must be sorted! */
+ static const WCHAR digitRanges[] =
+ {
+ 0x0030, /* '0'-'9' */
+ 0x0660, /* Eastern Arabic */
+ 0x06F0, /* Arabic - Hindu */
+ 0x0966, /* Devengari */
+ 0x09E6, /* Bengalii */
+ 0x0A66, /* Gurmukhi */
+ 0x0AE6, /* Gujarati */
+ 0x0B66, /* Oriya */
+ 0x0BE6, /* Tamil - No 0 */
+ 0x0C66, /* Telugu */
+ 0x0CE6, /* Kannada */
+ 0x0D66, /* Maylayalam */
+ 0x0E50, /* Thai */
+ 0x0ED0, /* Laos */
+ 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
+ 0x2080, /* Subscript */
+ 0x245F, /* Circled - 0 is out of sequence */
+ 0x2473, /* Bracketed */
+ 0x2487, /* Full stop */
+ 0x2775, /* Inverted circled - No 0 */
+ 0x277F, /* Patterned circled - No 0 */
+ 0x2789, /* Inverted Patterned circled - No 0 */
+ 0xff10, /* Pliene chasse (?) */
+ 0xffff /* Terminator */
+ };
+ /* Digits which are represented, but out of sequence */
+ static const WCHAR outOfSequenceDigits[] =
+ {
+ 0xB9, /* Superscript 1 */
+ 0xB2, /* Superscript 2 */
+ 0xB3, /* Superscript 3 */
+ 0x24EA, /* Circled 0 */
+ '\0' /* Terminator */
+ };
+ /* Digits in digitRanges for which no representation is available */
+ static const WCHAR noDigitAvailable[] =
+ {
+ 0x0BE6, /* No Tamil 0 */
+ 0x2473, /* No Bracketed 0 */
+ 0x2487, /* No 0 Full stop */
+ 0x2775, /* No inverted circled 0 */
+ 0x277F, /* No patterned circled */
+ 0x2789, /* No inverted Patterned circled */
+ '\0' /* Terminator */
+ };
+ /* Compatibility conversion results */
+ static const WCHAR compat_F900_FA2F[256+48] =
+ {
+ 0x8c48, 0x66f4, 0x8eca, 0x8cc8, 0x6ed1, 0x4e32, 0x53e5, 0x9f9c,
+ 0x9f9c, 0x5951, 0x91d1, 0x5587, 0x5948, 0x61f6, 0x7669, 0x7f85,
+ 0x863f, 0x87ba, 0x88f8, 0x908f, 0x6a02, 0x6d1b, 0x70d9, 0x73de,
+ 0x843d, 0x916a, 0x99f1, 0x4e82, 0x5375, 0x6b04, 0x721b, 0x862d,
+ 0x9e1e, 0x5d50, 0x6feb, 0x85cd, 0x8964, 0x62c9, 0x81d8, 0x881f,
+ 0x5eca, 0x6717, 0x6d6a, 0x72fc, 0x0000, 0x4f86, 0x51b7, 0x52de,
+ 0x64c4, 0x6ad3, 0x7210, 0x76e7, 0x8001, 0x8606, 0x865c, 0x8def,
+ 0x9732, 0x9b6f, 0x9dfa, 0x788c, 0x797f, 0x7da0, 0x83c9, 0x9304,
+ 0x9e7f, 0x8ad6, 0x58df, 0x5f04, 0x7c60, 0x807e, 0x7262, 0x78ca,
+ 0x8cc2, 0x96f7, 0x58d8, 0x5c62, 0x6a13, 0x6dda, 0x6f0f, 0x7d2f,
+ 0x7e37, 0x964b, 0x52d2, 0x808b, 0x51dc, 0x51cc, 0x7a1c, 0x7dbe,
+ 0x83f1, 0x9675, 0x8b80, 0x62cf, 0x6a02, 0x8afe, 0x4e39, 0x5be7,
+ 0x6012, 0x7387, 0x7570, 0x5317, 0x78fb, 0x4fbf, 0x5fa9, 0x4e0d,
+ 0x6ccc, 0x6578, 0x7d22, 0x53c3, 0x585e, 0x7701, 0x8449, 0x8aaa,
+ 0x6bba, 0x8fb0, 0x6c88, 0x62fe, 0x82e5, 0x63a0, 0x7565, 0x4eae,
+ 0x5169, 0x0000, 0x6881, 0x7ce7, 0x826f, 0x8ad2, 0x91cf, 0x52f5,
+ 0x5442, 0x5973, 0x5eec, 0x65c5, 0x6ffe, 0x792a, 0x95ad, 0x9a6a,
+ 0x9e97, 0x9ece, 0x529b, 0x66c6, 0x6b77, 0x8f62, 0x5e74, 0x6190,
+ 0x6200, 0x649a, 0x6f23, 0x7149, 0x7489, 0x0000, 0x7df4, 0x806f,
+ 0x8f26, 0x84ee, 0x9023, 0x934a, 0x5217, 0x52a3, 0x54bd, 0x70c8,
+ 0x88c2, 0x8aaa, 0x5ec9, 0x5ff5, 0x637b, 0x6bae, 0x7c3e, 0x7375,
+ 0x4ee4, 0x56f9, 0x5be7, 0x5dba, 0x601c, 0x73b2, 0x7469, 0x7f9a,
+ 0x8046, 0x9234, 0x96f6, 0x9748, 0x9818, 0x4f8b, 0x79ae, 0x91b4,
+ 0x96b8, 0x60e1, 0x4e86, 0x50da, 0x5bee, 0x5c3f, 0x6599, 0x6a02,
+ 0x71ce, 0x7642, 0x84fc, 0x907c, 0x9f8d, 0x6688, 0x962e, 0x5289,
+ 0x677b, 0x67f3, 0x6d41, 0x6e9c, 0x7409, 0x7559, 0x786b, 0x7d10,
+ 0x985e, 0x516d, 0x622e, 0x9678, 0x502b, 0x5d19, 0x6dea, 0x8f2a,
+ 0x5f8b, 0x6144, 0x6817, 0x7387, 0x9686, 0x5229, 0x540f, 0x5c65,
+ 0x6613, 0x674e, 0x68a8, 0x6ce5, 0x7406, 0x75e2, 0x7f79, 0x0000,
+ 0x88e1, 0x91cc, 0x96e2, 0x533f, 0x6eba, 0x541d, 0x71d0, 0x7498,
+ 0x85fa, 0x0000, 0x9c57, 0x9e9f, 0x6797, 0x6dcb, 0x81e8, 0x7acb,
+ 0x7b20, 0x7c92, 0x72c0, 0x7099, 0x8b58, 0x4ec0, 0x8336, 0x523a,
+ 0x5207, 0x5ea6, 0x62d3, 0x7cd6, 0x5b85, 0x6d1e, 0x66b4, 0x8f3b,
+ 0x884c, 0x964d, 0x898b, 0x5ed3, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x585a, 0x0000, 0x6674, 0x0000, 0x0000, 0x51de, 0x8c6c, 0x76ca,
+ 0x0000, 0x795e, 0x7965, 0x798f, 0x9756, 0x7cbe, 0x7fbd, 0x0000,
+ 0x0000, 0x0000, 0x8af8, 0x0000, 0x0000, 0x9038, 0x90fd, 0x0000,
+ 0x0000, 0x0000, 0x98ef, 0x98fc, 0x9928, 0x9db4, 0x0000, 0x0000
+ };
+ static const WCHAR compat_FE30_FEF7[200] =
+ {
+ 0x2025, 0x2014, 0x2013, 0x005f, 0x005f, 0x0028, 0x0029, 0x007b,
+ 0x007d, 0x3014, 0x3015, 0x3010, 0x3011, 0x300a, 0x300b, 0x3008,
+ 0x3009, 0x300c, 0x300d, 0x300e, 0x300f, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x203e, 0x203e, 0x203e, 0x203e, 0x005f, 0x005f, 0x005f,
+ 0x002c, 0x3001, 0x002e, 0x0000, 0x003b, 0x003a, 0x003f, 0x0021,
+ 0x2014, 0x0028, 0x0029, 0x007b, 0x007d, 0x3014, 0x3015, 0x0023,
+ 0x0026, 0x002a, 0x002b, 0x002d, 0x003c, 0x003e, 0x003d, 0x0000,
+ 0x0000, 0x0024, 0x0025, 0x0040, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x064b, 0x064b, 0x064c, 0x0000, 0x064d, 0x0000, 0x064e, 0x064e,
+ 0x064f, 0x064f, 0x0650, 0x0650, 0x0651, 0x0651, 0x0652, 0x0652,
+ 0x0621, 0x0622, 0x0622, 0x0623, 0x0623, 0x0624, 0x0624, 0x0625,
+ 0x0625, 0x0626, 0x0626, 0x0626, 0x0626, 0x0627, 0x0627, 0x0628,
+ 0x0628, 0x0628, 0x0628, 0x0629, 0x0629, 0x062a, 0x062a, 0x062a,
+ 0x062a, 0x062b, 0x062b, 0x062b, 0x062b, 0x062c, 0x062c, 0x062c,
+ 0x062c, 0x062d, 0x062d, 0x062d, 0x062d, 0x062e, 0x062e, 0x062e,
+ 0x062e, 0x062f, 0x062f, 0x0630, 0x0630, 0x0631, 0x0631, 0x0632,
+ 0x0632, 0x0633, 0x0633, 0x0633, 0x0633, 0x0634, 0x0634, 0x0634,
+ 0x0634, 0x0635, 0x0635, 0x0635, 0x0635, 0x0636, 0x0636, 0x0636,
+ 0x0636, 0x0637, 0x0637, 0x0637, 0x0637, 0x0638, 0x0638, 0x0638,
+ 0x0638, 0x0639, 0x0639, 0x0639, 0x0639, 0x063a, 0x063a, 0x063a,
+ 0x063a, 0x0641, 0x0641, 0x0641, 0x0641, 0x0642, 0x0642, 0x0642,
+ 0x0642, 0x0643, 0x0643, 0x0643, 0x0643, 0x0644, 0x0644, 0x0644,
+ 0x0644, 0x0645, 0x0645, 0x0645, 0x0645, 0x0646, 0x0646, 0x0646,
+ 0x0646, 0x0647, 0x0647, 0x0647, 0x0647, 0x0648, 0x0648, 0x0649,
+ 0x0649, 0x064a, 0x064a, 0x064a, 0x064a, 0x0000, 0x0000, 0x0000
+ };
+ static const WCHAR compat_FF00_FFEF[240] =
+ {
+ 0x0000, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x0000, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000,
+ 0x0000, 0x3002, 0x300c, 0x300d, 0x3001, 0x30fb, 0x30f2, 0x30a1,
+ 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3,
+ 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad,
+ 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd,
+ 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc,
+ 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de,
+ 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9,
+ 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c,
+ 0x3164, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137,
+ 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f,
+ 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147,
+ 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x0000,
+ 0x0000, 0x0000, 0x314f, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154,
+ 0x0000, 0x0000, 0x3155, 0x3156, 0x3157, 0x3158, 0x3159, 0x315a,
+ 0x0000, 0x0000, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160,
+ 0x0000, 0x0000, 0x3161, 0x3162, 0x3163, 0x0000, 0x0000, 0x0000,
+ 0x00a2, 0x00a3, 0x00ac, 0x00af, 0x00a6, 0x00a5, 0x20a9, 0x0000,
+ 0x2502, 0x2190, 0x2191, 0x2192, 0x2193, 0x25a0, 0x25cb, 0x0000
+ };
+ static const WCHAR ligatures_src[] =
+ {
+ 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
+ 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
+ 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
+ 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
+ 0xfb04, 0xfb05, 0xfb06, '\0'
+ };
+ static const WCHAR ligatures_dst[] =
+ {
+ 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
+ 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
+ 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
+ 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
+ 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
+ };
+
+ if (!pFoldStringW)
+ return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
+
+ /* Invalid flag combinations */
+ for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
+ {
+ src[0] = dst[0] = '\0';
+ SetLastError(0);
+ ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
+ if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+ return;
+ EXPECT_LEN(0); EXPECT_FLAGS;
+ }
+
+ /* src & dst cannot be the same */
+ SetLastError(0);
+ ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
+ EXPECT_LEN(0); EXPECT_INVALID;
+
+ /* src can't be NULL */
+ SetLastError(0);
+ ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
+ EXPECT_LEN(0); EXPECT_INVALID;
+
+ /* srclen can't be 0 */
+ SetLastError(0);
+ ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
+ EXPECT_LEN(0); EXPECT_INVALID;
+
+ /* dstlen can't be < 0 */
+ SetLastError(0);
+ ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
+ EXPECT_LEN(0); EXPECT_INVALID;
+
+ /* Ret includes terminating NUL which is appended if srclen = -1 */
+ SetLastError(0);
+ src[0] = 'A';
+ src[1] = '\0';
+ dst[0] = '\0';
+ ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
+ EXPECT_LEN(2); EXPECT_VALID;
+ ok(dst[0] == 'A' && dst[1] == '\0',
+ "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%ld\n",
+ 'A', '\0', ret, dst[0], dst[1], GetLastError());
+
+ /* If size is given, result is not NUL terminated */
+ SetLastError(0);
+ src[0] = 'A';
+ src[1] = 'A';
+ dst[0] = 'X';
+ dst[1] = 'X';
+ ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
+ EXPECT_LEN(1); EXPECT_VALID;
+ ok(dst[0] == 'A' && dst[1] == 'X',
+ "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%ld\n",
+ 'A','X', ret, dst[0], dst[1], GetLastError());
+
+ /* MAP_FOLDDIGITS */
+ for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
+ {
+ /* Check everything before this range */
+ for (ch = prev_ch; ch < digitRanges[j]; ch++)
+ {
+ SetLastError(0);
+ src[0] = ch;
+ src[1] = dst[0] = '\0';
+ ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
+ EXPECT_LEN(2); EXPECT_VALID;
+
+ ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
+ /* Wine (correctly) maps all Unicode 4.0+ digits */
+ isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF,
+ "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
+ }
+
+ if (digitRanges[j] == 0xffff)
+ break; /* Finished the whole code point space */
+
+ for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
+ {
+ WCHAR c;
+
+ /* Map out of sequence characters */
+ if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
+ else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
+ else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
+ else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
+ else c = ch;
+ SetLastError(0);
+ src[0] = c;
+ src[1] = dst[0] = '\0';
+ ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
+ EXPECT_LEN(2); EXPECT_VALID;
+
+ ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
+ strchrW(noDigitAvailable, c),
+ "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
+ ch, '0' + digitRanges[j] - ch, dst[0]);
+ }
+ prev_ch = ch;
+ }
+
+ /* MAP_FOLDCZONE */
+ for (ch = 1; ch <0xffff; ch++)
+ {
+ WCHAR expected = 0;
+
+ if (ch >= 0xF900 && ch <= 0xFA2F)
+ expected = compat_F900_FA2F[ch - 0xF900];
+ else if (ch >= 0xFE30 && ch <= 0xFEF7)
+ expected = compat_FE30_FEF7[ch - 0xFE30];
+ else if (ch >= 0xFF00 && ch <= 0xFFEF)
+ expected = compat_FF00_FFEF[ch - 0xFF00];
+
+ if (!expected)
+ expected = ch;
+
+ SetLastError(0);
+ src[0] = ch;
+ src[1] = dst[0] = '\0';
+ ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
+ EXPECT_LEN(2); EXPECT_VALID;
+ ok(dst[0] == expected ||
+ /* Wine (correctly) uses updated mappings for some Unicode 4.0 chars */
+ (ch >= 0xFA0D && ch <= 0xFA47) ||
+ 0xf92c || ch == 0xf979 || ch == 0xf995 || ch == 0xf9e7 || ch == 0xf9f1,
+ "MAP_FOLDCZONE: ch %d 0x%04x Expected 0x%04x got 0x%04x\n",
+ ch, ch, expected, dst[0]);
+ }
+
+ /* MAP_EXPAND_LIGATURES */
+ SetLastError(0);
+ ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
+ /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
+ if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
+ EXPECT_LEN(sizeof(ligatures_dst)/sizeof(ligatures_dst[0])); EXPECT_VALID;
+ ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
+ "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
+ for (i = 1; i <= 0xffff; i++)
+ {
+ if (!strchrW(ligatures_src, i))
+ {
+ src[0] = i;
+ src[1] = '\0';
+ SetLastError(0);
+ ret = pFoldStringW(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
+ EXPECT_LEN(2); EXPECT_VALID;
+ ok(dst[0] == src[0],
+ "MAP_EXPAND_LIGATURES: 0x%02x : Expected 0x%02x, got 0x%02x\n",
+ i, src[0], dst[0]);
+ }
+ }
+ }
+
+ /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
+}
+
+
+
+#define LCID_OK(l) \
+ ok(lcid == l, "Expected lcid = %08lx, got %08lx\n", l, lcid)
+#define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
+#define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
+#define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
+#define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
+
+static void test_ConvertDefaultLocale(void)
+{
+ LCID lcid;
+
+ /* Doesn't change lcid, even if non default sublang/sort used */
+ TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
+ TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
+ TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
+ TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
+
+ /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
+ LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
+ MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
+ LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
+ MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
+ LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE),
+ MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE));
+
+ /* Invariant language is not treated specially */
+ TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
+ LCID_RES(MKLCID(LANG_INVARIANT, SUBLANG_NEUTRAL, SORT_DEFAULT),
+ MKLCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT));
+
+ /* User/system default languages alone are not mapped */
+ TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
+ TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
+
+ /* Default lcids */
+ LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
+ LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
+ LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
+}
+
+static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
+ DWORD dwFlags, LONG_PTR lParam)
+{
+ trace("%08lx, %s, %s, %08lx, %08lx\n",
+ lgrpid, lpszNum, lpszName, dwFlags, lParam);
+
+ ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
+ "Enumerated grp %ld not valid (flags %ld)\n", lgrpid, dwFlags);
+
+ /* If lParam is one, we are calling with flags defaulted from 0 */
+ ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
+ "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %ld\n", dwFlags);
+
+ return TRUE;
+}
+
+static void test_EnumSystemLanguageGroupsA(void)
+{
+ if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
+ return;
+
+ /* No enumeration proc */
+ SetLastError(0);
+ pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
+ EXPECT_INVALID;
+
+ /* Invalid flags */
+ SetLastError(0);
+ pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
+ EXPECT_FLAGS;
+
+ /* No flags - defaults to LGRPID_INSTALLED */
+ SetLastError(0);
+ pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
+ EXPECT_VALID;
+
+ pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
+ pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
+}
+
+
+static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
+ LONG_PTR lParam)
+{
+ trace("%08lx, %08lx, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
+
+ ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
+ "Enumerated grp %ld not valid\n", lgrpid);
+ ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
+ "Enumerated grp locale %ld not valid\n", lcid);
+ return TRUE;
+}
+
+static void test_EnumLanguageGroupLocalesA(void)
+{
+ if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
+ return;
+
+ /* No enumeration proc */
+ SetLastError(0);
+ pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
+ EXPECT_INVALID;
+
+ /* lgrpid too small */
+ SetLastError(0);
+ pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
+ EXPECT_INVALID;
+
+ /* lgrpid too big */
+ SetLastError(0);
+ pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
+ EXPECT_INVALID;
+
+ /* dwFlags is reserved */
+ SetLastError(0);
+ pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
+ EXPECT_INVALID;
+
+ pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
+}
+
+static void test_SetLocaleInfoA(void)
+{
+ BOOL bRet;
+ LCID lcid = GetUserDefaultLCID();
+
+ /* Null data */
+ SetLastError(0);
+ bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
+ EXPECT_INVALID;
+
+ /* IDATE */
+ SetLastError(0);
+ bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA);
+ EXPECT_FLAGS;
+
+ /* ILDATE */
+ SetLastError(0);
+ bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA);
+ EXPECT_FLAGS;
+}
+
+static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
+{
+ trace("%s %08lx\n", value, lParam);
+ return(TRUE);
+}
+
+static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
+{
+ ok(!enumCount, "callback called again unexpected\n");
+ enumCount++;
+ return(FALSE);
+}
+
+static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
+{
+ ok(0,"callback called unexpected\n");
+ return(FALSE);
+}
+
+static void test_EnumUILanguageA(void)
+{
+ BOOL ret;
+ if (!pEnumUILanguagesA) {
+ trace("EnumUILanguagesA is not available on Win9x\n");
+ return;
+ }
+
+ SetLastError(ERROR_SUCCESS);
+ ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
+ EXPECT_TRUE; EXPECT_VALID;
+
+ enumCount = 0;
+ SetLastError(ERROR_SUCCESS);
+ ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
+ EXPECT_TRUE; EXPECT_VALID;
+
+ SetLastError(ERROR_SUCCESS);
+ ret = pEnumUILanguagesA(NULL, 0, 0);
+ EXPECT_FALSE; EXPECT_INVALID;
+
+ SetLastError(ERROR_SUCCESS);
+ ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
+ EXPECT_FALSE; EXPECT_FLAGS;
+
+ SetLastError(ERROR_SUCCESS);
+ ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
+ EXPECT_FALSE; EXPECT_INVALID;
+}
+
+static char date_fmt_buf[1024];
+
+static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
+{
+ lstrcatA(date_fmt_buf, fmt);
+ lstrcatA(date_fmt_buf, "\n");
+ return TRUE;
+}
+
+static void test_EnumDateFormatsA(void)
+{
+ char *p, buf[256];
+ BOOL ret;
+ LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+
+ trace("EnumDateFormatsA 0\n");
+ date_fmt_buf[0] = 0;
+ ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
+ ok(ret, "EnumDateFormatsA(0) error %ld\n", GetLastError());
+ trace("%s\n", date_fmt_buf);
+ /* test the 1st enumerated format */
+ if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
+ ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
+ ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError());
+ ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
+
+ trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
+ date_fmt_buf[0] = 0;
+ ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
+ ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %ld\n", GetLastError());
+ trace("%s\n", date_fmt_buf);
+ /* test the 1st enumerated format */
+ if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
+ ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
+ ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError());
+ ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
+
+ trace("EnumDateFormatsA DATE_SHORTDATE\n");
+ date_fmt_buf[0] = 0;
+ ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
+ ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %ld\n", GetLastError());
+ trace("%s\n", date_fmt_buf);
+ /* test the 1st enumerated format */
+ if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
+ ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
+ ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError());
+ ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
+
+ trace("EnumDateFormatsA DATE_LONGDATE\n");
+ date_fmt_buf[0] = 0;
+ ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
+ ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %ld\n", GetLastError());
+ trace("%s\n", date_fmt_buf);
+ /* test the 1st enumerated format */
+ if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
+ ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
+ ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %ld\n", GetLastError());
+ ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
+
+ trace("EnumDateFormatsA DATE_YEARMONTH\n");
+ date_fmt_buf[0] = 0;
+ ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
+ ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %ld\n", GetLastError());
+ trace("%s\n", date_fmt_buf);
+ /* test the 1st enumerated format */
+ if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
+ ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
+ ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %ld\n", GetLastError());
+ ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
+}
+
+static void test_EnumTimeFormatsA(void)
+{
+ char *p, buf[256];
+ BOOL ret;
+ LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+
+ trace("EnumTimeFormatsA 0\n");
+ date_fmt_buf[0] = 0;
+ ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
+ ok(ret, "EnumTimeFormatsA(0) error %ld\n", GetLastError());
+ trace("%s\n", date_fmt_buf);
+ /* test the 1st enumerated format */
+ if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
+ ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
+ ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %ld\n", GetLastError());
+ ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
+
+ trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
+ date_fmt_buf[0] = 0;
+ ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
+ ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %ld\n", GetLastError());
+ trace("%s\n", date_fmt_buf);
+ /* test the 1st enumerated format */
+ if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
+ ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
+ ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %ld\n", GetLastError());
+ ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
+}
+
+START_TEST(locale)
+{
+ InitFunctionPointers();
+
+ test_EnumTimeFormatsA();
+ test_EnumDateFormatsA();
+
+ test_GetLocaleInfoA();
+ test_GetTimeFormatA();
+ test_GetDateFormatA();
+ test_GetDateFormatW();
+ test_GetCurrencyFormatA(); /* Also tests the W version */
+ test_GetNumberFormatA(); /* Also tests the W version */
+ test_CompareStringA();
+ test_LCMapStringA();
+ test_LCMapStringW();
+ test_FoldStringA();
+ test_FoldStringW();
+ test_ConvertDefaultLocale();
+ test_EnumSystemLanguageGroupsA();
+ test_EnumLanguageGroupLocalesA();
+ test_SetLocaleInfoA();
+ test_EnumUILanguageA();
+
+ /* this requires collation table patch to make it MS compatible */
+ if (0) test_sorting();
+}
--- /dev/null
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 == ~0UL, "dwMax incorrect\n");
+ ok( dwNext == MAILSLOT_NO_MESSAGE, "dwNext incorrect\n");
+ ok( dwMsgCount == 0, "dwMsgCount incorrect\n");
+ ok( dwTimeout == ~0UL, "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();
+}
--- /dev/null
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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;
+ FARPROC fp;
+
+ SetLastError(0xdeadbeef);
+ hModule = LoadLibraryA("ntdll.dll");
+ ok( hModule != NULL, "ntdll.dll should be loadable\n");
+ ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %08lx\n", GetLastError());
+
+ fp = GetProcAddress(hModule, "NtCreateFile");
+ ok( fp != NULL, "Call should be there\n");
+ ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %08lx\n", GetLastError());
+
+ 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();
+}
--- /dev/null
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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;
+
+ *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,
+ "GetTempPath returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
+ newdir,tmpstr,tmpstr1,id);
+
+/* 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(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");
+ 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 */