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 *******************************************************************/
19 /* PRIVATE FUNCTIONS **********************************************************/
21 CONSOLE_IO_OBJECT_TYPE
22 GRAPHICS_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This
)
24 // return This->Header.Type;
25 return GRAPHICS_BUFFER
;
28 static CONSOLE_SCREEN_BUFFER_VTBL GraphicsVtbl
=
30 GRAPHICS_BUFFER_GetType
,
35 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
36 IN OUT PCONSOLE Console
,
37 IN PCONSOLE_SCREEN_BUFFER_VTBL Vtbl
,
40 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
);
44 GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
45 IN OUT PCONSOLE Console
,
46 IN PGRAPHICS_BUFFER_INFO GraphicsInfo
)
48 NTSTATUS Status
= STATUS_SUCCESS
;
49 PGRAPHICS_SCREEN_BUFFER NewBuffer
= NULL
;
51 LARGE_INTEGER SectionSize
;
55 if (Buffer
== NULL
|| Console
== NULL
|| GraphicsInfo
== NULL
)
56 return STATUS_INVALID_PARAMETER
;
60 Status
= CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER
*)&NewBuffer
,
63 sizeof(GRAPHICS_SCREEN_BUFFER
));
64 if (!NT_SUCCESS(Status
)) return Status
;
65 NewBuffer
->Header
.Type
= GRAPHICS_BUFFER
;
68 * Remember the handle to the process so that we can close or unmap
69 * correctly the allocated resources when the client releases the
72 ProcessHandle
= CsrGetClientThread()->Process
->ProcessHandle
;
73 NewBuffer
->ClientProcess
= ProcessHandle
;
75 /* Get infos from the graphics buffer information structure */
76 NewBuffer
->BitMapInfoLength
= GraphicsInfo
->Info
.dwBitMapInfoLength
;
78 NewBuffer
->BitMapInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, NewBuffer
->BitMapInfoLength
);
79 if (NewBuffer
->BitMapInfo
== NULL
)
81 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
82 return STATUS_INSUFFICIENT_RESOURCES
;
85 /* Adjust the bitmap height if needed (bottom-top vs. top-bottom). Use always bottom-up. */
86 if (GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
> 0)
87 GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
= -GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
;
89 /* We do not use anything else than uncompressed bitmaps */
90 if (GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biCompression
!= BI_RGB
)
92 DPRINT1("biCompression == %d != BI_RGB, fix that!\n",
93 GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biCompression
);
94 GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biCompression
= BI_RGB
;
97 RtlCopyMemory(NewBuffer
->BitMapInfo
,
98 GraphicsInfo
->Info
.lpBitMapInfo
,
99 GraphicsInfo
->Info
.dwBitMapInfoLength
);
101 NewBuffer
->BitMapUsage
= GraphicsInfo
->Info
.dwUsage
;
103 /* Set the screen buffer size. Fight against overflows. */
104 if ( GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biWidth
<= 0xFFFF &&
105 -GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
<= 0xFFFF )
107 /* Be careful about the sign of biHeight */
108 NewBuffer
->ScreenBufferSize
.X
= (SHORT
)GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biWidth
;
109 NewBuffer
->ScreenBufferSize
.Y
= (SHORT
)-GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
;
111 NewBuffer
->OldViewSize
= NewBuffer
->ViewSize
=
112 NewBuffer
->OldScreenBufferSize
= NewBuffer
->ScreenBufferSize
;
116 Status
= STATUS_INSUFFICIENT_RESOURCES
;
117 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
118 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
123 * Create a mutex to synchronize bitmap memory access
124 * between ourselves and the client.
126 Status
= NtCreateMutant(&NewBuffer
->Mutex
, MUTANT_ALL_ACCESS
, NULL
, FALSE
);
127 if (!NT_SUCCESS(Status
))
129 DPRINT1("NtCreateMutant() failed: %lu\n", Status
);
130 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
131 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
136 * Duplicate the Mutex for the client. We must keep a trace of it
137 * so that we can close it when the client releases the screen buffer.
139 Status
= NtDuplicateObject(NtCurrentProcess(),
142 &NewBuffer
->ClientMutex
,
143 0, 0, DUPLICATE_SAME_ACCESS
);
144 if (!NT_SUCCESS(Status
))
146 DPRINT1("NtDuplicateObject() failed: %lu\n", Status
);
147 NtClose(NewBuffer
->Mutex
);
148 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
149 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
154 * Create a memory section for the bitmap area, to share with the client.
156 SectionSize
.QuadPart
= NewBuffer
->BitMapInfo
->bmiHeader
.biSizeImage
;
157 Status
= NtCreateSection(&NewBuffer
->hSection
,
164 if (!NT_SUCCESS(Status
))
166 DPRINT1("Error: Impossible to create a shared section ; Status = %lu\n", Status
);
167 NtClose(NewBuffer
->ClientMutex
);
168 NtClose(NewBuffer
->Mutex
);
169 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
170 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
175 * Create a view for our needs.
178 NewBuffer
->BitMap
= NULL
;
179 Status
= NtMapViewOfSection(NewBuffer
->hSection
,
181 (PVOID
*)&NewBuffer
->BitMap
,
189 if (!NT_SUCCESS(Status
))
191 DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status
);
192 NtClose(NewBuffer
->hSection
);
193 NtClose(NewBuffer
->ClientMutex
);
194 NtClose(NewBuffer
->Mutex
);
195 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
196 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
201 * Create a view for the client. We must keep a trace of it so that
202 * we can unmap it when the client releases the screen buffer.
205 NewBuffer
->ClientBitMap
= NULL
;
206 Status
= NtMapViewOfSection(NewBuffer
->hSection
,
208 (PVOID
*)&NewBuffer
->ClientBitMap
,
216 if (!NT_SUCCESS(Status
))
218 DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status
);
219 NtUnmapViewOfSection(NtCurrentProcess(), NewBuffer
->BitMap
);
220 NtClose(NewBuffer
->hSection
);
221 NtClose(NewBuffer
->ClientMutex
);
222 NtClose(NewBuffer
->Mutex
);
223 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
224 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
228 NewBuffer
->ViewOrigin
.X
= NewBuffer
->ViewOrigin
.Y
= 0;
229 NewBuffer
->VirtualY
= 0;
231 NewBuffer
->CursorBlinkOn
= FALSE
;
232 NewBuffer
->ForceCursorOff
= TRUE
;
233 NewBuffer
->CursorInfo
.bVisible
= FALSE
;
234 NewBuffer
->CursorInfo
.dwSize
= 0;
235 NewBuffer
->CursorPosition
.X
= NewBuffer
->CursorPosition
.Y
= 0;
239 *Buffer
= (PCONSOLE_SCREEN_BUFFER
)NewBuffer
;
240 Status
= STATUS_SUCCESS
;
247 GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
)
249 PGRAPHICS_SCREEN_BUFFER Buff
= (PGRAPHICS_SCREEN_BUFFER
)Buffer
;
252 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
253 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
255 Buffer
->Header
.Type
= SCREEN_BUFFER
;
258 * Uninitialize the graphics screen buffer
259 * in the reverse way we initialized it.
261 NtUnmapViewOfSection(Buff
->ClientProcess
, Buff
->ClientBitMap
);
262 NtUnmapViewOfSection(NtCurrentProcess(), Buff
->BitMap
);
263 NtClose(Buff
->hSection
);
264 NtClose(Buff
->ClientMutex
);
265 NtClose(Buff
->Mutex
);
266 ConsoleFreeHeap(Buff
->BitMapInfo
);
268 CONSOLE_SCREEN_BUFFER_Destroy(Buffer
);