BOOL GuiSetForeground(HWND hWnd) { BOOL lbRc = FALSE; if (ghConEmuWndDC) { CESERVER_REQ *pIn = (CESERVER_REQ*)malloc(sizeof(*pIn)), *pOut; if (pIn) { ExecutePrepareCmd(pIn, CECMD_SETFOREGROUND, sizeof(CESERVER_REQ_HDR)+sizeof(u64)); //-V119 DWORD nConEmuPID = ASFW_ANY; GetWindowThreadProcessId(ghConEmuWndDC, &nConEmuPID); AllowSetForegroundWindow(nConEmuPID); pIn->qwData[0] = (u64)hWnd; HWND hConWnd = GetRealConsoleWindow(); pOut = ExecuteGuiCmd(hConWnd, pIn, hConWnd); if (pOut) { if (pOut->hdr.cbSize == (sizeof(CESERVER_REQ_HDR)+sizeof(DWORD))) lbRc = pOut->dwData[0]; ExecuteFreeResult(pOut); } free(pIn); } } return lbRc; }
int WINAPI OnStretchDIBits(HDC hdc, int XDest, int YDest, int nDestWidth, int nDestHeight, int XSrc, int YSrc, int nSrcWidth, int nSrcHeight, const VOID *lpBits, const BITMAPINFO *lpBitsInfo, UINT iUsage, DWORD dwRop) { //typedef int (WINAPI* OnStretchDIBits_t)(HDC hdc, int XDest, int YDest, int nDestWidth, int nDestHeight, int XSrc, int YSrc, int nSrcWidth, int nSrcHeight, const VOID *lpBits, const BITMAPINFO *lpBitsInfo, UINT iUsage, DWORD dwRop); ORIGINAL_EX(StretchDIBits); int iRc = 0; if (F(StretchDIBits)) iRc = F(StretchDIBits)(hdc, XDest, YDest, nDestWidth, nDestHeight, XSrc, YSrc, nSrcWidth, nSrcHeight, lpBits, lpBitsInfo, iUsage, dwRop); // Если рисуют _прямо_ на канвасе ConEmu if (iRc != (int)GDI_ERROR && hdc && hdc == ghTempHDC) { // Уведомить GUI, что у него прямо на канвасе кто-то что-то нарисовал :) CESERVER_REQ* pIn = ExecuteNewCmd(CECMD_LOCKDC, sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_LOCKDC)); if (pIn) { pIn->LockDc.hDcWnd = ghConEmuWndDC; // На всякий случай pIn->LockDc.bLock = TRUE; pIn->LockDc.Rect.left = XDest; pIn->LockDc.Rect.top = YDest; pIn->LockDc.Rect.right = XDest+nDestWidth-1; pIn->LockDc.Rect.bottom = YDest+nDestHeight-1; CESERVER_REQ* pOut = ExecuteGuiCmd(ghConWnd, pIn, ghConWnd); if (pOut) ExecuteFreeResult(pOut); ExecuteFreeResult(pIn); } } return iRc; }
BOOL WINAPI OnBitBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop) { //typedef int (WINAPI* OnBitBlt_t)(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop); ORIGINAL_EX(BitBlt); BOOL bRc = FALSE; if (F(BitBlt)) bRc = F(BitBlt)(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, dwRop); // Если рисуют _прямо_ на канвасе ConEmu if (bRc && hdcDest && hdcDest == ghTempHDC) { // Уведомить GUI, что у него прямо на канвасе кто-то что-то нарисовал :) CESERVER_REQ* pIn = ExecuteNewCmd(CECMD_LOCKDC, sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_LOCKDC)); if (pIn) { pIn->LockDc.hDcWnd = ghConEmuWndDC; // На всякий случай pIn->LockDc.bLock = TRUE; pIn->LockDc.Rect.left = nXDest; pIn->LockDc.Rect.top = nYDest; pIn->LockDc.Rect.right = nXDest+nWidth-1; pIn->LockDc.Rect.bottom = nYDest+nHeight-1; CESERVER_REQ* pOut = ExecuteGuiCmd(ghConWnd, pIn, ghConWnd); if (pOut) ExecuteFreeResult(pOut); ExecuteFreeResult(pIn); } } return bRc; }
int WINAPI RegisterPanelView(PanelViewInit *ppvi) { if (!ppvi) { _ASSERTE(ppvi != NULL); return -2; } if (ppvi->cbSize != sizeof(PanelViewInit)) { _ASSERTE(ppvi->cbSize == sizeof(PanelViewInit)); return -2; } PanelViewRegInfo *pp = (ppvi->bLeftPanel) ? &gPanelRegLeft : &gPanelRegRight; if (ppvi->bRegister) { pp->pfnPeekPreCall = ppvi->pfnPeekPreCall.f; pp->pfnPeekPostCall = ppvi->pfnPeekPostCall.f; pp->pfnReadPreCall = ppvi->pfnReadPreCall.f; pp->pfnReadPostCall = ppvi->pfnReadPostCall.f; pp->pfnWriteCall = ppvi->pfnWriteCall.f; } else { pp->pfnPeekPreCall = pp->pfnPeekPostCall = pp->pfnReadPreCall = pp->pfnReadPostCall = NULL; pp->pfnWriteCall = NULL; } pp->bRegister = ppvi->bRegister; CESERVER_REQ In; int nSize = sizeof(CESERVER_REQ_HDR) + sizeof(In.PVI); ExecutePrepareCmd(&In, CECMD_REGPANELVIEW, nSize); In.PVI = *ppvi; CESERVER_REQ* pOut = ExecuteGuiCmd(FarHwnd, &In, FarHwnd); if (!pOut) { pp->pfnPeekPreCall = pp->pfnPeekPostCall = pp->pfnReadPreCall = pp->pfnReadPostCall = NULL; pp->pfnWriteCall = NULL; pp->bRegister = FALSE; return -3; } *ppvi = pOut->PVI; ExecuteFreeResult(pOut); if (ppvi->cbSize == 0) { pp->pfnPeekPreCall = pp->pfnPeekPostCall = pp->pfnReadPreCall = pp->pfnReadPostCall = NULL; pp->pfnWriteCall = NULL; pp->bRegister = FALSE; return -1; } return 0; }
void PatchGuiMessage(bool bReceived, HWND& hWnd, UINT& Msg, WPARAM& wParam, LPARAM& lParam) { if (!ghAttachGuiClient) return; switch (Msg) { case WM_MOUSEACTIVATE: if (wParam == (WPARAM)ghConEmuWnd) { wParam = (WPARAM)ghAttachGuiClient; } break; case WM_LBUTTONDOWN: if (bReceived && ghConEmuWnd && ghConWnd) { HWND hActiveCon = (HWND)GetWindowLongPtr(ghConEmuWnd, GWLP_USERDATA); if (hActiveCon != ghConWnd) { CESERVER_REQ* pIn = ExecuteNewCmd(CECMD_ACTIVATECON, sizeof(CESERVER_REQ_HDR) + sizeof(CESERVER_REQ_ACTIVATECONSOLE)); if (pIn) { pIn->ActivateCon.hConWnd = ghConWnd; CESERVER_REQ* pOut = ExecuteGuiCmd(ghConWnd, pIn, ghConWnd); ExecuteFreeResult(pIn); ExecuteFreeResult(pOut); } } #if 0 // Если окно ChildGui активируется кликом - то ConEmu (holder) // может остаться "под" предыдущим окном бывшим в фокусе... // Победить пока не получается. DWORD nTID = 0, nPID = 0; HWND hFore = GetForegroundWindow(); if (hFore && ((nTID = GetWindowThreadProcessId(hFore, &nPID)) != 0)) { if ((nPID != GetCurrentProcessId()) && (nPID != gnGuiPID)) { SetForegroundWindow(ghConEmuWnd); } } #endif } break; #ifdef _DEBUG case WM_DESTROY: if (hWnd == ghAttachGuiClient) { int iDbg = -1; } break; #endif } }
void SendCurrentDirectory(HWND hConWnd, LPCWSTR asDirectory, LPCWSTR asPassiveDirectory /*= NULL*/) { CESERVER_REQ* pIn = NULL; DWORD cbSize = 0; if (!AllocateSendCurrentDirectory(pIn, cbSize, asDirectory, asPassiveDirectory)) return; CESERVER_REQ* pOut = ExecuteGuiCmd(hConWnd, pIn, hConWnd, TRUE); ExecuteFreeResult(pOut); ExecuteFreeResult(pIn); }
BOOL WINAPI OnStretchBlt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, DWORD dwRop) { //typedef int (WINAPI* OnStretchBlt_t)(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, DWORD dwRop); ORIGINAL_EX(StretchBlt); BOOL bRc = FALSE; //#ifdef _DEBUG //HWND h = WindowFromDC(hdcDest); //#endif // Если рисуют _прямо_ на канвасе ConEmu if (/*bRc &&*/ hdcDest && hdcDest == ghTempHDC) { if ( (!StretchBltBatch.bottom && !StretchBltBatch.top) || (nYOriginDest <= StretchBltBatch.top) || (nXOriginDest != StretchBltBatch.left) || (StretchBltBatch.right != (nXOriginDest+nWidthDest-1)) || (StretchBltBatch.bottom != (nYOriginDest-1)) ) { // Сброс батча StretchBltBatch.left = nXOriginDest; StretchBltBatch.top = nYOriginDest; StretchBltBatch.right = nXOriginDest+nWidthDest-1; StretchBltBatch.bottom = nYOriginDest+nHeightDest-1; } else { StretchBltBatch.bottom = nYOriginDest+nHeightDest-1; } // Уведомить GUI, что у него прямо на канвасе кто-то что-то нарисовал :) CESERVER_REQ* pIn = ExecuteNewCmd(CECMD_LOCKDC, sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_LOCKDC)); if (pIn) { pIn->LockDc.hDcWnd = ghConEmuWndDC; // На всякий случай pIn->LockDc.bLock = TRUE; pIn->LockDc.Rect = StretchBltBatch; CESERVER_REQ* pOut = ExecuteGuiCmd(ghConWnd, pIn, ghConWnd); if (pOut) ExecuteFreeResult(pOut); ExecuteFreeResult(pIn); } } if (F(StretchBlt)) bRc = F(StretchBlt)(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, dwRop); return bRc; }
// When _st_ is 0: remove progress. // When _st_ is 1: set progress value to _pr_ (number, 0-100). // When _st_ is 2: set error state in progress on Windows 7 taskbar void GuiSetProgress(WORD st, WORD pr) { CESERVER_REQ* pIn = ExecuteNewCmd(CECMD_SETPROGRESS, sizeof(CESERVER_REQ_HDR)+sizeof(WORD)*2); if (pIn) { pIn->wData[0] = st; pIn->wData[1] = pr; CESERVER_REQ* pOut = ExecuteGuiCmd(ghConWnd, pIn, ghConWnd); ExecuteFreeResult(pIn); ExecuteFreeResult(pOut); } }
// export // Активировать текущую консоль в ConEmu int WINAPI ActivateConsole() { CESERVER_REQ In; int nSize = sizeof(CESERVER_REQ_HDR) + sizeof(In.ActivateCon); ExecutePrepareCmd(&In, CECMD_ACTIVATECON, nSize); In.ActivateCon.hConWnd = FarHwnd; CESERVER_REQ* pOut = ExecuteGuiCmd(FarHwnd, &In, FarHwnd); if (!pOut) { return FALSE; } BOOL lbSucceeded = (pOut->ActivateCon.hConWnd == FarHwnd); ExecuteFreeResult(pOut); return lbSucceeded; }
void GuiFlashWindow(CEFlashType fType, HWND hWnd, BOOL bInvert, DWORD dwFlags, UINT uCount, DWORD dwTimeout) { if (ghConEmuWndDC) { CESERVER_REQ *pIn = (CESERVER_REQ*)malloc(sizeof(*pIn)), *pOut; if (pIn) { ExecutePrepareCmd(pIn, CECMD_FLASHWINDOW, sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_FLASHWINFO)); //-V119 pIn->Flash.fType = fType; pIn->Flash.hWnd = hWnd; pIn->Flash.bInvert = bInvert; pIn->Flash.dwFlags = dwFlags; pIn->Flash.uCount = uCount; pIn->Flash.dwTimeout = dwTimeout; HWND hConWnd = GetRealConsoleWindow(); pOut = ExecuteGuiCmd(hConWnd, pIn, hConWnd); if (pOut) ExecuteFreeResult(pOut); free(pIn); } } }
// Helper function: Notification ‘Debug’ setting page in ConEmu void OnPeekReadConsoleInput(char acPeekRead/*'P'/'R'*/, char acUnicode/*'A'/'W'*/, HANDLE hConsoleInput, PINPUT_RECORD lpBuffer, DWORD nRead) { #ifdef TRAP_ON_MOUSE_0x0 if (lpBuffer && nRead) { for (UINT i = 0; i < nRead; i++) { if (lpBuffer[i].EventType == MOUSE_EVENT) { if (lpBuffer[i].Event.MouseEvent.dwMousePosition.X == 0 && lpBuffer[i].Event.MouseEvent.dwMousePosition.Y == 0) { _ASSERTE(!(lpBuffer[i].Event.MouseEvent.dwMousePosition.X == 0 && lpBuffer[i].Event.MouseEvent.dwMousePosition.Y == 0)); } //if (lpBuffer[i].Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED && lpBuffer[i].Event.MouseEvent.dwMousePosition.X != 5) //{ // _ASSERTE(!(lpBuffer[i].Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED && lpBuffer[i].Event.MouseEvent.dwMousePosition.X != 5)); //} } } } #endif DWORD nCurrentTID = GetCurrentThreadId(); gReadConsoleInfo.LastReadConsoleInputTID = nCurrentTID; gReadConsoleInfo.hConsoleInput2 = hConsoleInput; if (nRead) { if (!gbWasSucceededInRead) gbWasSucceededInRead = TRUE; // Сброс кешированных значений GetConsoleScreenBufferInfoCached(NULL, NULL); } if (!gFarMode.bFarHookMode || !gFarMode.bMonitorConsoleInput || !nRead || !lpBuffer) return; //// Пока - только Read. Peek игнорируем //if (acPeekRead != 'R') // return; CESERVER_REQ *pIn = ExecuteNewCmd(CECMD_PEEKREADINFO, sizeof(CESERVER_REQ_HDR) //-V119 +sizeof(CESERVER_REQ_PEEKREADINFO)+(nRead-1)*sizeof(INPUT_RECORD)); if (pIn) { pIn->PeekReadInfo.nCount = (WORD)nRead; pIn->PeekReadInfo.cPeekRead = acPeekRead; pIn->PeekReadInfo.cUnicode = acUnicode; pIn->PeekReadInfo.h = hConsoleInput; pIn->PeekReadInfo.nTID = nCurrentTID; pIn->PeekReadInfo.nPID = GetCurrentProcessId(); pIn->PeekReadInfo.bMainThread = (pIn->PeekReadInfo.nTID == gnHookMainThreadId); memmove(pIn->PeekReadInfo.Buffer, lpBuffer, nRead*sizeof(INPUT_RECORD)); CESERVER_REQ* pOut = ExecuteGuiCmd(ghConWnd, pIn, ghConWnd); if (pOut) ExecuteFreeResult(pOut); ExecuteFreeResult(pIn); } }
// Вызывается ТОЛЬКО в главной нити! void CPluginBackground::UpdateBackground() { if (!mn_BgPluginsCount) return; if (!ghConEmuWndDC || !IsWindow(ghConEmuWndDC)) return; if (mb_ThNeedLoad) { LoadThSet(TRUE/*Мы уже в главной нити*/); } //RECT rcClient; GetClientRect(ghConEmuWndDC, &rcClient); struct PaintBackgroundArg Arg = m_Default; Arg.cbSize = sizeof(struct PaintBackgroundArg); //m_Default.dcSizeX = Arg.dcSizeX = rcClient.right+1; //m_Default.dcSizeY = Arg.dcSizeY = rcClient.bottom+1; m_Default.dcSizeX = Arg.dcSizeX = (m_Default.rcConWorkspace.right-m_Default.rcConWorkspace.left+1)*m_Default.MainFont.nFontCellWidth; m_Default.dcSizeY = Arg.dcSizeY = (m_Default.rcConWorkspace.bottom-m_Default.rcConWorkspace.top+1)*m_Default.MainFont.nFontHeight; // ********************************************************************************** // запомнить данные из m_Default в m_Last, но т.к. там есть указатели - move не катит // ********************************************************************************** //memmove(&m_Last, &m_Default, sizeof(m_Last)); m_Last.MainFont = m_Default.MainFont; memmove(m_Last.crPalette, m_Default.crPalette, sizeof(m_Last.crPalette)); m_Last.dcSizeX = m_Default.dcSizeX; m_Last.dcSizeY = m_Default.dcSizeY; m_Last.rcDcLeft = m_Default.rcDcLeft; m_Last.rcDcRight = m_Default.rcDcRight; m_Last.rcConWorkspace = m_Default.rcConWorkspace; m_Last.conCursor = m_Default.conCursor; m_Last.FarInterfaceSettings.Raw = m_Default.FarInterfaceSettings.Raw; m_Last.FarPanelSettings.Raw = m_Default.FarPanelSettings.Raw; memmove(m_Last.nFarColors, m_Default.nFarColors, sizeof(m_Last.nFarColors)); m_Last.bPanelsAllowed = m_Default.bPanelsAllowed; // struct tag_BkPanelInfo m_Last.LeftPanel.bVisible = m_Default.LeftPanel.bVisible; m_Last.LeftPanel.bFocused = m_Default.LeftPanel.bFocused; m_Last.LeftPanel.bPlugin = m_Default.LeftPanel.bPlugin; m_Last.LeftPanel.rcPanelRect = m_Default.LeftPanel.rcPanelRect; m_Last.RightPanel.bVisible = m_Default.RightPanel.bVisible; m_Last.RightPanel.bFocused = m_Default.RightPanel.bFocused; m_Last.RightPanel.bPlugin = m_Default.RightPanel.bPlugin; m_Last.RightPanel.rcPanelRect = m_Default.RightPanel.rcPanelRect; // строки lstrcpyW(m_Last.LeftPanel.szCurDir, m_Default.LeftPanel.szCurDir); lstrcpyW(m_Last.LeftPanel.szFormat, m_Default.LeftPanel.szFormat); lstrcpyW(m_Last.LeftPanel.szHostFile, m_Default.LeftPanel.szHostFile); lstrcpyW(m_Last.RightPanel.szCurDir, m_Default.RightPanel.szCurDir); lstrcpyW(m_Last.RightPanel.szFormat, m_Default.RightPanel.szFormat); lstrcpyW(m_Last.RightPanel.szHostFile, m_Default.RightPanel.szHostFile); // ********************************************************************************** if (m_Default.dcSizeX < 1 || m_Default.dcSizeY < 1) { _ASSERTE(m_Default.dcSizeX >= 1 && m_Default.dcSizeY >= 1); return; } SetDcPanelRect(&Arg.rcDcLeft, &Arg.LeftPanel, &Arg); SetDcPanelRect(&Arg.rcDcRight, &Arg.RightPanel, &Arg); // gpTabs отстает от реальности. Arg.Place = m_Default.Place; //if (!gpTabs) // Arg.Place = pbp_Panels; //else if (gnCurrentWindowType == WTYPE_EDITOR) // Arg.Place = pbp_Editor; //else if (gnCurrentWindowType == WTYPE_VIEWER) // Arg.Place = pbp_Viewer; //else if (Arg.LeftPanel.bVisible || Arg.RightPanel.bVisible) //{ // _ASSERTE(gnCurrentWindowType == WTYPE_PANELS); // Arg.Place = pbp_Panels; //} BITMAPINFOHEADER bi = {sizeof(BITMAPINFOHEADER)}; bi.biWidth = Arg.dcSizeX; bi.biHeight = Arg.dcSizeY; bi.biPlanes = 1; bi.biBitCount = 32; //-V112 bi.biCompression = BI_RGB; //_ASSERTE(Arg.LeftPanel.bVisible || Arg.RightPanel.bVisible); HDC hScreen = GetDC(NULL); RECT rcMeta = {0,0, Arg.dcSizeX, Arg.dcSizeY}; // (in pixels) int iWidthMM = GetDeviceCaps(hScreen, HORZSIZE); if (iWidthMM <= 0) { _ASSERTE(iWidthMM>0); iWidthMM = 1024; } int iHeightMM = GetDeviceCaps(hScreen, VERTSIZE); if (iHeightMM <= 0) { _ASSERTE(iHeightMM>0); iHeightMM = 768; } int iWidthPels = GetDeviceCaps(hScreen, HORZRES); if (iWidthPels <= 0) { _ASSERTE(iWidthPels>0); iWidthPels = 0; } int iHeightPels = GetDeviceCaps(hScreen, VERTRES); if (iHeightPels <= 0) { _ASSERTE(iHeightPels>0); iHeightPels = 0; } RECT rcMetaMM = {0,0, (rcMeta.right * iWidthMM * 100)/iWidthPels, (rcMeta.bottom * iHeightMM * 100)/iHeightPels}; // (in .01-millimeter units) HDC hdc = NULL; HENHMETAFILE hEmf = NULL; COLORREF* pBits = NULL; HBITMAP hDib = NULL, hOld = NULL; #ifdef CREATE_EMF_TEMP_FILES wchar_t szEmfFile[MAX_PATH] = {}; #endif wchar_t *pszEmfFile = NULL; if (SETBACKGROUND_USE_EMF==1) { #ifdef CREATE_EMF_TEMP_FILES GetTempPath(MAX_PATH-32, szEmfFile); int nLen = lstrlen(szEmfFile); if (*szEmfFile && szEmfFile[nLen-1] != L'\\') { szEmfFile[nLen++] = L'\\'; szEmfFile[nLen] = 0; } _wsprintf(szEmfFile+nLen, SKIPLEN(31) L"CeBack%u.emf", GetCurrentProcessId()); pszEmfFile = szEmfFile; #endif hdc = CreateEnhMetaFile(hScreen, pszEmfFile, &rcMetaMM, L"ConEmu\0Far Background\0\0"); if (!hdc) { _ASSERTE(hdc!=NULL); return; } } else { hdc = CreateCompatibleDC(hScreen); if (!hdc) { _ASSERTE(hdc!=NULL); return; } _ASSERTE(pBits = NULL); hDib = CreateDIBSection(hScreen, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&pBits, NULL, 0); } ReleaseDC(NULL, hScreen); hScreen = NULL; Arg.hdc = hdc; if (SETBACKGROUND_USE_EMF==1) { HBRUSH hFillBr = CreateSolidBrush ( #ifdef _DEBUG RGB(128,128,0) #else RGB(0,0,0) #endif ); FillRect(hdc, &rcMeta, hFillBr); DeleteObject(hFillBr); } else { if (!hDib || !pBits) { _ASSERTE(hDib && pBits); if (hDib) DeleteObject(hDib); if (hdc) DeleteDC(hdc); return; } hOld = (HBITMAP)SelectObject(hdc, hDib); // Залить черным - по умолчанию #ifdef _DEBUG memset(pBits, 128, bi.biWidth*bi.biHeight*4); //-V112 #else memset(pBits, 0, bi.biWidth*bi.biHeight*4); #endif } // Painting! int nProcessed = 0; MSectionLock SC; SC.Lock(csBgPlugins, TRUE); DWORD nFromLevel = 0, nNextLevel, nSuggested; DWORD dwDrawnPlaces = Arg.Place; while(true) { nNextLevel = nFromLevel; struct RegisterBackgroundArg *p = mp_BgPlugins; for(int i = 0; i < mn_BgPluginsCount; i++, p++) { if (p->Cmd != rbc_Register || !(p->dwPlaces & Arg.Place) || !(p->PaintConEmuBackground)) continue; // пустая, неактивная в данном контексте, или некорректная ячейка // Слои nSuggested = p->dwSuggestedLevel; if (nSuggested < nFromLevel) { continue; // Этот слой уже обработан } else if (nSuggested > nFromLevel) { // Этот слой нужно будет обработать в следующий раз if ((nNextLevel == nFromLevel) || (nSuggested < nNextLevel)) nNextLevel = nSuggested; continue; } // На уровне 0 (заливающий фон) должен быть только один плагин Arg.dwLevel = (nProcessed == 0) ? 0 : (nFromLevel == 0 && nProcessed) ? 1 : nFromLevel; Arg.lParam = mp_BgPlugins[i].lParam; Arg.dwDrawnPlaces = 0; //mp_BgPlugins[i].PaintConEmuBackground(&Arg); UpdateBackground_Exec(mp_BgPlugins+i, &Arg); // Что плагин покрасил (панели/редактор/вьювер считаются покрашенными по умолчанию) dwDrawnPlaces |= Arg.dwDrawnPlaces; // nProcessed++; } if (nNextLevel == nFromLevel) break; // больше слоев нет nFromLevel = nNextLevel; } SC.Unlock(); // Sending background to GUI! if (nProcessed < 1) { // Ситуация возникает при старте ConEmu, когда панелей "еще нет" //_ASSERTE(nProcessed >= 1); if (mb_BgWasSent) { mb_BgWasSent = FALSE; CESERVER_REQ *pIn = ExecuteNewCmd(CECMD_SETBACKGROUND, sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_SETBACKGROUND)); if (pIn) { pIn->Background.nType = 1; pIn->Background.bEnabled = FALSE; pIn->Background.dwDrawnPlaces = 0; CESERVER_REQ *pOut = ExecuteGuiCmd(FarHwnd, pIn, FarHwnd); if (pOut) { ExecuteFreeResult(pOut); } ExecuteFreeResult(pIn); } } } else // есть "отработавшие" плагины, обновить Background! { GdiFlush(); DWORD nBitSize = 0, nBitsError = 0; if (SETBACKGROUND_USE_EMF==1) { hEmf = CloseEnhMetaFile(hdc); hdc = NULL; nBitSize = GetEnhMetaFileBits(hEmf, 0, NULL); if (nBitSize == 0) { dwDrawnPlaces = 0; nBitsError = GetLastError(); _ASSERTE(nBitSize!=0); if (hEmf) { // В случае ошибки - сразу удаляем DeleteEnhMetaFile(hEmf); hEmf = NULL; } } } else { nBitSize = bi.biWidth*bi.biHeight*sizeof(COLORREF); } DWORD nWholeSize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_SETBACKGROUND)+nBitSize; //-V103 //-V119 CESERVER_REQ *pIn = ExecuteNewCmd(CECMD_SETBACKGROUND, nWholeSize); if (!pIn) { _ASSERTE(pIn); } else { pIn->Background.nType = 1; pIn->Background.bEnabled = TRUE; pIn->Background.dwDrawnPlaces = dwDrawnPlaces; if (SETBACKGROUND_USE_EMF==1) pIn->Background.bmp.bfType = 0x4645/*EF*/; else pIn->Background.bmp.bfType = 0x4D42/*BM*/; pIn->Background.bmp.bfSize = nBitSize+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); //-V119 pIn->Background.bmp.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); //-V119 pIn->Background.bi = bi; if (SETBACKGROUND_USE_EMF==1) { LPBYTE pBits = ((LPBYTE)&pIn->Background)+sizeof(pIn->Background); DWORD nBitsRc = (nBitSize && hEmf) ? GetEnhMetaFileBits(hEmf, nBitSize, pBits) : 0; _ASSERTE(nBitsRc == nBitSize); if (!nBitsRc) { _ASSERTE(nBitsRc!=NULL); // Отключить нафиг ExecutePrepareCmd(&pIn->hdr, CECMD_SETBACKGROUND, nWholeSize-nBitSize); pIn->Background.nType = 1; pIn->Background.bEnabled = FALSE; pIn->Background.dwDrawnPlaces = 0; } } else { memmove(((LPBYTE)&pIn->Background)+sizeof(pIn->Background), pBits, bi.biWidth*bi.biHeight*sizeof(COLORREF)); } CESERVER_REQ *pOut = ExecuteGuiCmd(FarHwnd, pIn, FarHwnd); // Вызывается ТОЛЬКО в главной нити _ASSERTE(GetCurrentThreadId() == gnMainThreadId); if (pOut) { mb_BgWasSent = TRUE; // Сбросим флажок "Ошибка уже была показана" if (pOut->BackgroundRet.nResult == esbr_OK) { mb_BgErrorShown = FALSE; } // Показать ошибку, если есть else if ((pOut->BackgroundRet.nResult > esbr_OK) && (pOut->BackgroundRet.nResult <= esbr_LastErrorNo) && (pOut->BackgroundRet.nResult != esbr_ConEmuInShutdown) && !mb_BgErrorShown) { mb_BgErrorShown = TRUE; Plugin()->ShowMessage(CEBkError_ExecFailed+pOut->BackgroundRet.nResult, 0); } ExecuteFreeResult(pOut); } else if (!mb_BgErrorShown) { mb_BgErrorShown = TRUE; Plugin()->ShowMessage(CEBkError_ExecFailed, 0); } ExecuteFreeResult(pIn); } } if (SETBACKGROUND_USE_EMF == 0) { if (hdc && hOld) SelectObject(hdc, hOld); if (hDib) DeleteObject(hDib); if (hdc) DeleteDC(hdc); } else { if (hdc) { hEmf = CloseEnhMetaFile(hdc); hdc = NULL; } if (hEmf) { DeleteEnhMetaFile(hEmf); hEmf = NULL; } } }
DWORD WINAPI DllStart(LPVOID /*apParm*/) { wchar_t *szModule = (wchar_t*)calloc((MAX_PATH+1),sizeof(wchar_t)); if (!GetModuleFileName(NULL, szModule, MAX_PATH+1)) _wcscpy_c(szModule, MAX_PATH+1, L"GetModuleFileName failed"); const wchar_t* pszName = PointToName(szModule); #if defined(SHOW_EXE_TIMINGS) || defined(SHOW_EXE_MSGBOX) wchar_t szTimingMsg[512]; UNREFERENCED_PARAMETER(szTimingMsg); HANDLE hTimingHandle = GetStdHandle(STD_OUTPUT_HANDLE); if (!lstrcmpi(pszName, SHOW_EXE_MSGBOX_NAME)) { gbShowExeMsgBox = true; } #endif // ******************* begin ********************* print_timings(L"DllStart: InitializeHookedModules"); InitializeHookedModules(); //HANDLE hStartedEvent = (HANDLE)apParm; #if defined(SHOW_EXE_MSGBOX) if (gbShowExeMsgBox) { STARTUPINFO si = {sizeof(si)}; GetStartupInfo(&si); LPCWSTR pszCmd = GetCommandLineW(); // GuiMessageBox еще не прокатит, ничего не инициализировано HMODULE hUser = LoadLibrary(user32); typedef int (WINAPI* MessageBoxW_t)(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); if (hUser) { MessageBoxW_t MsgBox = (MessageBoxW_t)GetProcAddress(hUser, "MessageBoxW"); if (MsgBox) { wchar_t szMsg[128]; lstrcpyn(szMsg, pszName, 96); lstrcat(szMsg, L" loaded!"); wchar_t szTitle[64]; msprintf(szTitle, countof(szTitle), L"ConEmuHk, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); MsgBox(NULL, szMsg, szTitle, MB_SYSTEMMODAL); } FreeLibrary(hUser); } } #endif #ifdef _DEBUG { wchar_t szCpInfo[128]; DWORD nCP = GetConsoleOutputCP(); _wsprintf(szCpInfo, SKIPLEN(countof(szCpInfo)) L"Current Output CP = %u", nCP); print_timings(szCpInfo); } #endif if ((lstrcmpi(pszName, L"powershell.exe") == 0) || (lstrcmpi(pszName, L"powershell") == 0)) { HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if (IsOutputHandle(hStdOut)) { gbPowerShellMonitorProgress = true; MY_CONSOLE_SCREEN_BUFFER_INFOEX csbi = {sizeof(csbi)}; if (apiGetConsoleScreenBufferInfoEx(hStdOut, &csbi)) { gnConsolePopupColors = csbi.wPopupAttributes; } else { WARNING("Получить Popup атрибуты из мэппинга"); //gnConsolePopupColors = ...; gnConsolePopupColors = 0; } } } // Поскольку процедура в принципе может быть кем-то перехвачена, сразу найдем адрес // iFindAddress = FindKernelAddress(pi.hProcess, pi.dwProcessId, &fLoadLibrary); //HMODULE hKernel = ::GetModuleHandle(L"kernel32.dll"); //if (hKernel) //{ // gfnLoadLibrary = (UINT_PTR)::GetProcAddress(hKernel, "LoadLibraryW"); // _ASSERTE(gfnLoadLibrary!=NULL); //} //else //{ // _ASSERTE(hKernel!=NULL); // gfnLoadLibrary = NULL; //} if (!GetLoadLibraryAddress()) { _ASSERTE(gfnLoadLibrary!=0); } ghUser32 = GetModuleHandle(user32); if (ghUser32) ghUser32 = LoadLibrary(user32); // если подлинкован - увеличить счетчик WARNING("Попробовать не создавать LocalSecurity при старте"); //#ifndef TESTLINK gpLocalSecurity = LocalSecurity(); //gnMsgActivateCon = RegisterWindowMessage(CONEMUMSG_ACTIVATECON); //#endif //wchar_t szSkipEventName[128]; //msprintf(szSkipEventName, SKIPLEN(countof(szSkipEventName)) CEHOOKDISABLEEVENT, GetCurrentProcessId()); //HANDLE hSkipEvent = OpenEvent(EVENT_ALL_ACCESS , FALSE, szSkipEventName); ////BOOL lbSkipInjects = FALSE; //if (hSkipEvent) //{ // gbSkipInjects = (WaitForSingleObject(hSkipEvent, 0) == WAIT_OBJECT_0); // CloseHandle(hSkipEvent); //} //else //{ // gbSkipInjects = FALSE; //} WARNING("Попробовать не ломиться в мэппинг, а взять все из переменной ConEmuData"); // Открыть мэппинг консоли и попытаться получить HWND GUI, PID сервера, и пр... if (ghConWnd) { print_timings(L"OnConWndChanged"); OnConWndChanged(ghConWnd); //GetConMap(); } if (ghConEmuWnd) { #ifdef SHOW_INJECT_MSGBOX wchar_t* szDbgMsg = (wchar_t*)calloc(1024, sizeof(wchar_t)); wchar_t* szTitle = (wchar_t*)calloc(128, sizeof(wchar_t)); msprintf(szTitle, 1024, L"ConEmuHk, PID=%u", GetCurrentProcessId()); msprintf(szDbgMsg, 128, L"SetAllHooks, ConEmuHk, PID=%u\n%s", GetCurrentProcessId(), szModule); GuiMessageBox(ghConEmuWnd, szDbgMsg, szTitle, MB_SYSTEMMODAL); free(szDbgMsg); free(szTitle); #endif } //if (!gbSkipInjects && ghConWnd) //{ // InitializeConsoleInputSemaphore(); //} print_timings(L"GetImageSubsystem"); // Необходимо определить битность и тип (CUI/GUI) процесса, в который нас загрузили gnImageBits = WIN3264TEST(32,64); gnImageSubsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; // Определим тип (CUI/GUI) GetImageSubsystem(gnImageSubsystem, gnImageBits); // Проверка чего получилось _ASSERTE(gnImageBits==WIN3264TEST(32,64)); _ASSERTE(gnImageSubsystem==IMAGE_SUBSYSTEM_WINDOWS_GUI || gnImageSubsystem==IMAGE_SUBSYSTEM_WINDOWS_CUI); //BOOL lbGuiWindowAttach = FALSE; // Прицепить к ConEmu гуевую программу (notepad, putty, ...) #ifdef USE_PIPE_SERVER _ASSERTEX(gpHookServer==NULL); print_timings(L"gpHookServer"); gpHookServer = (PipeServer<CESERVER_REQ>*)calloc(1,sizeof(*gpHookServer)); if (gpHookServer) { wchar_t szPipeName[128]; msprintf(szPipeName, countof(szPipeName), CEHOOKSPIPENAME, L".", GetCurrentProcessId()); gpHookServer->SetMaxCount(3); gpHookServer->SetOverlapped(true); gpHookServer->SetLoopCommands(false); gpHookServer->SetDummyAnswerSize(sizeof(CESERVER_REQ_HDR)); if (!gpHookServer->StartPipeServer(szPipeName, (LPARAM)gpHookServer, LocalSecurity(), HookServerCommand, HookServerFree, NULL, NULL, HookServerReady)) { _ASSERTEX(FALSE); // Ошибка запуска Pipes? gpHookServer->StopPipeServer(); free(gpHookServer); gpHookServer = NULL; } } else { _ASSERTEX(gpHookServer!=NULL); } #endif WARNING("Попробовать не ломиться в мэппинг, а взять все из переменной ConEmuData"); if (ghConWnd) { print_timings(L"CShellProc"); CShellProc* sp = new CShellProc; if (sp) { if (sp->LoadGuiMapping()) { wchar_t *szExeName = (wchar_t*)calloc((MAX_PATH+1),sizeof(wchar_t)); //BOOL lbDosBoxAllowed = FALSE; if (!GetModuleFileName(NULL, szExeName, MAX_PATH+1)) szExeName[0] = 0; if (sp->GetUseInjects() == 2) { // Можно ли использовать облегченную версию хуков (только для exe-шника)? if (!gbSelfIsRootConsoleProcess && !IsFarExe(szExeName)) { gbHookExecutableOnly = true; } } CESERVER_REQ* pIn = sp->NewCmdOnCreate(eInjectingHooks, L"", szExeName, GetCommandLineW(), NULL, NULL, NULL, NULL, // flags gnImageBits, gnImageSubsystem, GetStdHandle(STD_INPUT_HANDLE), GetStdHandle(STD_OUTPUT_HANDLE), GetStdHandle(STD_ERROR_HANDLE)); if (pIn) { //HWND hConWnd = GetConsoleWindow(); CESERVER_REQ* pOut = ExecuteGuiCmd(ghConWnd, pIn, ghConWnd); ExecuteFreeResult(pIn); if (pOut) ExecuteFreeResult(pOut); } free(szExeName); } delete sp; } } else if (gnImageSubsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { print_timings(L"IMAGE_SUBSYSTEM_WINDOWS_GUI"); DWORD dwConEmuHwnd = 0; BOOL bAttachExistingWindow = FALSE; wchar_t szVar[64], *psz; ConEmuGuiMapping* GuiMapping = (ConEmuGuiMapping*)calloc(1,sizeof(*GuiMapping)); if (GuiMapping && LoadGuiMapping(gnSelfPID, *GuiMapping)) { gnGuiPID = GuiMapping->nGuiPID; ghConEmuWnd = GuiMapping->hGuiWnd; bAttachExistingWindow = gbAttachGuiClient = TRUE; //ghAttachGuiClient = } SafeFree(GuiMapping); // Если аттачим существующее окно - таб в ConEmu еще не готов if (!bAttachExistingWindow) { if (!dwConEmuHwnd && GetEnvironmentVariable(ENV_CONEMUHWND_VAR_W, szVar, countof(szVar))) { if (szVar[0] == L'0' && szVar[1] == L'x') { dwConEmuHwnd = wcstoul(szVar+2, &psz, 16); if (!user->isWindow((HWND)dwConEmuHwnd)) dwConEmuHwnd = 0; else if (!user->getClassNameW((HWND)dwConEmuHwnd, szVar, countof(szVar))) dwConEmuHwnd = 0; else if (lstrcmp(szVar, VirtualConsoleClassMain) != 0) dwConEmuHwnd = 0; } } if (dwConEmuHwnd) { // Предварительное уведомление ConEmu GUI, что запущено GUI приложение // и оно может "захотеть во вкладку ConEmu". DWORD nSize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_ATTACHGUIAPP); CESERVER_REQ *pIn = (CESERVER_REQ*)malloc(nSize); ExecutePrepareCmd(pIn, CECMD_ATTACHGUIAPP, nSize); pIn->AttachGuiApp.nPID = GetCurrentProcessId(); GetModuleFileName(NULL, pIn->AttachGuiApp.sAppFileName, countof(pIn->AttachGuiApp.sAppFileName)); pIn->AttachGuiApp.hkl = (DWORD)(LONG)(LONG_PTR)GetKeyboardLayout(0); wchar_t szGuiPipeName[128]; msprintf(szGuiPipeName, countof(szGuiPipeName), CEGUIPIPENAME, L".", dwConEmuHwnd); CESERVER_REQ* pOut = ExecuteCmd(szGuiPipeName, pIn, 10000, NULL); free(pIn); if (pOut) { if (pOut->hdr.cbSize > sizeof(CESERVER_REQ_HDR)) { if (pOut->AttachGuiApp.nFlags & agaf_Success) { user->allowSetForegroundWindow(pOut->hdr.nSrcPID); // PID ConEmu. _ASSERTEX(gnGuiPID==0 || gnGuiPID==pOut->hdr.nSrcPID); gnGuiPID = pOut->hdr.nSrcPID; //ghConEmuWnd = (HWND)dwConEmuHwnd; _ASSERTE(ghConEmuWnd==NULL || gnGuiPID!=0); _ASSERTE(pOut->AttachGuiApp.hConEmuWnd==(HWND)dwConEmuHwnd); ghConEmuWnd = pOut->AttachGuiApp.hConEmuWnd; ghConEmuWndDC = pOut->AttachGuiApp.hConEmuWndDC; ghConWnd = pOut->AttachGuiApp.hSrvConWnd; _ASSERTE(ghConEmuWndDC && user->isWindow(ghConEmuWndDC)); grcConEmuClient = pOut->AttachGuiApp.rcWindow; gnServerPID = pOut->AttachGuiApp.nPID; if (pOut->AttachGuiApp.hkl) { LONG_PTR hkl = (LONG_PTR)(LONG)pOut->AttachGuiApp.hkl; BOOL lbRc = ActivateKeyboardLayout((HKL)hkl, KLF_SETFORPROCESS) != NULL; UNREFERENCED_PARAMETER(lbRc); } OnConWndChanged(ghConWnd); gbAttachGuiClient = TRUE; } } ExecuteFreeResult(pOut); } } } } //if (!gbSkipInjects) { //gnRunMode = RM_APPLICATION; #ifdef _DEBUG //wchar_t szModule[MAX_PATH+1]; szModule[0] = 0; //GetModuleFileName(NULL, szModule, countof(szModule)); _ASSERTE((gnImageSubsystem==IMAGE_SUBSYSTEM_WINDOWS_CUI) || (lstrcmpi(pszName, L"DosBox.exe")==0) || gbAttachGuiClient); //if (!lstrcmpi(pszName, L"far.exe") || !lstrcmpi(pszName, L"mingw32-make.exe")) //if (!lstrcmpi(pszName, L"as.exe")) // MessageBoxW(NULL, L"as.exe loaded!", L"ConEmuHk", MB_SYSTEMMODAL); //else if (!lstrcmpi(pszName, L"cc1plus.exe")) // MessageBoxW(NULL, L"cc1plus.exe loaded!", L"ConEmuHk", MB_SYSTEMMODAL); //else if (!lstrcmpi(pszName, L"mingw32-make.exe")) // MessageBoxW(NULL, L"mingw32-make.exe loaded!", L"ConEmuHk", MB_SYSTEMMODAL); //if (!lstrcmpi(pszName, L"g++.exe")) // MessageBoxW(NULL, L"g++.exe loaded!", L"ConEmuHk", MB_SYSTEMMODAL); //{ #endif print_timings(L"StartupHooks"); gbHooksWasSet = StartupHooks(ghOurModule); print_timings(L"StartupHooks - done"); #ifdef _DEBUG //} #endif // Если NULL - значит это "Detached" консольный процесс, посылать "Started" в сервер смысла нет if (ghConWnd != NULL) { print_timings(L"SendStarted"); SendStarted(); //#ifdef _DEBUG //// Здесь это приводит к обвалу _chkstk, //// похоже из-за того, что dll-ка загружена НЕ из известных модулей, //// а из специально сформированного блока памяти // -- в одной из функций, под локальные переменные выделялось слишком много памяти // -- переделал в malloc/free, все заработало //TestShellProcessor(); //#endif } } //else //{ // gbHooksWasSet = FALSE; //} //delete sp; /* #ifdef _DEBUG if (!lstrcmpi(pszName, L"mingw32-make.exe")) GuiMessageBox(ghConEmuWnd, L"mingw32-make.exe DllMain finished", L"ConEmuHk", MB_SYSTEMMODAL); #endif */ SafeFree(szModule); //if (hStartedEvent) // SetEvent(hStartedEvent); print_timings(L"DllStart - done"); return 0; }
// Helper function: Notification ‘Debug’ setting page in ConEmu void OnPeekReadConsoleInput(char acPeekRead/*'P'/'R'*/, char acUnicode/*'A'/'W'*/, HANDLE hConsoleInput, PINPUT_RECORD lpBuffer, DWORD& nRead) { #ifdef TRAP_ON_MOUSE_0x0 if (lpBuffer && nRead) { for (UINT i = 0; i < nRead; i++) { if (lpBuffer[i].EventType == MOUSE_EVENT) { if (lpBuffer[i].Event.MouseEvent.dwMousePosition.X == 0 && lpBuffer[i].Event.MouseEvent.dwMousePosition.Y == 0) { _ASSERTE(!(lpBuffer[i].Event.MouseEvent.dwMousePosition.X == 0 && lpBuffer[i].Event.MouseEvent.dwMousePosition.Y == 0)); } //if (lpBuffer[i].Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED && lpBuffer[i].Event.MouseEvent.dwMousePosition.X != 5) //{ // _ASSERTE(!(lpBuffer[i].Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED && lpBuffer[i].Event.MouseEvent.dwMousePosition.X != 5)); //} } } } #endif DWORD nCurrentTID = GetCurrentThreadId(); gReadConsoleInfo.LastReadConsoleInputTID = nCurrentTID; gReadConsoleInfo.hConsoleInput2 = hConsoleInput; if (nRead) { if (!gbWasSucceededInRead) gbWasSucceededInRead = TRUE; // Сброс кешированных значений GetConsoleScreenBufferInfoCached(NULL, NULL); } if (!nRead || !lpBuffer) return; if (gFarMode.bFarHookMode && gFarMode.bMonitorConsoleInput) { CESERVER_REQ *pIn = ExecuteNewCmd(CECMD_PEEKREADINFO, sizeof(CESERVER_REQ_HDR) //-V119 +sizeof(CESERVER_REQ_PEEKREADINFO)+(nRead-1)*sizeof(INPUT_RECORD)); if (pIn) { pIn->PeekReadInfo.nCount = (WORD)nRead; pIn->PeekReadInfo.cPeekRead = acPeekRead; pIn->PeekReadInfo.cUnicode = acUnicode; pIn->PeekReadInfo.h = hConsoleInput; pIn->PeekReadInfo.nTID = nCurrentTID; pIn->PeekReadInfo.nPID = GetCurrentProcessId(); pIn->PeekReadInfo.bMainThread = (pIn->PeekReadInfo.nTID == gnHookMainThreadId); memmove(pIn->PeekReadInfo.Buffer, lpBuffer, nRead*sizeof(INPUT_RECORD)); CESERVER_REQ* pOut = ExecuteGuiCmd(ghConWnd, pIn, ghConWnd); if (pOut) ExecuteFreeResult(pOut); ExecuteFreeResult(pIn); } } // Temp bugfix for unexpected WINDOW_BUFFER_SIZE_EVENT if (gFarMode.bFarHookMode && (acPeekRead == 'R') && IsWin10()) { static WINDOW_BUFFER_SIZE_RECORD last_size = {}; INPUT_RECORD *src = lpBuffer, *dst = lpBuffer, *buf_end = lpBuffer + nRead; while (src < buf_end) { if (src != dst) { *dst = *src; } if (src->EventType != WINDOW_BUFFER_SIZE_EVENT) { ++src; ++dst; continue; } // OK, reported size was changed since last call if (last_size.dwSize != src->Event.WindowBufferSizeEvent.dwSize) { last_size = src->Event.WindowBufferSizeEvent; ++src; ++dst; continue; } // Size was not changed _ASSERTE(nRead > 0); --nRead; ++src; dst->EventType = 0; } } }