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)
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.
12 /* INCLUDES *******************************************************************/
15 #include "include/conio.h"
16 #include "include/conio2.h"
17 #include "conoutput.h"
24 /* PRIVATE FUNCTIONS **********************************************************/
26 CONSOLE_IO_OBJECT_TYPE
27 GRAPHICS_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This
)
29 // return This->Header.Type;
30 return GRAPHICS_BUFFER
;
33 static CONSOLE_SCREEN_BUFFER_VTBL GraphicsVtbl
=
35 GRAPHICS_BUFFER_GetType
,
40 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
41 IN OUT PCONSOLE Console
,
44 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
);
48 GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
49 IN OUT PCONSOLE Console
,
50 IN PGRAPHICS_BUFFER_INFO GraphicsInfo
)
52 NTSTATUS Status
= STATUS_SUCCESS
;
53 PGRAPHICS_SCREEN_BUFFER NewBuffer
= NULL
;
55 LARGE_INTEGER SectionSize
;
59 if (Buffer
== NULL
|| Console
== NULL
|| GraphicsInfo
== NULL
)
60 return STATUS_INVALID_PARAMETER
;
64 Status
= CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER
*)&NewBuffer
,
66 sizeof(GRAPHICS_SCREEN_BUFFER
));
67 if (!NT_SUCCESS(Status
)) return Status
;
68 NewBuffer
->Header
.Type
= GRAPHICS_BUFFER
;
69 NewBuffer
->Vtbl
= &GraphicsVtbl
;
72 * Remember the handle to the process so that we can close or unmap
73 * correctly the allocated resources when the client releases the
76 ProcessHandle
= CsrGetClientThread()->Process
->ProcessHandle
;
77 NewBuffer
->ClientProcess
= ProcessHandle
;
79 /* Get infos from the graphics buffer information structure */
80 NewBuffer
->BitMapInfoLength
= GraphicsInfo
->Info
.dwBitMapInfoLength
;
82 NewBuffer
->BitMapInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, NewBuffer
->BitMapInfoLength
);
83 if (NewBuffer
->BitMapInfo
== NULL
)
85 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
86 return STATUS_INSUFFICIENT_RESOURCES
;
89 /* Adjust the bitmap height if needed (bottom-top vs. top-bottom). Use always bottom-up. */
90 if (GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
> 0)
91 GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
= -GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
;
93 /* We do not use anything else than uncompressed bitmaps */
94 if (GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biCompression
!= BI_RGB
)
96 DPRINT1("biCompression == %d != BI_RGB, correct that!\n", GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biCompression
);
97 GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biCompression
= BI_RGB
;
100 RtlCopyMemory(NewBuffer
->BitMapInfo
,
101 GraphicsInfo
->Info
.lpBitMapInfo
,
102 GraphicsInfo
->Info
.dwBitMapInfoLength
);
104 NewBuffer
->BitMapUsage
= GraphicsInfo
->Info
.dwUsage
;
106 /* Set the screen buffer size. Fight against overflows. */
107 if ( GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biWidth
<= 0xFFFF &&
108 -GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
<= 0xFFFF )
110 /* Be careful about the sign of biHeight */
111 NewBuffer
->ScreenBufferSize
.X
= (SHORT
)GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biWidth
;
112 NewBuffer
->ScreenBufferSize
.Y
= (SHORT
)-GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
;
114 NewBuffer
->OldViewSize
= NewBuffer
->ViewSize
=
115 NewBuffer
->OldScreenBufferSize
= NewBuffer
->ScreenBufferSize
;
119 Status
= STATUS_INSUFFICIENT_RESOURCES
;
120 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
121 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
126 * Create a mutex to synchronize bitmap memory access
127 * between ourselves and the client.
129 Status
= NtCreateMutant(&NewBuffer
->Mutex
, MUTANT_ALL_ACCESS
, NULL
, FALSE
);
130 if (!NT_SUCCESS(Status
))
132 DPRINT1("NtCreateMutant() failed: %lu\n", Status
);
133 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
134 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
139 * Duplicate the Mutex for the client. We must keep a trace of it
140 * so that we can close it when the client releases the screen buffer.
142 Status
= NtDuplicateObject(NtCurrentProcess(),
145 &NewBuffer
->ClientMutex
,
146 0, 0, DUPLICATE_SAME_ACCESS
);
147 if (!NT_SUCCESS(Status
))
149 DPRINT1("NtDuplicateObject() failed: %lu\n", Status
);
150 NtClose(NewBuffer
->Mutex
);
151 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
152 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
157 * Create a memory section for the bitmap area, to share with the client.
159 SectionSize
.QuadPart
= NewBuffer
->BitMapInfo
->bmiHeader
.biSizeImage
;
160 Status
= NtCreateSection(&NewBuffer
->hSection
,
167 if (!NT_SUCCESS(Status
))
169 DPRINT1("Error: Impossible to create a shared section ; Status = %lu\n", Status
);
170 NtClose(NewBuffer
->ClientMutex
);
171 NtClose(NewBuffer
->Mutex
);
172 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
173 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
178 * Create a view for our needs.
181 NewBuffer
->BitMap
= NULL
;
182 Status
= NtMapViewOfSection(NewBuffer
->hSection
,
184 (PVOID
*)&NewBuffer
->BitMap
,
192 if (!NT_SUCCESS(Status
))
194 DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status
);
195 NtClose(NewBuffer
->hSection
);
196 NtClose(NewBuffer
->ClientMutex
);
197 NtClose(NewBuffer
->Mutex
);
198 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
199 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
204 * Create a view for the client. We must keep a trace of it so that
205 * we can unmap it when the client releases the screen buffer.
208 NewBuffer
->ClientBitMap
= NULL
;
209 Status
= NtMapViewOfSection(NewBuffer
->hSection
,
211 (PVOID
*)&NewBuffer
->ClientBitMap
,
219 if (!NT_SUCCESS(Status
))
221 DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status
);
222 NtUnmapViewOfSection(NtCurrentProcess(), NewBuffer
->BitMap
);
223 NtClose(NewBuffer
->hSection
);
224 NtClose(NewBuffer
->ClientMutex
);
225 NtClose(NewBuffer
->Mutex
);
226 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
227 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
231 NewBuffer
->ViewOrigin
.X
= NewBuffer
->ViewOrigin
.Y
= 0;
232 NewBuffer
->VirtualY
= 0;
234 NewBuffer
->CursorBlinkOn
= FALSE
;
235 NewBuffer
->ForceCursorOff
= TRUE
;
236 NewBuffer
->CursorInfo
.bVisible
= FALSE
;
237 NewBuffer
->CursorInfo
.dwSize
= 0;
238 NewBuffer
->CursorPosition
.X
= NewBuffer
->CursorPosition
.Y
= 0;
242 *Buffer
= (PCONSOLE_SCREEN_BUFFER
)NewBuffer
;
243 Status
= STATUS_SUCCESS
;
250 GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
)
252 PGRAPHICS_SCREEN_BUFFER Buff
= (PGRAPHICS_SCREEN_BUFFER
)Buffer
;
255 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
256 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
258 Buffer
->Header
.Type
= SCREEN_BUFFER
;
261 * Uninitialize the graphics screen buffer
262 * in the reverse way we initialized it.
264 NtUnmapViewOfSection(Buff
->ClientProcess
, Buff
->ClientBitMap
);
265 NtUnmapViewOfSection(NtCurrentProcess(), Buff
->BitMap
);
266 NtClose(Buff
->hSection
);
267 NtClose(Buff
->ClientMutex
);
268 NtClose(Buff
->Mutex
);
269 ConsoleFreeHeap(Buff
->BitMapInfo
);
271 CONSOLE_SCREEN_BUFFER_Destroy(Buffer
);