[USER32] Add support for navigating a group of radio buttons using a keyboard.
[reactos.git] / win32ss / user / ntuser / usrheap.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <win32k.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 HANDLE GlobalUserHeap = NULL;
26 PVOID GlobalUserHeapSection = NULL;
27
28
29 _Function_class_(RTL_HEAP_COMMIT_ROUTINE)
30 _IRQL_requires_same_
31 static
32 NTSTATUS
33 NTAPI
34 IntUserHeapCommitRoutine(
35 _In_ PVOID Base,
36 _Inout_ PVOID *CommitAddress,
37 _Inout_ PSIZE_T CommitSize)
38 {
39 PPROCESSINFO W32Process;
40 PW32HEAP_USER_MAPPING Mapping;
41 PVOID UserBase = NULL;
42 NTSTATUS Status;
43 SIZE_T Delta;
44 PVOID UserCommitAddress;
45
46 W32Process = PsGetCurrentProcessWin32Process();
47
48 if (W32Process != NULL)
49 {
50 /* Search for the mapping */
51 Mapping = &W32Process->HeapMappings;
52 while (Mapping != NULL)
53 {
54 if (Mapping->KernelMapping == Base)
55 {
56 UserBase = Mapping->UserMapping;
57 break;
58 }
59
60 Mapping = Mapping->Next;
61 }
62
63 ASSERT(UserBase != NULL);
64 }
65 else
66 {
67 SIZE_T ViewSize = 0;
68 LARGE_INTEGER Offset;
69
70 /* HACK: This needs to be handled during startup only... */
71 ASSERT(Base == (PVOID)GlobalUserHeap);
72
73 /* Temporarily map it into user space */
74 Offset.QuadPart = 0;
75 Status = MmMapViewOfSection(GlobalUserHeapSection,
76 PsGetCurrentProcess(),
77 &UserBase,
78 0,
79 0,
80 &Offset,
81 &ViewSize,
82 ViewUnmap,
83 SEC_NO_CHANGE,
84 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
85
86 if (!NT_SUCCESS(Status))
87 return Status;
88 }
89
90 /* Apply the commit address offset to the user base address */
91 Delta = (SIZE_T)((ULONG_PTR)(*CommitAddress) - (ULONG_PTR)Base);
92 UserCommitAddress = (PVOID)((ULONG_PTR)UserBase + Delta);
93
94 /* Perform the actual commit */
95 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
96 &UserCommitAddress,
97 0,
98 CommitSize,
99 MEM_COMMIT,
100 PAGE_EXECUTE_READ);
101
102 if (NT_SUCCESS(Status))
103 {
104 /* Determine the address to return */
105 Delta = (SIZE_T)((ULONG_PTR)UserCommitAddress - (ULONG_PTR)UserBase);
106 *CommitAddress = (PVOID)((ULONG_PTR)Base + Delta);
107 }
108
109 if (W32Process == NULL)
110 {
111 MmUnmapViewOfSection(PsGetCurrentProcess(),
112 UserBase);
113 }
114
115 return Status;
116 }
117
118 static PWIN32HEAP
119 IntUserHeapCreate(IN PVOID SectionObject,
120 IN PVOID *SystemMappedBase,
121 IN ULONG HeapSize)
122 {
123 PVOID MappedView = NULL;
124 LARGE_INTEGER Offset;
125 SIZE_T ViewSize = PAGE_SIZE;
126 RTL_HEAP_PARAMETERS Parameters = {0};
127 PVOID pHeap;
128 NTSTATUS Status;
129
130 Offset.QuadPart = 0;
131
132 /* Commit the first page before creating the heap! */
133 Status = MmMapViewOfSection(SectionObject,
134 PsGetCurrentProcess(),
135 &MappedView,
136 0,
137 0,
138 &Offset,
139 &ViewSize,
140 ViewUnmap,
141 SEC_NO_CHANGE,
142 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
143 if (!NT_SUCCESS(Status))
144 return NULL;
145
146 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
147 &MappedView,
148 0,
149 &ViewSize,
150 MEM_COMMIT,
151 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
152
153 MmUnmapViewOfSection(PsGetCurrentProcess(),
154 MappedView);
155
156 if (!NT_SUCCESS(Status))
157 return NULL;
158
159 /* Create the heap, don't serialize in kmode! The caller is responsible
160 to synchronize the heap! */
161 Parameters.Length = sizeof(Parameters);
162 Parameters.InitialCommit = ViewSize;
163 Parameters.InitialReserve = (SIZE_T)HeapSize;
164 Parameters.CommitRoutine = IntUserHeapCommitRoutine;
165
166 pHeap = RtlCreateHeap(HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE,
167 *SystemMappedBase,
168 (SIZE_T)HeapSize,
169 ViewSize,
170 NULL,
171 &Parameters);
172
173 return pHeap;
174 }
175
176 PWIN32HEAP
177 UserCreateHeap(OUT PVOID *SectionObject,
178 IN OUT PVOID *SystemBase,
179 IN SIZE_T HeapSize)
180 {
181 LARGE_INTEGER SizeHeap;
182 PWIN32HEAP pHeap = NULL;
183 NTSTATUS Status;
184
185 SizeHeap.QuadPart = HeapSize;
186
187 /* Create the section and map it into session space */
188 Status = MmCreateSection((PVOID*)SectionObject,
189 SECTION_ALL_ACCESS,
190 NULL,
191 &SizeHeap,
192 PAGE_EXECUTE_READWRITE, /* Would prefer PAGE_READWRITE, but thanks to RTL heaps... */
193 SEC_RESERVE | 1,
194 NULL,
195 NULL);
196
197 if (!NT_SUCCESS(Status))
198 {
199 SetLastNtError(Status);
200 return FALSE;
201 }
202
203 Status = MmMapViewInSessionSpace(*SectionObject,
204 SystemBase,
205 &HeapSize);
206 if (!NT_SUCCESS(Status))
207 {
208 ObDereferenceObject(*SectionObject);
209 *SectionObject = NULL;
210
211 SetLastNtError(Status);
212 return FALSE;
213 }
214
215 /* Create the heap */
216 pHeap = IntUserHeapCreate(*SectionObject,
217 SystemBase,
218 HeapSize);
219
220 if (pHeap == NULL)
221 {
222 ObDereferenceObject(*SectionObject);
223 *SectionObject = NULL;
224
225 SetLastNtError(STATUS_UNSUCCESSFUL);
226 }
227
228 return pHeap;
229 }
230
231 NTSTATUS
232 UnmapGlobalUserHeap(IN PEPROCESS Process)
233 {
234 NTSTATUS Status = STATUS_SUCCESS;
235 PPROCESSINFO W32Process;
236 PW32HEAP_USER_MAPPING HeapMapping;
237
238 TRACE_CH(UserProcess, "IntUnmapDesktopView called for process 0x%p\n", Process);
239
240 W32Process = PsGetProcessWin32Process(Process);
241 if (W32Process == NULL)
242 {
243 ERR_CH(UserProcess, "UnmapGlobalUserHeap - We don't have a Win32 process!\n");
244 ASSERT(FALSE);
245 }
246
247 /* The first mapping entry must be the global user heap */
248 HeapMapping = &W32Process->HeapMappings;
249 ASSERT(HeapMapping->KernelMapping == (PVOID)GlobalUserHeap);
250
251 /* Unmap if we're the last thread using the global user heap */
252 if (--HeapMapping->Count == 0)
253 {
254 TRACE_CH(UserProcess, "UnmapGlobalUserHeap - Unmapping\n");
255 Status = MmUnmapViewOfSection(Process, HeapMapping->UserMapping);
256 }
257
258 return Status;
259 }
260
261 NTSTATUS
262 MapGlobalUserHeap(IN PEPROCESS Process,
263 OUT PVOID* KernelMapping,
264 OUT PVOID* UserMapping)
265 {
266 NTSTATUS Status;
267 PPROCESSINFO W32Process;
268 PW32HEAP_USER_MAPPING HeapMapping;
269 PVOID UserBase = NULL;
270
271 SIZE_T ViewSize = 0;
272 LARGE_INTEGER Offset;
273
274 TRACE_CH(UserProcess, "MapGlobalUserHeap called for process 0x%p\n", Process);
275
276 W32Process = PsGetProcessWin32Process(Process);
277 if (W32Process == NULL)
278 {
279 ERR_CH(UserProcess, "MapGlobalUserHeap - We don't have a Win32 process!\n");
280 ASSERT(FALSE);
281 }
282
283 TRACE_CH(UserProcess, "MapGlobalUserHeap - We got a Win32 process, find for existing global user heap mapping...\n");
284
285 /* The first mapping entry must be the global user heap */
286 HeapMapping = &W32Process->HeapMappings;
287
288 /* Find out if another thread already mapped the global user heap */
289 if (HeapMapping->KernelMapping == (PVOID)GlobalUserHeap)
290 {
291 HeapMapping->Count++;
292
293 TRACE_CH(UserProcess, "MapGlobalUserHeap - A mapping was found, return it.\n");
294
295 *KernelMapping = HeapMapping->KernelMapping;
296 *UserMapping = HeapMapping->UserMapping;
297
298 return STATUS_SUCCESS;
299 }
300
301 TRACE_CH(UserProcess, "MapGlobalUserHeap - No mapping was found, let's map...\n");
302
303 /* We're the first, map the global heap into the process */
304 Offset.QuadPart = 0;
305 Status = MmMapViewOfSection(GlobalUserHeapSection,
306 Process,
307 &UserBase,
308 0,
309 0,
310 &Offset,
311 &ViewSize,
312 ViewUnmap,
313 SEC_NO_CHANGE,
314 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
315 if (!NT_SUCCESS(Status))
316 {
317 ERR_CH(UserProcess, "MapGlobalUserHeap - Failed to map the global heap! 0x%x\n", Status);
318 return Status;
319 }
320
321 TRACE_CH(UserProcess, "MapGlobalUserHeap -- Mapped kernel global heap 0x%p to user space at 0x%p\n",
322 GlobalUserHeap, UserBase);
323
324 /* Add the mapping */
325 HeapMapping->Next = NULL;
326 HeapMapping->KernelMapping = (PVOID)GlobalUserHeap;
327 HeapMapping->UserMapping = UserBase;
328 HeapMapping->Limit = ViewSize;
329 HeapMapping->Count = 1;
330
331 *KernelMapping = HeapMapping->KernelMapping;
332 *UserMapping = HeapMapping->UserMapping;
333
334 return STATUS_SUCCESS;
335 }
336
337 /* EOF */