ntdll/kernel32: GetCommState & IOCTL_SERIAL_GET_HANDFLOW
[wine] / dlls / kernel / virtual.c
1 /*
2  * Win32 virtual memory functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <fcntl.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
35 #include "ntstatus.h"
36 #define WIN32_NO_STATUS
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winternl.h"
41 #include "winerror.h"
42 #include "wine/exception.h"
43 #include "excpt.h"
44 #include "wine/debug.h"
45
46 #include "kernel_private.h"
47
48 WINE_DECLARE_DEBUG_CHANNEL(seh);
49
50 static unsigned int page_size;
51
52
53 /***********************************************************************
54  *             VirtualAlloc   (KERNEL32.@)
55  *
56  * Reserves or commits a region of pages in virtual address space.
57  *
58  * PARAMS
59  *  addr    [I] Address of region to reserve or commit.
60  *  size    [I] Size of region.
61  *  type    [I] Type of allocation.
62  *  protect [I] Type of access protection.
63  *
64  * RETURNS
65  *      Success: Base address of allocated region of pages.
66  *      Failure: NULL.
67  */
68 LPVOID WINAPI VirtualAlloc( LPVOID addr, SIZE_T size, DWORD type, DWORD protect )
69 {
70     return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect );
71 }
72
73
74 /***********************************************************************
75  *             VirtualAllocEx   (KERNEL32.@)
76  *
77  * Seems to be just as VirtualAlloc, but with process handle.
78  *
79  * PARAMS
80  *  hProcess [I] Handle to process to do mem operation.
81  *  addr     [I] Address of region to reserve or commit.
82  *  size     [I] Size of region.
83  *  type     [I] Type of allocation.
84  *  protect  [I] Type of access protection.
85  *
86  *
87  * RETURNS
88  *      Success: Base address of allocated region of pages.
89  *      Failure: NULL.
90  */
91 LPVOID WINAPI VirtualAllocEx( HANDLE hProcess, LPVOID addr, SIZE_T size,
92     DWORD type, DWORD protect )
93 {
94     LPVOID ret = addr;
95     NTSTATUS status;
96
97     if ((status = NtAllocateVirtualMemory( hProcess, &ret, 0, &size, type, protect )))
98     {
99         SetLastError( RtlNtStatusToDosError(status) );
100         ret = NULL;
101     }
102     return ret;
103 }
104
105
106 /***********************************************************************
107  *             VirtualFree   (KERNEL32.@)
108  *
109  * Releases or decommits a region of pages in virtual address space.
110  *
111  * PARAMS
112  *  addr [I] Address of region of committed pages.
113  *  size [I] Size of region.
114  *  type [I] Type of operation.
115  *
116  * RETURNS
117  *      Success: TRUE.
118  *      Failure: FALSE.
119  */
120 BOOL WINAPI VirtualFree( LPVOID addr, SIZE_T size, DWORD type )
121 {
122     return VirtualFreeEx( GetCurrentProcess(), addr, size, type );
123 }
124
125
126 /***********************************************************************
127  *             VirtualFreeEx   (KERNEL32.@)
128  *
129  * Releases or decommits a region of pages in virtual address space.
130  *
131  * PARAMS
132  *  process [I] Handle to process.
133  *  addr    [I] Address of region to free.
134  *  size    [I] Size of region.
135  *  type    [I] Type of operation.
136  *
137  * RETURNS
138  *      Success: TRUE.
139  *      Failure: FALSE.
140  */
141 BOOL WINAPI VirtualFreeEx( HANDLE process, LPVOID addr, SIZE_T size, DWORD type )
142 {
143     NTSTATUS status = NtFreeVirtualMemory( process, &addr, &size, type );
144     if (status) SetLastError( RtlNtStatusToDosError(status) );
145     return !status;
146 }
147
148
149 /***********************************************************************
150  *             VirtualLock   (KERNEL32.@)
151  *
152  * Locks the specified region of virtual address space.
153  *
154  * PARAMS
155  *  addr [I] Address of first byte of range to lock.
156  *  size [I] Number of bytes in range to lock.
157  *
158  * RETURNS
159  *      Success: TRUE.
160  *      Failure: FALSE.
161  *
162  * NOTES
163  *      Always returns TRUE.
164  *
165  */
166 BOOL WINAPI VirtualLock( LPVOID addr, SIZE_T size )
167 {
168     NTSTATUS status = NtLockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
169     if (status) SetLastError( RtlNtStatusToDosError(status) );
170     return !status;
171 }
172
173
174 /***********************************************************************
175  *             VirtualUnlock   (KERNEL32.@)
176  *
177  * Unlocks a range of pages in the virtual address space.
178  *
179  * PARAMS
180  *  addr [I] Address of first byte of range.
181  *  size [I] Number of bytes in range.
182  *
183  * RETURNS
184  *      Success: TRUE.
185  *      Failure: FALSE.
186  *
187  * NOTES
188  *      Always returns TRUE.
189  *
190  */
191 BOOL WINAPI VirtualUnlock( LPVOID addr, SIZE_T size )
192 {
193     NTSTATUS status = NtUnlockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
194     if (status) SetLastError( RtlNtStatusToDosError(status) );
195     return !status;
196 }
197
198
199 /***********************************************************************
200  *             VirtualProtect   (KERNEL32.@)
201  *
202  * Changes the access protection on a region of committed pages.
203  *
204  * PARAMS
205  *  addr     [I] Address of region of committed pages.
206  *  size     [I] Size of region.
207  *  new_prot [I] Desired access protection.
208  *  old_prot [O] Address of variable to get old protection.
209  *
210  * RETURNS
211  *      Success: TRUE.
212  *      Failure: FALSE.
213  */
214 BOOL WINAPI VirtualProtect( LPVOID addr, SIZE_T size, DWORD new_prot, LPDWORD old_prot)
215 {
216     return VirtualProtectEx( GetCurrentProcess(), addr, size, new_prot, old_prot );
217 }
218
219
220 /***********************************************************************
221  *             VirtualProtectEx   (KERNEL32.@)
222  *
223  * Changes the access protection on a region of committed pages in the
224  * virtual address space of a specified process.
225  *
226  * PARAMS
227  *  process  [I] Handle of process.
228  *  addr     [I] Address of region of committed pages.
229  *  size     [I] Size of region.
230  *  new_prot [I] Desired access protection.
231  *  old_prot [O] Address of variable to get old protection.
232  *
233  * RETURNS
234  *      Success: TRUE.
235  *      Failure: FALSE.
236  */
237 BOOL WINAPI VirtualProtectEx( HANDLE process, LPVOID addr, SIZE_T size,
238     DWORD new_prot, LPDWORD old_prot )
239 {
240     NTSTATUS status = NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot );
241     if (status) SetLastError( RtlNtStatusToDosError(status) );
242     return !status;
243 }
244
245
246 /***********************************************************************
247  *             VirtualQuery   (KERNEL32.@)
248  *
249  * Provides info about a range of pages in virtual address space.
250  *
251  * PARAMS
252  *  addr [I] Address of region.
253  *  info [O] Address of info buffer.
254  *  len  [I] Size of buffer.
255  *
256  * RETURNS
257  *      Number of bytes returned in information buffer or 0 if
258  *      addr >= 0xc0000000 (kernel space).
259  */
260 SIZE_T WINAPI VirtualQuery( LPCVOID addr, PMEMORY_BASIC_INFORMATION info,
261     SIZE_T len )
262 {
263     return VirtualQueryEx( GetCurrentProcess(), addr, info, len );
264 }
265
266
267 /***********************************************************************
268  *             VirtualQueryEx   (KERNEL32.@)
269  *
270  * Provides info about a range of pages in virtual address space of a
271  * specified process.
272  *
273  * PARAMS
274  *  process [I] Handle to process.
275  *  addr    [I] Address of region.
276  *  info    [O] Address of info buffer.
277  *  len     [I] Size of buffer.
278  *
279  * RETURNS
280  *      Number of bytes returned in information buffer.
281  */
282 SIZE_T WINAPI VirtualQueryEx( HANDLE process, LPCVOID addr,
283     PMEMORY_BASIC_INFORMATION info, SIZE_T len )
284 {
285     SIZE_T ret;
286     NTSTATUS status;
287
288     if ((status = NtQueryVirtualMemory( process, addr, MemoryBasicInformation, info, len, &ret )))
289     {
290         SetLastError( RtlNtStatusToDosError(status) );
291         ret = 0;
292     }
293     return ret;
294 }
295
296
297 /***********************************************************************
298  *             CreateFileMappingA   (KERNEL32.@)
299  *
300  * Creates a named or unnamed file-mapping object for the specified file.
301  *
302  * PARAMS
303  *  hFile     [I] Handle to the file to map.
304  *  sa        [I] Optional security attributes.
305  *  protect   [I] Protection for mapping object.
306  *  size_high [I] High-order 32 bits of object size.
307  *  size_low  [I] Low-order 32 bits of object size.
308  *  name      [I] Name of file-mapping object.
309  *
310  * RETURNS
311  *      Success: Handle.
312  *      Failure: NULL. Mapping object does not exist.
313  */
314 HANDLE WINAPI CreateFileMappingA( HANDLE hFile, SECURITY_ATTRIBUTES *sa,
315     DWORD protect, DWORD size_high, DWORD size_low, LPCSTR name )
316 {
317     WCHAR buffer[MAX_PATH];
318
319     if (!name) return CreateFileMappingW( hFile, sa, protect, size_high, size_low, NULL );
320
321     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
322     {
323         SetLastError( ERROR_FILENAME_EXCED_RANGE );
324         return 0;
325     }
326     return CreateFileMappingW( hFile, sa, protect, size_high, size_low, buffer );
327 }
328
329
330 /***********************************************************************
331  *             CreateFileMappingW   (KERNEL32.@)
332  *
333  * See CreateFileMappingA.
334  */
335 HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa,
336                                   DWORD protect, DWORD size_high,
337                                   DWORD size_low, LPCWSTR name )
338 {
339     static const int sec_flags = SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE;
340
341     HANDLE ret;
342     OBJECT_ATTRIBUTES attr;
343     UNICODE_STRING nameW;
344     NTSTATUS status;
345     DWORD access, sec_type;
346     LARGE_INTEGER size;
347
348     attr.Length                   = sizeof(attr);
349     attr.RootDirectory            = 0;
350     attr.ObjectName               = NULL;
351     attr.Attributes               = OBJ_CASE_INSENSITIVE | OBJ_OPENIF |
352                                     ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0);
353     attr.SecurityDescriptor       = sa ? sa->lpSecurityDescriptor : NULL;
354     attr.SecurityQualityOfService = NULL;
355
356     if (name)
357     {
358         RtlInitUnicodeString( &nameW, name );
359         attr.ObjectName = &nameW;
360         attr.RootDirectory = get_BaseNamedObjects_handle();
361     }
362
363     sec_type = protect & sec_flags;
364     protect &= ~sec_flags;
365     if (!sec_type) sec_type = SEC_COMMIT;
366
367     switch(protect)
368     {
369     case 0:
370         protect = PAGE_READONLY;  /* Win9x compatibility */
371         /* fall through */
372     case PAGE_READONLY:
373     case PAGE_WRITECOPY:
374         access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
375         break;
376     case PAGE_READWRITE:
377         access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE;
378         break;
379     default:
380         SetLastError( ERROR_INVALID_PARAMETER );
381         return 0;
382     }
383
384     if (hFile == INVALID_HANDLE_VALUE)
385     {
386         hFile = 0;
387         if (!size_low && !size_high)
388         {
389             SetLastError( ERROR_INVALID_PARAMETER );
390             return 0;
391         }
392     }
393
394     size.u.LowPart  = size_low;
395     size.u.HighPart = size_high;
396
397     status = NtCreateSection( &ret, access, &attr, &size, protect, sec_type, hFile );
398     if (status == STATUS_OBJECT_NAME_EXISTS)
399         SetLastError( ERROR_ALREADY_EXISTS );
400     else
401         SetLastError( RtlNtStatusToDosError(status) );
402     return ret;
403 }
404
405
406 /***********************************************************************
407  *             OpenFileMappingA   (KERNEL32.@)
408  *
409  * Opens a named file-mapping object.
410  *
411  * PARAMS
412  *  access  [I] Access mode.
413  *  inherit [I] Inherit flag.
414  *  name    [I] Name of file-mapping object.
415  *
416  * RETURNS
417  *      Success: Handle.
418  *      Failure: NULL.
419  */
420 HANDLE WINAPI OpenFileMappingA( DWORD access, BOOL inherit, LPCSTR name )
421 {
422     WCHAR buffer[MAX_PATH];
423
424     if (!name) return OpenFileMappingW( access, inherit, NULL );
425
426     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
427     {
428         SetLastError( ERROR_FILENAME_EXCED_RANGE );
429         return 0;
430     }
431     return OpenFileMappingW( access, inherit, buffer );
432 }
433
434
435 /***********************************************************************
436  *             OpenFileMappingW   (KERNEL32.@)
437  *
438  * See OpenFileMappingA.
439  */
440 HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
441 {
442     OBJECT_ATTRIBUTES attr;
443     UNICODE_STRING nameW;
444     HANDLE ret;
445     NTSTATUS status;
446
447     if (!name)
448     {
449         SetLastError( ERROR_INVALID_PARAMETER );
450         return 0;
451     }
452     attr.Length = sizeof(attr);
453     attr.RootDirectory = get_BaseNamedObjects_handle();
454     attr.ObjectName = &nameW;
455     attr.Attributes = OBJ_CASE_INSENSITIVE | (inherit ? OBJ_INHERIT : 0);
456     attr.SecurityDescriptor = NULL;
457     attr.SecurityQualityOfService = NULL;
458     RtlInitUnicodeString( &nameW, name );
459
460     if (access == FILE_MAP_COPY) access = FILE_MAP_READ;
461
462     if ((status = NtOpenSection( &ret, access, &attr )))
463     {
464         SetLastError( RtlNtStatusToDosError(status) );
465         ret = 0;
466     }
467     return ret;
468 }
469
470
471 /***********************************************************************
472  *             MapViewOfFile   (KERNEL32.@)
473  *
474  * Maps a view of a file into the address space.
475  *
476  * PARAMS
477  *  mapping     [I] File-mapping object to map.
478  *  access      [I] Access mode.
479  *  offset_high [I] High-order 32 bits of file offset.
480  *  offset_low  [I] Low-order 32 bits of file offset.
481  *  count       [I] Number of bytes to map.
482  *
483  * RETURNS
484  *      Success: Starting address of mapped view.
485  *      Failure: NULL.
486  */
487 LPVOID WINAPI MapViewOfFile( HANDLE mapping, DWORD access,
488     DWORD offset_high, DWORD offset_low, SIZE_T count )
489 {
490     return MapViewOfFileEx( mapping, access, offset_high,
491                             offset_low, count, NULL );
492 }
493
494
495 /***********************************************************************
496  *             MapViewOfFileEx   (KERNEL32.@)
497  *
498  * Maps a view of a file into the address space.
499  *
500  * PARAMS
501  *  handle      [I] File-mapping object to map.
502  *  access      [I] Access mode.
503  *  offset_high [I] High-order 32 bits of file offset.
504  *  offset_low  [I] Low-order 32 bits of file offset.
505  *  count       [I] Number of bytes to map.
506  *  addr        [I] Suggested starting address for mapped view.
507  *
508  * RETURNS
509  *      Success: Starting address of mapped view.
510  *      Failure: NULL.
511  */
512 LPVOID WINAPI MapViewOfFileEx( HANDLE handle, DWORD access,
513     DWORD offset_high, DWORD offset_low, SIZE_T count, LPVOID addr )
514 {
515     NTSTATUS status;
516     LARGE_INTEGER offset;
517     ULONG protect;
518
519     offset.u.LowPart  = offset_low;
520     offset.u.HighPart = offset_high;
521
522     if (access & FILE_MAP_WRITE) protect = PAGE_READWRITE;
523     else if (access & FILE_MAP_READ) protect = PAGE_READONLY;
524     else if (access & FILE_MAP_COPY) protect = PAGE_WRITECOPY;
525     else protect = PAGE_NOACCESS;
526
527     if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, &offset,
528                                       &count, ViewShare, 0, protect )))
529     {
530         SetLastError( RtlNtStatusToDosError(status) );
531         addr = NULL;
532     }
533     return addr;
534 }
535
536
537 /***********************************************************************
538  *             UnmapViewOfFile   (KERNEL32.@)
539  *
540  * Unmaps a mapped view of a file.
541  *
542  * PARAMS
543  *  addr [I] Address where mapped view begins.
544  *
545  * RETURNS
546  *      Success: TRUE.
547  *      Failure: FALSE.
548  *
549  * NOTES
550  *      Should addr be an LPCVOID?
551  */
552 BOOL WINAPI UnmapViewOfFile( LPVOID addr )
553 {
554     NTSTATUS status = NtUnmapViewOfSection( GetCurrentProcess(), addr );
555     if (status) SetLastError( RtlNtStatusToDosError(status) );
556     return !status;
557 }
558
559
560 /***********************************************************************
561  *             FlushViewOfFile   (KERNEL32.@)
562  *
563  * Writes to the disk a byte range within a mapped view of a file.
564  *
565  * PARAMS
566  *  base [I] Start address of byte range to flush.
567  *  size [I] Number of bytes in range.
568  *
569  * RETURNS
570  *      Success: TRUE.
571  *      Failure: FALSE.
572  */
573 BOOL WINAPI FlushViewOfFile( LPCVOID base, SIZE_T size )
574 {
575     NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 );
576     if (status)
577     {
578         if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS;
579         else SetLastError( RtlNtStatusToDosError(status) );
580     }
581     return !status;
582 }
583
584
585 /***********************************************************************
586  *             IsBadReadPtr   (KERNEL32.@)
587  *
588  * Check for read access on a memory block.
589  *
590  * ptr  [I] Address of memory block.
591  * size [I] Size of block.
592  *
593  * RETURNS
594  *  Success: TRUE.
595  *      Failure: FALSE. Process has read access to entire block.
596  */
597 BOOL WINAPI IsBadReadPtr( LPCVOID ptr, UINT size )
598 {
599     if (!size) return FALSE;  /* handle 0 size case w/o reference */
600     if (!ptr) return TRUE;
601     
602     if (!page_size) page_size = getpagesize();
603     __TRY
604     {
605         volatile const char *p = ptr;
606         char dummy;
607         UINT count = size;
608
609         while (count > page_size)
610         {
611             dummy = *p;
612             p += page_size;
613             count -= page_size;
614         }
615         dummy = p[0];
616         dummy = p[count - 1];
617     }
618     __EXCEPT_PAGE_FAULT
619     {
620         TRACE_(seh)("%p caused page fault during read\n", ptr);
621         return TRUE;
622     }
623     __ENDTRY
624     return FALSE;
625 }
626
627
628 /***********************************************************************
629  *             IsBadWritePtr   (KERNEL32.@)
630  *
631  * Check for write access on a memory block.
632  *
633  * PARAMS
634  *  ptr  [I] Address of memory block.
635  *  size [I] Size of block in bytes.
636  *
637  * RETURNS
638  *  Success: TRUE.
639  *      Failure: FALSE. Process has write access to entire block.
640  */
641 BOOL WINAPI IsBadWritePtr( LPVOID ptr, UINT size )
642 {
643     if (!size) return FALSE;  /* handle 0 size case w/o reference */
644     if (!ptr) return TRUE;
645     
646     if (!page_size) page_size = getpagesize();
647     __TRY
648     {
649         volatile char *p = ptr;
650         UINT count = size;
651
652         while (count > page_size)
653         {
654             *p |= 0;
655             p += page_size;
656             count -= page_size;
657         }
658         p[0] |= 0;
659         p[count - 1] |= 0;
660     }
661     __EXCEPT_PAGE_FAULT
662     {
663         TRACE_(seh)("%p caused page fault during write\n", ptr);
664         return TRUE;
665     }
666     __ENDTRY
667     return FALSE;
668 }
669
670
671 /***********************************************************************
672  *             IsBadHugeReadPtr   (KERNEL32.@)
673  *
674  * Check for read access on a memory block.
675  *
676  * PARAMS
677  *  ptr  [I] Address of memory block.
678  *  size [I] Size of block.
679  *
680  * RETURNS
681  *  Success: TRUE.
682  *      Failure: FALSE. Process has read access to entire block.
683  */
684 BOOL WINAPI IsBadHugeReadPtr( LPCVOID ptr, UINT size )
685 {
686     return IsBadReadPtr( ptr, size );
687 }
688
689
690 /***********************************************************************
691  *             IsBadHugeWritePtr   (KERNEL32.@)
692  *
693  * Check for write access on a memory block.
694  *
695  * PARAMS
696  *  ptr  [I] Address of memory block.
697  *  size [I] Size of block.
698  *
699  * RETURNS
700  *  Success: TRUE.
701  *      Failure: FALSE. Process has write access to entire block.
702  */
703 BOOL WINAPI IsBadHugeWritePtr( LPVOID ptr, UINT size )
704 {
705     return IsBadWritePtr( ptr, size );
706 }
707
708
709 /***********************************************************************
710  *             IsBadCodePtr   (KERNEL32.@)
711  *
712  * Check for read access on a memory address.
713  *
714  * PARAMS
715  *  ptr [I] Address of function.
716  *
717  * RETURNS
718  *      Success: TRUE.
719  *      Failure: FALSE. Process has read access to specified memory.
720  */
721 BOOL WINAPI IsBadCodePtr( FARPROC ptr )
722 {
723     return IsBadReadPtr( ptr, 1 );
724 }
725
726
727 /***********************************************************************
728  *             IsBadStringPtrA   (KERNEL32.@)
729  *
730  * Check for read access on a range of memory pointed to by a string pointer.
731  *
732  * PARAMS
733  *  str [I] Address of string.
734  *  max [I] Maximum size of string.
735  *
736  * RETURNS
737  *      Success: TRUE.
738  *      Failure: FALSE. Read access to all bytes in string.
739  */
740 BOOL WINAPI IsBadStringPtrA( LPCSTR str, UINT max )
741 {
742     if (!str) return TRUE;
743     
744     __TRY
745     {
746         volatile const char *p = str;
747         while (p != str + max) if (!*p++) break;
748     }
749     __EXCEPT_PAGE_FAULT
750     {
751         TRACE_(seh)("%p caused page fault during read\n", str);
752         return TRUE;
753     }
754     __ENDTRY
755     return FALSE;
756 }
757
758
759 /***********************************************************************
760  *             IsBadStringPtrW   (KERNEL32.@)
761  *
762  * See IsBadStringPtrA.
763  */
764 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT max )
765 {
766     if (!str) return TRUE;
767     
768     __TRY
769     {
770         volatile const WCHAR *p = str;
771         while (p != str + max) if (!*p++) break;
772     }
773     __EXCEPT_PAGE_FAULT
774     {
775         TRACE_(seh)("%p caused page fault during read\n", str);
776         return TRUE;
777     }
778     __ENDTRY
779     return FALSE;
780 }