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