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 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 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