Changed the CreateDC driver entry point to use an HDC instead of a DC
[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 #include "windef.h"
37 #include "winbase.h"
38 #include "winnls.h"
39 #include "winreg.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 WINE_DEFAULT_DEBUG_CHANNEL(virtual);
47
48 static unsigned int page_size;
49
50 /* filter for page-fault exceptions */
51 static WINE_EXCEPTION_FILTER(page_fault)
52 {
53     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
54         return EXCEPTION_EXECUTE_HANDLER;
55     return EXCEPTION_CONTINUE_SEARCH;
56 }
57
58
59 /***********************************************************************
60  *             VirtualAlloc   (KERNEL32.@)
61  * Reserves or commits a region of pages in virtual address space
62  *
63  * RETURNS
64  *      Base address of allocated region of pages
65  *      NULL: Failure
66  */
67 LPVOID WINAPI VirtualAlloc(
68               LPVOID addr,  /* [in] Address of region to reserve or commit */
69               SIZE_T size,  /* [in] Size of region */
70               DWORD type,   /* [in] Type of allocation */
71               DWORD protect)/* [in] Type of access protection */
72 {
73     return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect );
74 }
75
76
77 /***********************************************************************
78  *             VirtualAllocEx   (KERNEL32.@)
79  *
80  * Seems to be just as VirtualAlloc, but with process handle.
81  */
82 LPVOID WINAPI VirtualAllocEx(
83               HANDLE hProcess, /* [in] Handle of process to do mem operation */
84               LPVOID addr,     /* [in] Address of region to reserve or commit */
85               SIZE_T size,     /* [in] Size of region */
86               DWORD type,      /* [in] Type of allocation */
87               DWORD protect )  /* [in] Type of access protection */
88 {
89     LPVOID ret;
90     NTSTATUS status;
91
92     if ((status = NtAllocateVirtualMemory( hProcess, &ret, addr, &size, type, protect )))
93     {
94         SetLastError( RtlNtStatusToDosError(status) );
95         ret = NULL;
96     }
97     return ret;
98 }
99
100
101 /***********************************************************************
102  *             VirtualFree   (KERNEL32.@)
103  * Release or decommits a region of pages in virtual address space.
104  *
105  * RETURNS
106  *      TRUE: Success
107  *      FALSE: Failure
108  */
109 BOOL WINAPI VirtualFree(
110               LPVOID addr, /* [in] Address of region of committed pages */
111               SIZE_T size, /* [in] Size of region */
112               DWORD type   /* [in] Type of operation */
113 ) {
114     return VirtualFreeEx( GetCurrentProcess(), addr, size, type );
115 }
116
117
118 /***********************************************************************
119  *             VirtualFreeEx   (KERNEL32.@)
120  * Release or decommits a region of pages in virtual address space.
121  *
122  * RETURNS
123  *      TRUE: Success
124  *      FALSE: Failure
125  */
126 BOOL WINAPI VirtualFreeEx( HANDLE process, LPVOID addr, SIZE_T size, DWORD type )
127 {
128     NTSTATUS status = NtFreeVirtualMemory( process, &addr, &size, type );
129     if (status) SetLastError( RtlNtStatusToDosError(status) );
130     return !status;
131 }
132
133
134 /***********************************************************************
135  *             VirtualLock   (KERNEL32.@)
136  * Locks the specified region of virtual address space
137  *
138  * NOTE
139  *      Always returns TRUE
140  *
141  * RETURNS
142  *      TRUE: Success
143  *      FALSE: Failure
144  */
145 BOOL WINAPI VirtualLock( LPVOID addr, /* [in] Address of first byte of range to lock */
146                          SIZE_T size ) /* [in] Number of bytes in range to lock */
147 {
148     NTSTATUS status = NtLockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
149     if (status) SetLastError( RtlNtStatusToDosError(status) );
150     return !status;
151 }
152
153
154 /***********************************************************************
155  *             VirtualUnlock   (KERNEL32.@)
156  * Unlocks a range of pages in the virtual address space
157  *
158  * NOTE
159  *      Always returns TRUE
160  *
161  * RETURNS
162  *      TRUE: Success
163  *      FALSE: Failure
164  */
165 BOOL WINAPI VirtualUnlock( LPVOID addr, /* [in] Address of first byte of range */
166                            SIZE_T size ) /* [in] Number of bytes in range */
167 {
168     NTSTATUS status = NtUnlockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
169     if (status) SetLastError( RtlNtStatusToDosError(status) );
170     return !status;
171 }
172
173
174 /***********************************************************************
175  *             VirtualProtect   (KERNEL32.@)
176  * Changes the access protection on a region of committed pages
177  *
178  * RETURNS
179  *      TRUE: Success
180  *      FALSE: Failure
181  */
182 BOOL WINAPI VirtualProtect(
183               LPVOID addr,     /* [in] Address of region of committed pages */
184               SIZE_T size,     /* [in] Size of region */
185               DWORD new_prot,  /* [in] Desired access protection */
186               LPDWORD old_prot /* [out] Address of variable to get old protection */
187 ) {
188     return VirtualProtectEx( GetCurrentProcess(), addr, size, new_prot, old_prot );
189 }
190
191
192 /***********************************************************************
193  *             VirtualProtectEx   (KERNEL32.@)
194  * Changes the access protection on a region of committed pages in the
195  * virtual address space of a specified process
196  *
197  * RETURNS
198  *      TRUE: Success
199  *      FALSE: Failure
200  */
201 BOOL WINAPI VirtualProtectEx(
202               HANDLE process,  /* [in]  Handle of process */
203               LPVOID addr,     /* [in]  Address of region of committed pages */
204               SIZE_T size,     /* [in]  Size of region */
205               DWORD new_prot,  /* [in]  Desired access protection */
206               LPDWORD old_prot /* [out] Address of variable to get old protection */ )
207 {
208     NTSTATUS status = NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot );
209     if (status) SetLastError( RtlNtStatusToDosError(status) );
210     return !status;
211 }
212
213
214 /***********************************************************************
215  *             VirtualQuery   (KERNEL32.@)
216  * Provides info about a range of pages in virtual address space
217  *
218  * RETURNS
219  *      Number of bytes returned in information buffer
220  *      or 0 if addr is >= 0xc0000000 (kernel space).
221  */
222 SIZE_T WINAPI VirtualQuery(
223              LPCVOID addr,                    /* [in]  Address of region */
224              PMEMORY_BASIC_INFORMATION info,  /* [out] Address of info buffer */
225              SIZE_T len                       /* [in]  Size of buffer */
226 ) {
227     return VirtualQueryEx( GetCurrentProcess(), addr, info, len );
228 }
229
230
231 /***********************************************************************
232  *             VirtualQueryEx   (KERNEL32.@)
233  * Provides info about a range of pages in virtual address space of a
234  * specified process
235  *
236  * RETURNS
237  *      Number of bytes returned in information buffer
238  */
239 SIZE_T WINAPI VirtualQueryEx(
240              HANDLE process,                  /* [in] Handle of process */
241              LPCVOID addr,                    /* [in] Address of region */
242              PMEMORY_BASIC_INFORMATION info,  /* [out] Address of info buffer */
243              SIZE_T len                       /* [in] Size of buffer */ )
244 {
245     DWORD ret;
246     NTSTATUS status;
247
248     if ((status = NtQueryVirtualMemory( process, addr, MemoryBasicInformation, info, len, &ret )))
249     {
250         SetLastError( RtlNtStatusToDosError(status) );
251         ret = 0;
252     }
253     return ret;
254 }
255
256
257 /***********************************************************************
258  *             CreateFileMappingA   (KERNEL32.@)
259  * Creates a named or unnamed file-mapping object for the specified file
260  *
261  * RETURNS
262  *      Handle: Success
263  *      0: Mapping object does not exist
264  *      NULL: Failure
265  */
266 HANDLE WINAPI CreateFileMappingA(
267                 HANDLE hFile,   /* [in] Handle of file to map */
268                 SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/
269                 DWORD protect,   /* [in] Protection for mapping object */
270                 DWORD size_high, /* [in] High-order 32 bits of object size */
271                 DWORD size_low,  /* [in] Low-order 32 bits of object size */
272                 LPCSTR name      /* [in] Name of file-mapping object */ )
273 {
274     WCHAR buffer[MAX_PATH];
275
276     if (!name) return CreateFileMappingW( hFile, sa, protect, size_high, size_low, NULL );
277
278     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
279     {
280         SetLastError( ERROR_FILENAME_EXCED_RANGE );
281         return 0;
282     }
283     return CreateFileMappingW( hFile, sa, protect, size_high, size_low, buffer );
284 }
285
286
287 /***********************************************************************
288  *             CreateFileMappingW   (KERNEL32.@)
289  * See CreateFileMappingA
290  */
291 HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa,
292                                   DWORD protect, DWORD size_high,
293                                   DWORD size_low, LPCWSTR name )
294 {
295     static const int sec_flags = SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE;
296
297     HANDLE ret;
298     OBJECT_ATTRIBUTES attr;
299     UNICODE_STRING nameW;
300     NTSTATUS status;
301     DWORD access, sec_type;
302     LARGE_INTEGER size;
303
304     attr.Length                   = sizeof(attr);
305     attr.RootDirectory            = 0;
306     attr.ObjectName               = NULL;
307     attr.Attributes               = (sa && sa->bInheritHandle) ? OBJ_INHERIT : 0;
308     attr.SecurityDescriptor       = sa ? sa->lpSecurityDescriptor : NULL;
309     attr.SecurityQualityOfService = NULL;
310
311     if (name)
312     {
313         RtlInitUnicodeString( &nameW, name );
314         attr.ObjectName = &nameW;
315     }
316
317     sec_type = protect & sec_flags;
318     protect &= ~sec_flags;
319     if (!sec_type) sec_type = SEC_COMMIT;
320
321     switch(protect)
322     {
323     case 0:
324     case PAGE_READONLY:
325     case PAGE_WRITECOPY:
326         access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
327         break;
328     case PAGE_READWRITE:
329         access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE;
330         break;
331     default:
332         SetLastError( ERROR_INVALID_PARAMETER );
333         return 0;
334     }
335
336     if (hFile == INVALID_HANDLE_VALUE)
337     {
338         hFile = 0;
339         if (!size_low && !size_high)
340         {
341             SetLastError( ERROR_INVALID_PARAMETER );
342             return 0;
343         }
344     }
345
346     size.u.LowPart  = size_low;
347     size.u.HighPart = size_high;
348
349     status = NtCreateSection( &ret, access, &attr, &size, protect, sec_type, hFile );
350     SetLastError( RtlNtStatusToDosError(status) );
351     return ret;
352 }
353
354
355 /***********************************************************************
356  *             OpenFileMappingA   (KERNEL32.@)
357  * Opens a named file-mapping object.
358  *
359  * RETURNS
360  *      Handle: Success
361  *      NULL: Failure
362  */
363 HANDLE WINAPI OpenFileMappingA(
364                 DWORD access,   /* [in] Access mode */
365                 BOOL inherit, /* [in] Inherit flag */
366                 LPCSTR name )   /* [in] Name of file-mapping object */
367 {
368     WCHAR buffer[MAX_PATH];
369
370     if (!name) return OpenFileMappingW( access, inherit, NULL );
371
372     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
373     {
374         SetLastError( ERROR_FILENAME_EXCED_RANGE );
375         return 0;
376     }
377     return OpenFileMappingW( access, inherit, buffer );
378 }
379
380
381 /***********************************************************************
382  *             OpenFileMappingW   (KERNEL32.@)
383  * See OpenFileMappingA
384  */
385 HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
386 {
387     OBJECT_ATTRIBUTES attr;
388     UNICODE_STRING nameW;
389     HANDLE ret;
390     NTSTATUS status;
391
392     if (!name)
393     {
394         SetLastError( ERROR_INVALID_PARAMETER );
395         return 0;
396     }
397     attr.Length = sizeof(attr);
398     attr.RootDirectory = 0;
399     attr.ObjectName = &nameW;
400     attr.Attributes = inherit ? OBJ_INHERIT : 0;
401     attr.SecurityDescriptor = NULL;
402     attr.SecurityQualityOfService = NULL;
403     RtlInitUnicodeString( &nameW, name );
404
405     if (access == FILE_MAP_COPY) access = FILE_MAP_READ;
406
407     if ((status = NtOpenSection( &ret, access, &attr )))
408     {
409         SetLastError( RtlNtStatusToDosError(status) );
410         ret = 0;
411     }
412     return ret;
413 }
414
415
416 /***********************************************************************
417  *             MapViewOfFile   (KERNEL32.@)
418  * Maps a view of a file into the address space
419  *
420  * RETURNS
421  *      Starting address of mapped view
422  *      NULL: Failure
423  */
424 LPVOID WINAPI MapViewOfFile(
425               HANDLE mapping,  /* [in] File-mapping object to map */
426               DWORD access,      /* [in] Access mode */
427               DWORD offset_high, /* [in] High-order 32 bits of file offset */
428               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
429               SIZE_T count       /* [in] Number of bytes to map */
430 ) {
431     return MapViewOfFileEx( mapping, access, offset_high,
432                             offset_low, count, NULL );
433 }
434
435
436 /***********************************************************************
437  *             MapViewOfFileEx   (KERNEL32.@)
438  * Maps a view of a file into the address space
439  *
440  * RETURNS
441  *      Starting address of mapped view
442  *      NULL: Failure
443  */
444 LPVOID WINAPI MapViewOfFileEx(
445               HANDLE handle,   /* [in] File-mapping object to map */
446               DWORD access,      /* [in] Access mode */
447               DWORD offset_high, /* [in] High-order 32 bits of file offset */
448               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
449               SIZE_T count,      /* [in] Number of bytes to map */
450               LPVOID addr        /* [in] Suggested starting address for mapped view */
451 ) {
452     NTSTATUS status;
453     LARGE_INTEGER offset;
454     ULONG protect;
455
456     offset.u.LowPart  = offset_low;
457     offset.u.HighPart = offset_high;
458
459     if (access & FILE_MAP_WRITE) protect = PAGE_READWRITE;
460     else if (access & FILE_MAP_READ) protect = PAGE_READONLY;
461     else if (access & FILE_MAP_COPY) protect = PAGE_WRITECOPY;
462     else protect = PAGE_NOACCESS;
463
464     if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, &offset,
465                                       &count, ViewShare, 0, protect )))
466     {
467         SetLastError( RtlNtStatusToDosError(status) );
468         addr = NULL;
469     }
470     return addr;
471 }
472
473
474 /***********************************************************************
475  *             UnmapViewOfFile   (KERNEL32.@)
476  * Unmaps a mapped view of a file.
477  *
478  * NOTES
479  *      Should addr be an LPCVOID?
480  *
481  * RETURNS
482  *      TRUE: Success
483  *      FALSE: Failure
484  */
485 BOOL WINAPI UnmapViewOfFile( LPVOID addr ) /* [in] Address where mapped view begins */
486 {
487     NTSTATUS status = NtUnmapViewOfSection( GetCurrentProcess(), addr );
488     if (status) SetLastError( RtlNtStatusToDosError(status) );
489     return !status;
490 }
491
492
493 /***********************************************************************
494  *             FlushViewOfFile   (KERNEL32.@)
495  * Writes to the disk a byte range within a mapped view of a file
496  *
497  * RETURNS
498  *      TRUE: Success
499  *      FALSE: Failure
500  */
501 BOOL WINAPI FlushViewOfFile( LPCVOID base,  /* [in] Start address of byte range to flush */
502                              SIZE_T size )   /* [in] Number of bytes in range */
503 {
504     NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 );
505     if (status)
506     {
507         if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS;
508         else SetLastError( RtlNtStatusToDosError(status) );
509     }
510     return !status;
511 }
512
513
514 /***********************************************************************
515  *             IsBadReadPtr   (KERNEL32.@)
516  *
517  * RETURNS
518  *      FALSE: Process has read access to entire block
519  *      TRUE: Otherwise
520  */
521 BOOL WINAPI IsBadReadPtr(
522               LPCVOID ptr, /* [in] Address of memory block */
523               UINT size )  /* [in] Size of block */
524 {
525     if (!size) return FALSE;  /* handle 0 size case w/o reference */
526     if (!page_size) page_size = getpagesize();
527     __TRY
528     {
529         volatile const char *p = ptr;
530         char dummy;
531         UINT count = size;
532
533         while (count > page_size)
534         {
535             dummy = *p;
536             p += page_size;
537             count -= page_size;
538         }
539         dummy = p[0];
540         dummy = p[count - 1];
541     }
542     __EXCEPT(page_fault) { return TRUE; }
543     __ENDTRY
544     return FALSE;
545 }
546
547
548 /***********************************************************************
549  *             IsBadWritePtr   (KERNEL32.@)
550  *
551  * RETURNS
552  *      FALSE: Process has write access to entire block
553  *      TRUE: Otherwise
554  */
555 BOOL WINAPI IsBadWritePtr(
556               LPVOID ptr, /* [in] Address of memory block */
557               UINT size ) /* [in] Size of block in bytes */
558 {
559     if (!size) return FALSE;  /* handle 0 size case w/o reference */
560     if (!page_size) page_size = getpagesize();
561     __TRY
562     {
563         volatile char *p = ptr;
564         UINT count = size;
565
566         while (count > page_size)
567         {
568             *p |= 0;
569             p += page_size;
570             count -= page_size;
571         }
572         p[0] |= 0;
573         p[count - 1] |= 0;
574     }
575     __EXCEPT(page_fault) { return TRUE; }
576     __ENDTRY
577     return FALSE;
578 }
579
580
581 /***********************************************************************
582  *             IsBadHugeReadPtr   (KERNEL32.@)
583  * RETURNS
584  *      FALSE: Process has read access to entire block
585  *      TRUE: Otherwise
586  */
587 BOOL WINAPI IsBadHugeReadPtr(
588               LPCVOID ptr, /* [in] Address of memory block */
589               UINT size  /* [in] Size of block */
590 ) {
591     return IsBadReadPtr( ptr, size );
592 }
593
594
595 /***********************************************************************
596  *             IsBadHugeWritePtr   (KERNEL32.@)
597  * RETURNS
598  *      FALSE: Process has write access to entire block
599  *      TRUE: Otherwise
600  */
601 BOOL WINAPI IsBadHugeWritePtr(
602               LPVOID ptr, /* [in] Address of memory block */
603               UINT size /* [in] Size of block */
604 ) {
605     return IsBadWritePtr( ptr, size );
606 }
607
608
609 /***********************************************************************
610  *             IsBadCodePtr   (KERNEL32.@)
611  *
612  * RETURNS
613  *      FALSE: Process has read access to specified memory
614  *      TRUE: Otherwise
615  */
616 BOOL WINAPI IsBadCodePtr( FARPROC ptr ) /* [in] Address of function */
617 {
618     return IsBadReadPtr( ptr, 1 );
619 }
620
621
622 /***********************************************************************
623  *             IsBadStringPtrA   (KERNEL32.@)
624  *
625  * RETURNS
626  *      FALSE: Read access to all bytes in string
627  *      TRUE: Else
628  */
629 BOOL WINAPI IsBadStringPtrA(
630               LPCSTR str, /* [in] Address of string */
631               UINT max )  /* [in] Maximum size of string */
632 {
633     __TRY
634     {
635         volatile const char *p = str;
636         while (p != str + max) if (!*p++) break;
637     }
638     __EXCEPT(page_fault) { return TRUE; }
639     __ENDTRY
640     return FALSE;
641 }
642
643
644 /***********************************************************************
645  *             IsBadStringPtrW   (KERNEL32.@)
646  * See IsBadStringPtrA
647  */
648 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT max )
649 {
650     __TRY
651     {
652         volatile const WCHAR *p = str;
653         while (p != str + max) if (!*p++) break;
654     }
655     __EXCEPT(page_fault) { return TRUE; }
656     __ENDTRY
657     return FALSE;
658 }