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
,
39 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
);
43 GRAPHICS_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
44 IN OUT PCONSOLE Console
,
45 IN PGRAPHICS_BUFFER_INFO GraphicsInfo
)
47 NTSTATUS Status
= STATUS_SUCCESS
;
48 PGRAPHICS_SCREEN_BUFFER NewBuffer
= NULL
;
50 LARGE_INTEGER SectionSize
;
54 if (Buffer
== NULL
|| Console
== NULL
|| GraphicsInfo
== NULL
)
55 return STATUS_INVALID_PARAMETER
;
59 Status
= CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER
*)&NewBuffer
,
61 sizeof(GRAPHICS_SCREEN_BUFFER
));
62 if (!NT_SUCCESS(Status
)) return Status
;
63 NewBuffer
->Header
.Type
= GRAPHICS_BUFFER
;
64 NewBuffer
->Vtbl
= &GraphicsVtbl
;
67 * Remember the handle to the process so that we can close or unmap
68 * correctly the allocated resources when the client releases the
71 ProcessHandle
= CsrGetClientThread()->Process
->ProcessHandle
;
72 NewBuffer
->ClientProcess
= ProcessHandle
;
74 /* Get infos from the graphics buffer information structure */
75 NewBuffer
->BitMapInfoLength
= GraphicsInfo
->Info
.dwBitMapInfoLength
;
77 NewBuffer
->BitMapInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, NewBuffer
->BitMapInfoLength
);
78 if (NewBuffer
->BitMapInfo
== NULL
)
80 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
81 return STATUS_INSUFFICIENT_RESOURCES
;
84 /* Adjust the bitmap height if needed (bottom-top vs. top-bottom). Use always bottom-up. */
85 if (GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
> 0)
86 GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
= -GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
;
88 /* We do not use anything else than uncompressed bitmaps */
89 if (GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biCompression
!= BI_RGB
)
91 DPRINT1("biCompression == %d != BI_RGB, correct that!\n", GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biCompression
);
92 GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biCompression
= BI_RGB
;
95 RtlCopyMemory(NewBuffer
->BitMapInfo
,
96 GraphicsInfo
->Info
.lpBitMapInfo
,
97 GraphicsInfo
->Info
.dwBitMapInfoLength
);
99 NewBuffer
->BitMapUsage
= GraphicsInfo
->Info
.dwUsage
;
101 /* Set the screen buffer size. Fight against overflows. */
102 if ( GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biWidth
<= 0xFFFF &&
103 -GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
<= 0xFFFF )
105 /* Be careful about the sign of biHeight */
106 NewBuffer
->ScreenBufferSize
.X
= (SHORT
)GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biWidth
;
107 NewBuffer
->ScreenBufferSize
.Y
= (SHORT
)-GraphicsInfo
->Info
.lpBitMapInfo
->bmiHeader
.biHeight
;
109 NewBuffer
->OldViewSize
= NewBuffer
->ViewSize
=
110 NewBuffer
->OldScreenBufferSize
= NewBuffer
->ScreenBufferSize
;
114 Status
= STATUS_INSUFFICIENT_RESOURCES
;
115 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
116 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
121 * Create a mutex to synchronize bitmap memory access
122 * between ourselves and the client.
124 Status
= NtCreateMutant(&NewBuffer
->Mutex
, MUTANT_ALL_ACCESS
, NULL
, FALSE
);
125 if (!NT_SUCCESS(Status
))
127 DPRINT1("NtCreateMutant() failed: %lu\n", Status
);
128 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
129 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
134 * Duplicate the Mutex for the client. We must keep a trace of it
135 * so that we can close it when the client releases the screen buffer.
137 Status
= NtDuplicateObject(NtCurrentProcess(),
140 &NewBuffer
->ClientMutex
,
141 0, 0, DUPLICATE_SAME_ACCESS
);
142 if (!NT_SUCCESS(Status
))
144 DPRINT1("NtDuplicateObject() failed: %lu\n", Status
);
145 NtClose(NewBuffer
->Mutex
);
146 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
147 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
152 * Create a memory section for the bitmap area, to share with the client.
154 SectionSize
.QuadPart
= NewBuffer
->BitMapInfo
->bmiHeader
.biSizeImage
;
155 Status
= NtCreateSection(&NewBuffer
->hSection
,
162 if (!NT_SUCCESS(Status
))
164 DPRINT1("Error: Impossible to create a shared section ; Status = %lu\n", Status
);
165 NtClose(NewBuffer
->ClientMutex
);
166 NtClose(NewBuffer
->Mutex
);
167 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
168 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
173 * Create a view for our needs.
176 NewBuffer
->BitMap
= NULL
;
177 Status
= NtMapViewOfSection(NewBuffer
->hSection
,
179 (PVOID
*)&NewBuffer
->BitMap
,
187 if (!NT_SUCCESS(Status
))
189 DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status
);
190 NtClose(NewBuffer
->hSection
);
191 NtClose(NewBuffer
->ClientMutex
);
192 NtClose(NewBuffer
->Mutex
);
193 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
194 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
199 * Create a view for the client. We must keep a trace of it so that
200 * we can unmap it when the client releases the screen buffer.
203 NewBuffer
->ClientBitMap
= NULL
;
204 Status
= NtMapViewOfSection(NewBuffer
->hSection
,
206 (PVOID
*)&NewBuffer
->ClientBitMap
,
214 if (!NT_SUCCESS(Status
))
216 DPRINT1("Error: Impossible to map the shared section ; Status = %lu\n", Status
);
217 NtUnmapViewOfSection(NtCurrentProcess(), NewBuffer
->BitMap
);
218 NtClose(NewBuffer
->hSection
);
219 NtClose(NewBuffer
->ClientMutex
);
220 NtClose(NewBuffer
->Mutex
);
221 ConsoleFreeHeap(NewBuffer
->BitMapInfo
);
222 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
226 NewBuffer
->ViewOrigin
.X
= NewBuffer
->ViewOrigin
.Y
= 0;
227 NewBuffer
->VirtualY
= 0;
229 NewBuffer
->CursorBlinkOn
= FALSE
;
230 NewBuffer
->ForceCursorOff
= TRUE
;
231 NewBuffer
->CursorInfo
.bVisible
= FALSE
;
232 NewBuffer
->CursorInfo
.dwSize
= 0;
233 NewBuffer
->CursorPosition
.X
= NewBuffer
->CursorPosition
.Y
= 0;
237 *Buffer
= (PCONSOLE_SCREEN_BUFFER
)NewBuffer
;
238 Status
= STATUS_SUCCESS
;
245 GRAPHICS_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
)
247 PGRAPHICS_SCREEN_BUFFER Buff
= (PGRAPHICS_SCREEN_BUFFER
)Buffer
;
250 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
251 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
253 Buffer
->Header
.Type
= SCREEN_BUFFER
;
256 * Uninitialize the graphics screen buffer
257 * in the reverse way we initialized it.
259 NtUnmapViewOfSection(Buff
->ClientProcess
, Buff
->ClientBitMap
);
260 NtUnmapViewOfSection(NtCurrentProcess(), Buff
->BitMap
);
261 NtClose(Buff
->hSection
);
262 NtClose(Buff
->ClientMutex
);
263 NtClose(Buff
->Mutex
);
264 ConsoleFreeHeap(Buff
->BitMapInfo
);
266 CONSOLE_SCREEN_BUFFER_Destroy(Buffer
);