1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Driver DLL
4 * FILE: win32ss/user/winsrv/consrv/condrv/graphics.c
5 * PURPOSE: Console Output Functions for graphics-mode screen-buffers
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7 *
8 * NOTE: See http://blog.airesoft.co.uk/2012/10/things-ms-can-do-that-they-dont-tell-you-about-console-graphics/
9 * for more information.
10 */
11
12 /* INCLUDES *******************************************************************/
13
14 #include <consrv.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* PRIVATE FUNCTIONS **********************************************************/
20
21 NTSTATUS
22 CONSOLE_SCREEN_BUFFER_Initialize(
23 OUT PCONSOLE_SCREEN_BUFFER* Buffer,
24 IN PCONSOLE Console,
25 IN CONSOLE_IO_OBJECT_TYPE Type,
26 IN SIZE_T Size);
27
28 VOID
29 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
30
31
32 NTSTATUS
GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER * Buffer,IN PCONSOLE Console,IN HANDLE ProcessHandle,IN PGRAPHICS_BUFFER_INFO GraphicsInfo)33 GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
34 IN PCONSOLE Console,
35 IN HANDLE ProcessHandle,
36 IN PGRAPHICS_BUFFER_INFO GraphicsInfo)
37 {
38 NTSTATUS Status = STATUS_SUCCESS;
39 PGRAPHICS_SCREEN_BUFFER NewBuffer = NULL;
40
41 LARGE_INTEGER SectionSize;
42 SIZE_T ViewSize = 0;
43
44 if (Buffer == NULL || Console == NULL || GraphicsInfo == NULL)
45 return STATUS_INVALID_PARAMETER;
46
47 *Buffer = NULL;
48
49 Status = CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER*)&NewBuffer,
50 Console,
51 GRAPHICS_BUFFER,
52 sizeof(GRAPHICS_SCREEN_BUFFER));
53 if (!NT_SUCCESS(Status)) return Status;
54
55 /*
56 * Remember the handle to the process so that we can close or unmap
57 * correctly the allocated resources when the client releases the
58 * screen buffer.
59 */
60 NewBuffer->ClientProcess = ProcessHandle;
61
62 /* Get information from the graphics buffer information structure */
63 NewBuffer->BitMapInfoLength = GraphicsInfo->Info.dwBitMapInfoLength;
64
65 NewBuffer->BitMapInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, NewBuffer->BitMapInfoLength);
66 if (NewBuffer->BitMapInfo == NULL)
67 {
68 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
69 return STATUS_INSUFFICIENT_RESOURCES;
70 }
71
72 /* Adjust the bitmap height if needed (bottom-top vs. top-bottom). Use always bottom-up. */
73 if (GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight > 0)
74 GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight = -GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight;
75
76 /* We do not use anything else than uncompressed bitmaps */
77 if (GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression != BI_RGB)
78 {
79 DPRINT1("biCompression == %d != BI_RGB, fix that!\n",
80 GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression);
81 GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biCompression = BI_RGB;
82 }
83
84 RtlCopyMemory(NewBuffer->BitMapInfo,
85 GraphicsInfo->Info.lpBitMapInfo,
86 GraphicsInfo->Info.dwBitMapInfoLength);
87
88 NewBuffer->BitMapUsage = GraphicsInfo->Info.dwUsage;
89
90 /* Set the screen buffer size. Fight against overflows. */
91 if ( GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biWidth <= 0xFFFF &&
92 -GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight <= 0xFFFF )
93 {
94 /* Be careful about the sign of biHeight */
95 NewBuffer->ScreenBufferSize.X = (SHORT)GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biWidth ;
96 NewBuffer->ScreenBufferSize.Y = (SHORT)-GraphicsInfo->Info.lpBitMapInfo->bmiHeader.biHeight;
97
98 NewBuffer->OldViewSize = NewBuffer->ViewSize =
99 NewBuffer->OldScreenBufferSize = NewBuffer->ScreenBufferSize;
100 }
101 else
102 {
103 Status = STATUS_INSUFFICIENT_RESOURCES;
104 ConsoleFreeHeap(NewBuffer->BitMapInfo);
105 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
106 goto Quit;
107 }
108
109 /*
110 * Create a mutex to synchronize bitmap memory access
111 * between ourselves and the client.
112 */
113 Status = NtCreateMutant(&NewBuffer->Mutex, MUTANT_ALL_ACCESS, NULL, FALSE);
114 if (!NT_SUCCESS(Status))
115 {
116 DPRINT1("NtCreateMutant() failed: %lu\n", Status);
117 ConsoleFreeHeap(NewBuffer->BitMapInfo);
118 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
119 goto Quit;
120 }
121
122 /*
123 * Duplicate the Mutex for the client. We must keep a trace of it
124 * so that we can close it when the client releases the screen buffer.
125 */
126 Status = NtDuplicateObject(NtCurrentProcess(),
127 NewBuffer->Mutex,
128 ProcessHandle,
129 &NewBuffer->ClientMutex,
130 0, 0, DUPLICATE_SAME_ACCESS);
131 if (!NT_SUCCESS(Status))
132 {
133 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
134 NtClose(NewBuffer->Mutex);
135 ConsoleFreeHeap(NewBuffer->BitMapInfo);
136 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
137 goto Quit;
138 }
139
140 /*
141 * Create a memory section for the bitmap area, to share with the client.
142 */
143 SectionSize.QuadPart = NewBuffer->BitMapInfo->bmiHeader.biSizeImage;
144 Status = NtCreateSection(&NewBuffer->hSection,
145 SECTION_ALL_ACCESS,
146 NULL,
147 &SectionSize,
148 PAGE_READWRITE,
149 SEC_COMMIT,
150 NULL);
151 if (!NT_SUCCESS(Status))
152 {
153 DPRINT1("Error: Impossible to create a shared section, Status = 0x%08lx\n", Status);
154 NtDuplicateObject(ProcessHandle, NewBuffer->ClientMutex,
155 NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
156 NtClose(NewBuffer->Mutex);
157 ConsoleFreeHeap(NewBuffer->BitMapInfo);
158 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
159 goto Quit;
160 }
161
162 /*
163 * Create a view for our needs.
164 */
165 ViewSize = 0;
166 NewBuffer->BitMap = NULL;
167 Status = NtMapViewOfSection(NewBuffer->hSection,
168 NtCurrentProcess(),
169 (PVOID*)&NewBuffer->BitMap,
170 0,
171 0,
172 NULL,
173 &ViewSize,
174 ViewUnmap,
175 0,
176 PAGE_READWRITE);
177 if (!NT_SUCCESS(Status))
178 {
179 DPRINT1("Error: Impossible to map the shared section, Status = 0x%08lx\n", Status);
180 NtClose(NewBuffer->hSection);
181 NtDuplicateObject(ProcessHandle, NewBuffer->ClientMutex,
182 NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
183 NtClose(NewBuffer->Mutex);
184 ConsoleFreeHeap(NewBuffer->BitMapInfo);
185 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
186 goto Quit;
187 }
188
189 /*
190 * Create a view for the client. We must keep a trace of it so that
191 * we can unmap it when the client releases the screen buffer.
192 */
193 ViewSize = 0;
194 NewBuffer->ClientBitMap = NULL;
195 Status = NtMapViewOfSection(NewBuffer->hSection,
196 ProcessHandle,
197 (PVOID*)&NewBuffer->ClientBitMap,
198 0,
199 0,
200 NULL,
201 &ViewSize,
202 ViewUnmap,
203 0,
204 PAGE_READWRITE);
205 if (!NT_SUCCESS(Status))
206 {
207 DPRINT1("Error: Impossible to map the shared section, Status = 0x%08lx\n", Status);
208 NtUnmapViewOfSection(NtCurrentProcess(), NewBuffer->BitMap);
209 NtClose(NewBuffer->hSection);
210 NtDuplicateObject(ProcessHandle, NewBuffer->ClientMutex,
211 NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
212 NtClose(NewBuffer->Mutex);
213 ConsoleFreeHeap(NewBuffer->BitMapInfo);
214 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
215 goto Quit;
216 }
217
218 NewBuffer->ViewOrigin.X = NewBuffer->ViewOrigin.Y = 0;
219
220 NewBuffer->CursorBlinkOn = FALSE;
221 NewBuffer->ForceCursorOff = TRUE;
222 NewBuffer->CursorInfo.bVisible = FALSE;
223 NewBuffer->CursorInfo.dwSize = 0;
224 NewBuffer->CursorPosition.X = NewBuffer->CursorPosition.Y = 0;
225
226 NewBuffer->Mode = 0;
227
228 *Buffer = (PCONSOLE_SCREEN_BUFFER)NewBuffer;
229 Status = STATUS_SUCCESS;
230
231 Quit:
232 return Status;
233 }
234
235 VOID
GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)236 GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
237 {
238 PGRAPHICS_SCREEN_BUFFER Buff = (PGRAPHICS_SCREEN_BUFFER)Buffer;
239
240 /*
241 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
242 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
243 */
244 Buffer->Header.Type = SCREEN_BUFFER;
245
246 /*
247 * Uninitialize the graphics screen buffer
248 * in the reverse way we initialized it.
249 */
250 NtUnmapViewOfSection(Buff->ClientProcess, Buff->ClientBitMap);
251 NtUnmapViewOfSection(NtCurrentProcess(), Buff->BitMap);
252 NtClose(Buff->hSection);
253 NtDuplicateObject(Buff->ClientProcess, Buff->ClientMutex,
254 NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
255 NtClose(Buff->Mutex);
256 ConsoleFreeHeap(Buff->BitMapInfo);
257
258 CONSOLE_SCREEN_BUFFER_Destroy(Buffer);
259 }
260
261 /* EOF */
262