Skip to content

Commit

Permalink
gh-1323, gh-1385, gh-1841: Let ‘Alternative mode’ toolbar button work…
Browse files Browse the repository at this point in the history
…s with console buffers.
  • Loading branch information
Maximus5 committed Mar 10, 2019
1 parent 2d11e11 commit ceb8715
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 97 deletions.
54 changes: 12 additions & 42 deletions src/ConEmu/RealBuffer.cpp
Expand Up @@ -588,52 +588,22 @@ bool CRealBuffer::LoadAlternativeConsole(LoadAltMode iMode /*= lam_Default*/)
}
}

if (iMode == lam_LastOutput)
if ((iMode == lam_LastOutput) || (iMode == lam_FullBuffer))
{
MFileMapping<CESERVER_CONSAVE_MAPHDR> StoredOutputHdr;
MFileMapping<CESERVER_CONSAVE_MAP> StoredOutputItem;

CESERVER_CONSAVE_MAPHDR* pHdr = NULL;
CESERVER_CONSAVE_MAP* pData = NULL;
CONSOLE_SCREEN_BUFFER_INFO storedSbi = {};
DWORD cchMaxBufferSize = 0;
size_t nMaxSize = 0;

StoredOutputHdr.InitName(CECONOUTPUTNAME, LODWORD(mp_RCon->hConWnd));
if (!(pHdr = StoredOutputHdr.Open()) || !pHdr->sCurrentMap[0])
{
// #AltBuffer Load alt buffer from Console Server (CECMD_GETOUTPUT / cmd_GetOutput)
DisplayLastError(L"Stored output mapping was not created!");
goto wrap;
}

cchMaxBufferSize = std::min(pHdr->MaxCellCount, (DWORD)(pHdr->info.dwSize.X * pHdr->info.dwSize.Y));

StoredOutputItem.InitName(pHdr->sCurrentMap); //-V205
nMaxSize = sizeof(*pData) + cchMaxBufferSize * sizeof(pData->Data[0]);
if (!(pData = StoredOutputItem.Open(FALSE,nMaxSize)))
{
DisplayLastError(L"Stored output data mapping was not created!");
goto wrap;
}

if ((pData->hdr.nVersion != CESERVER_REQ_VER) || (pData->hdr.cbSize <= sizeof(CESERVER_CONSAVE_MAP)))
{
DisplayLastError(L"Invalid data in mapping header", -1);
goto wrap;
}

storedSbi = pData->info;

lbRc = LoadDataFromDump(storedSbi, pData->Data, cchMaxBufferSize);
}
else if (iMode == lam_FullBuffer)
{
CESERVER_REQ *pIn = ExecuteNewCmd(CECMD_CONSOLEFULL, sizeof(CESERVER_REQ_HDR)+sizeof(DWORD));
CESERVER_REQ *pIn = ExecuteNewCmd(CECMD_CONSOLEFULL, sizeof(CESERVER_REQ_HDR) + 2 * sizeof(DWORD));
if (pIn)
{
int dynHeight = mp_RCon->mp_RBuf->GetDynamicHeight();
pIn->dwData[0] = (dynHeight > 0) ? dynHeight : 0;
if (iMode == lam_FullBuffer)
{
pIn->dwData[0] = (dynHeight > 0) ? dynHeight : 0;
pIn->dwData[1] = FALSE;
}
else
{
pIn->dwData[0] = 0;
pIn->dwData[1] = TRUE;
}
CESERVER_REQ *pOut = ExecuteSrvCmd(mp_RCon->GetServerPID(), pIn, ghWnd);
if (pOut && (pOut->hdr.cbSize > sizeof(CESERVER_CONSAVE_MAP)))
{
Expand Down
89 changes: 54 additions & 35 deletions src/ConEmuCD/ConEmuSrv.cpp
Expand Up @@ -1097,13 +1097,6 @@ int ServerInit()
// Межпроцессный семафор не помогает, оставил пока только в качестве заглушки
//InitializeConsoleInputSemaphore();

// Windows 7 has a bug which makes impossible to utilize ScreenBuffers
// https://conemu.github.io/en/MicrosoftBugs.html#CorruptedScreenBuffer
if (gpSrv->osv.dwMajorVersion == 6 && gpSrv->osv.dwMinorVersion == 1)
gpSrv->bReopenHandleAllowed = FALSE;
else
gpSrv->bReopenHandleAllowed = TRUE;

if (gnRunMode == RM_SERVER)
{
if (!gnConfirmExitParm)
Expand Down Expand Up @@ -1841,7 +1834,7 @@ BOOL MyWriteConsoleOutput(HANDLE hOut, CHAR_INFO *pData, COORD& bufSize, COORD&

void ConOutCloseHandle()
{
if (gpSrv->bReopenHandleAllowed)
if (isReopenHandleAllowed())
{
// Need to block all requests to output buffer in other threads
MSectionLockSimple csRead;
Expand All @@ -1852,31 +1845,27 @@ void ConOutCloseHandle()
}
}

// В Win7 закрытие дескриптора в ДРУГОМ процессе - закрывает консольный буфер ПОЛНОСТЬЮ!!!
// В итоге, буфер вывода telnet'а схлопывается!
bool isReopenHandleAllowed()
{
// Windows 7 has a bug which makes impossible to utilize ScreenBuffers
// https://conemu.github.io/en/MicrosoftBugs.html#CorruptedScreenBuffer
if (IsWin7Eql())
return false;
return true;
}

bool CmdOutputOpenMap(CONSOLE_SCREEN_BUFFER_INFO& lsbi, CESERVER_CONSAVE_MAPHDR*& pHdr, CESERVER_CONSAVE_MAP*& pData)
{
LogFunction(L"CmdOutputOpenMap");

pHdr = NULL;
pData = NULL;

// В Win7 закрытие дескриптора в ДРУГОМ процессе - закрывает консольный буфер ПОЛНОСТЬЮ!!!
// В итоге, буфер вывода telnet'а схлопывается!
if (gpSrv->bReopenHandleAllowed)
{
ConOutCloseHandle();
}
pHdr = nullptr;
pData = nullptr;

// Need to block all requests to output buffer in other threads
MSectionLockSimple csRead; csRead.Lock(&gpSrv->csReadConsoleInfo, LOCK_READOUTPUT_TIMEOUT);

// !!! Нас интересует реальное положение дел в консоли,
// а не скорректированное функцией MyGetConsoleScreenBufferInfo
if (!GetConsoleScreenBufferInfo(ghConOut, &lsbi))
{
return false; // Не смогли получить информацию о консоли...
}


if (!gpSrv->pStoredOutputHdr)
{
gpSrv->pStoredOutputHdr = new MFileMapping<CESERVER_CONSAVE_MAPHDR>;
Expand All @@ -1900,14 +1889,12 @@ bool CmdOutputOpenMap(CONSOLE_SCREEN_BUFFER_INFO& lsbi, CESERVER_CONSAVE_MAPHDR*
}
}

if (!lsbi.dwSize.Y)
lsbi = pHdr->info;

WARNING("А вот это нужно бы делать в RefreshThread!!!");
DEBUGSTR(L"--- CmdOutputStore begin\n");

//MSectionLock CS; CS.Lock(gpcsStoredOutput, FALSE);



COORD crMaxSize = MyGetLargestConsoleWindowSize(ghConOut);
DWORD cchOneBufferSize = lsbi.dwSize.X * lsbi.dwSize.Y; // Читаем всю консоль целиком!
DWORD cchMaxBufferSize = std::max<DWORD>(pHdr->MaxCellCount, (lsbi.dwSize.Y * lsbi.dwSize.X));

Expand Down Expand Up @@ -1994,15 +1981,36 @@ bool CmdOutputOpenMap(CONSOLE_SCREEN_BUFFER_INFO& lsbi, CESERVER_CONSAVE_MAPHDR*
// Сохранить данные ВСЕЙ консоли в mapping
void CmdOutputStore(bool abCreateOnly /*= false*/)
{
const bool reopen_allowed = isReopenHandleAllowed();
if (reopen_allowed)
{
// Nothing to do, in this mode we utilize conhost screen buffers
return;
}

LogFunction(L"CmdOutputStore");

CONSOLE_SCREEN_BUFFER_INFO lsbi = {{0,0}};
CONSOLE_SCREEN_BUFFER_INFO lsbi = {};
CESERVER_CONSAVE_MAPHDR* pHdr = NULL;
CESERVER_CONSAVE_MAP* pData = NULL;

// Need to block all requests to output buffer in other threads
MSectionLockSimple csRead; csRead.Lock(&gpSrv->csReadConsoleInfo, LOCK_READOUTPUT_TIMEOUT);

// Just in case we change the logic somehow
if (reopen_allowed)
ConOutCloseHandle();

// !!! Нас интересует реальное положение дел в консоли,
// а не скорректированное функцией MyGetConsoleScreenBufferInfo
if (!GetConsoleScreenBufferInfo(ghConOut, &lsbi) || !lsbi.dwSize.Y)
{
LogString("GetConsoleScreenBufferInfo failed");
return; // Не смогли получить информацию о консоли...
}
// just for information
COORD crMaxSize = MyGetLargestConsoleWindowSize(ghConOut);

if (!CmdOutputOpenMap(lsbi, pHdr, pData))
return;

Expand Down Expand Up @@ -2033,13 +2041,21 @@ void CmdOutputStore(bool abCreateOnly /*= false*/)

LogString("CmdOutputStore finished");
DEBUGSTR(L"--- CmdOutputStore end\n");
UNREFERENCED_PARAMETER(crMaxSize);
}

// abSimpleMode==true - просто восстановить экран на момент вызова CmdOutputStore
// ==false - пытаться подгонять строки вывода под текущее состояние
// задел на будущее для выполнения команд из Far (без /w), mc, или еще кого.
void CmdOutputRestore(bool abSimpleMode)
{
const bool reopen_allowed = isReopenHandleAllowed();
if (reopen_allowed)
{
// Nothing to do, in this mode we utilize conhost screen buffers
return;
}

LogFunction(L"CmdOutputRestore");

if (!abSimpleMode)
Expand All @@ -2050,11 +2066,14 @@ void CmdOutputRestore(bool abSimpleMode)
return;
}


// Need to block all requests to output buffer in other threads
MSectionLockSimple csRead; csRead.Lock(&gpSrv->csReadConsoleInfo, LOCK_READOUTPUT_TIMEOUT);

CONSOLE_SCREEN_BUFFER_INFO lsbi = {{0,0}};
// Just in case we change the logic somehow
if (reopen_allowed)
ConOutCloseHandle();

CONSOLE_SCREEN_BUFFER_INFO lsbi = {};
CESERVER_CONSAVE_MAPHDR* pHdr = NULL;
CESERVER_CONSAVE_MAP* pData = NULL;
if (!CmdOutputOpenMap(lsbi, pHdr, pData))
Expand Down Expand Up @@ -4501,7 +4520,7 @@ bool FreezeRefreshThread()
_ASSERTE(GetCurrentThreadId() != gpSrv->dwRefreshThread);
return false;
}

gpSrv->nRefreshFreezeRequests++;
ResetEvent(gpSrv->hFreezeRefreshThread);

Expand Down Expand Up @@ -4738,7 +4757,7 @@ DWORD WINAPI RefreshThread(LPVOID lpvParam)
// Always update con handle, мягкий вариант
// !!! В Win7 закрытие дескриптора в ДРУГОМ процессе - закрывает консольный буфер ПОЛНОСТЬЮ. В итоге, буфер вывода telnet'а схлопывается! !!!
// 120507 - Если крутится альт.сервер - то игнорировать
if (gpSrv->bReopenHandleAllowed
if (isReopenHandleAllowed()
&& !nAltWait
&& ((GetTickCount() - nLastConHandleTick) > UPDATECONHANDLE_TIMEOUT))
{
Expand Down
4 changes: 3 additions & 1 deletion src/ConEmuCD/ConEmuSrv.h
Expand Up @@ -407,7 +407,10 @@ bool IsAutoAttachAllowed();
//extern MConHandle ghConIn;
extern MConHandle ghConOut;
extern MConHandle gPrimaryBuffer, gAltBuffer;
extern USHORT gnPrimaryBufferLastRow;
void ConOutCloseHandle();
bool CmdOutputOpenMap(CONSOLE_SCREEN_BUFFER_INFO& lsbi, CESERVER_CONSAVE_MAPHDR*& pHdr, CESERVER_CONSAVE_MAP*& pData);
bool isReopenHandleAllowed();


typedef enum tag_RunMode
Expand Down Expand Up @@ -526,7 +529,6 @@ struct SrvInfo
bool bServerForcedTermination;
//
OSVERSIONINFO osv;
BOOL bReopenHandleAllowed;
UINT nMaxFPS;
//
MSection *csAltSrv;
Expand Down
1 change: 1 addition & 0 deletions src/ConEmuCD/ConsoleMain.cpp
Expand Up @@ -156,6 +156,7 @@ FGetConsoleDisplayMode pfnGetConsoleDisplayMode = NULL;
MConHandle ghConOut(L"CONOUT$");
//Used to store and restore console screen buffers in cmd_AltBuffer
MConHandle gPrimaryBuffer(NULL), gAltBuffer(NULL);
USHORT gnPrimaryBufferLastRow = 0; // last detected written row in gPrimaryBuffer

// Время ожидания завершения консольных процессов, когда юзер нажал крестик в КОНСОЛЬНОМ окне
// The system also displays this dialog box if the process does not respond within a certain time-out period
Expand Down

0 comments on commit ceb8715

Please sign in to comment.