Exemple #1
0
int getwtext(int __left, int __top, int __right, int __bottom, wchar_info *__destin)
{
	int i;
	SMALL_RECT r;
	CHAR_INFO* buffer;
	COORD s, c = { 0,0 };
	if (__right<__left || __bottom<__top) return 0;
	init_ti();
	r.Left = __left - 1;
	r.Top = __top - 1;
	r.Right = __right - 1;
	r.Bottom = __bottom - 1;
	s.X = __right - __left + 1;
	s.Y = __bottom - __top + 1;
	buffer = (CHAR_INFO*)malloc(s.X * s.Y * sizeof(CHAR_INFO));
	if (ReadConsoleOutputW(GetStdHandle(STD_OUTPUT_HANDLE), buffer, s, c, &r))
	{
		for (i = 0; i < s.X * s.Y; i++)
		{
			__destin[i].letter = buffer[i].Char.UnicodeChar;
			__destin[i].attr = buffer[i].Attributes;
		}
	}
	free(buffer);
	return 0;
}
Exemple #2
0
int movetext(int __left, int __top, int __right, int __bottom,
	int __destleft, int __desttop)
{
	CHAR_INFO * buffer;
	SMALL_RECT r;
	COORD c = { 0,0 }, s;
	HANDLE con;
	init_ti();
	s.X = __right - __left + 1;
	s.Y = __bottom - __top + 1;
	if (s.X <= 0 || s.Y <= 0) return 0;
	buffer = (CHAR_INFO*)malloc(s.X * s.Y * sizeof(CHAR_INFO));
	con = GetStdHandle(STD_OUTPUT_HANDLE);
	r.Left = __left - 1;
	r.Top = __top - 1;
	r.Right = __right - 1;
	r.Bottom = __bottom - 1;
	if (ReadConsoleOutputW(con, buffer, s, c, &r))
		WriteConsoleOutputW(con, buffer, s, c, &r);
	free(buffer);
	return 0;
}
Exemple #3
0
// Консоль любит глючить, при попытках запроса более определенного количества ячеек.
// MAX_CONREAD_SIZE подобрано экспериментально
BOOL ReadConsoleOutputEx(HANDLE hOut, CHAR_INFO *pData, COORD bufSize, SMALL_RECT rgn, COORD* lpCursor /*= NULL*/)
{
	BOOL lbRc = FALSE;

	DWORD nTick1 = GetTickCount(), nTick2 = 0, nTick3 = 0, nTick4 = 0, nTick5 = 0;

	/*
	static bool bDBCS = false, bDBCS_Checked = false;
	if (!bDBCS_Checked)
	{
		bDBCS = (GetSystemMetrics(SM_DBCSENABLED) != 0);
		bDBCS_Checked = true;
	}

	bool   bDBCS_CP = bDBCS;
	UINT   MaxCharSize = 0;
	DWORD  nCP, nCP1, nMode;

	if (bDBCS)
	{
		nCP = GetConsoleOutputCP();
		nCP1 = GetConsoleCP();
		GetConsoleMode(hOut, &nMode);

		if (!AreCpInfoLeads(nCP, &MaxCharSize) || MaxCharSize < 2)
		{
			if (!IsWin10())
				bDBCS_CP = false;
		}
	}
	*/

	bool bDBCS_CP = IsConsoleDoubleCellCP();

	size_t nBufWidth = bufSize.X;
	int nWidth = (rgn.Right - rgn.Left + 1);
	int nHeight = (rgn.Bottom - rgn.Top + 1);
	int nCurSize = nWidth * nHeight;

	_ASSERTE(bufSize.X >= nWidth);
	_ASSERTE(bufSize.Y >= nHeight);
	_ASSERTE(rgn.Top>=0 && rgn.Bottom>=rgn.Top);
	_ASSERTE(rgn.Left>=0 && rgn.Right>=rgn.Left);

	//MSectionLock RCS;
	//if (gpSrv->pReqSizeSection && !RCS.Lock(gpSrv->pReqSizeSection, TRUE, 30000))
	//{
	//	_ASSERTE(FALSE);
	//	SetLastError(ERROR_INVALID_PARAMETER);
	//	return FALSE;

	//}

	COORD bufCoord = {0,0};
	DWORD dwErrCode = 0;
	CONSOLE_SCREEN_BUFFER_INFO sbi_tmp = {}; BOOL bSbiTmp = (BOOL)-1;

	nTick2 = GetTickCount();

	if (!bDBCS_CP && (nCurSize <= MAX_CONREAD_SIZE))
	{
		InterlockedIncrement(&gnInReadConsoleOutput);
		if (ReadConsoleOutputW(hOut, pData, bufSize, bufCoord, &rgn))
			lbRc = TRUE;
		InterlockedDecrement(&gnInReadConsoleOutput);
		nTick3 = GetTickCount();
	}

	if (!lbRc)
	{
		// Придется читать построчно
		
		// Теоретически - можно и блоками, но оверхед очень маленький, а велик
		// шанс обломаться, если консоль "глючит". Поэтому построчно...

		//bufSize.X = TextWidth;
		bufSize.Y = 1;
		bufCoord.X = 0; bufCoord.Y = 0;
		//rgn = gpSrv->sbi.srWindow;

		int Y1 = rgn.Top;
		int Y2 = rgn.Bottom;

		CHAR_INFO* pLine = pData;
		if (!bDBCS_CP)
		{
			// Simple processing (no DBCS) - one cell == one wchar_t
			for (int y = Y1; y <= Y2; y++, rgn.Top++, pLine+=nBufWidth)
			{
				nTick3 = GetTickCount();
				rgn.Bottom = rgn.Top;

				#ifdef DUMP_TEST_READS
				bSbiTmp = GetConsoleScreenBufferInfo(hOut, &sbi_tmp);
				#endif

				InterlockedIncrement(&gnInReadConsoleOutput);
				lbRc = ReadConsoleOutputW(hOut, pLine, bufSize, bufCoord, &rgn);
				InterlockedDecrement(&gnInReadConsoleOutput);

				#ifdef DUMP_TEST_READS
				UNREFERENCED_PARAMETER(sbi_tmp.dwSize.Y);
				#endif

				if (!lbRc)
				{
					dwErrCode = GetLastError();
					_ASSERTE(FALSE && "ReadConsoleOutputW failed in MyReadConsoleOutput");
					break;
				}
				nTick4 = GetTickCount();
			}
		}
		else // Process on DBCS-capable systems
		{
			for (int y = Y1; y <= Y2; y++, rgn.Top++, pLine+=nBufWidth)
			{
				nTick3 = GetTickCount();
				rgn.Bottom = rgn.Top;

				#ifdef DUMP_TEST_READS
				bSbiTmp = GetConsoleScreenBufferInfo(hOut, &sbi_tmp);
				#endif

				InterlockedIncrement(&gnInReadConsoleOutput);
				lbRc = ReadConsoleOutputW(hOut, pLine, bufSize, bufCoord, &rgn);
				InterlockedDecrement(&gnInReadConsoleOutput);

				#ifdef DUMP_TEST_READS
				UNREFERENCED_PARAMETER(sbi_tmp.dwSize.Y);
				#endif

				if (!lbRc)
				{
					dwErrCode = GetLastError();
					_ASSERTE(FALSE && "ReadConsoleOutputW failed in MyReadConsoleOutput");
					break;
				}

				// DBCS corrections (we need only glyph per hieroglyph for drawing)
				const CHAR_INFO* pSrc = pLine;
				const CHAR_INFO* pEnd = pLine + nBufWidth;
				CHAR_INFO* pDst = pLine;
				// Check first, line has hieroglyphs?
				while (pSrc < pEnd)
				{
					if (pSrc->Attributes & COMMON_LVB_LEADING_BYTE)
						break;
					*(pDst++) = *(pSrc++);
				}
				// If line was not fully processed (LVB was found)
				if (pSrc < pEnd)
				{
					// If caller want to know correction status
					CHAR_INFO* pCursorEnd = (lpCursor && (lpCursor->Y == rgn.Top)) ? (pLine + lpCursor->X) : pLine;
					int iCellsSkipped = 0;

					// Yes, Process this line with substitutions
					while (pSrc < pEnd)
					{
						*pDst = *pSrc;
						wchar_t wc = pSrc->Char.UnicodeChar;
						if (pSrc->Attributes & COMMON_LVB_LEADING_BYTE)
						{
							// If caller want to know correction status
							if ((pSrc+1) <= pCursorEnd)
							{
								iCellsSkipped++;
							}
							// Process LVB flags
							while (((++pSrc) < pEnd) && !(pSrc->Attributes & COMMON_LVB_TRAILING_BYTE))
							{
								// May be 2 or 4 cells
								if ((pDst->Char.UnicodeChar != wc) && ((pDst+1) < pEnd))
								{
									wc = pSrc->Char.UnicodeChar;
									*(++pDst) = *pSrc;
								}
								// If caller want to know correction status
								else if (pSrc <= pCursorEnd)
								{
									iCellsSkipped++;
								}
							}
							pDst->Attributes |= COMMON_LVB_TRAILING_BYTE;
						}
						pSrc++; pDst++;
					}
					// Clean rest of line
					WORD nLastAttr = (pEnd-1)->Attributes;
					while (pDst < pEnd)
					{
						pDst->Attributes = nLastAttr;
						pDst->Char.UnicodeChar = L' ';
						pDst++;
					}
					// If caller want to know correction status
					if (lpCursor && (lpCursor->Y == rgn.Top))
					{
						lpCursor->X = max(0, (lpCursor->X - iCellsSkipped));
					}
				}

				// Line is done
				nTick4 = GetTickCount();
			}
		} // End of DBCS-capable processing

		nTick5 = GetTickCount();
	}

	UNREFERENCED_PARAMETER(nTick1);
	UNREFERENCED_PARAMETER(nTick2);
	UNREFERENCED_PARAMETER(nTick3);
	UNREFERENCED_PARAMETER(nTick4);
	UNREFERENCED_PARAMETER(nTick5);
	UNREFERENCED_PARAMETER(sbi_tmp.dwSize.Y);
	UNREFERENCED_PARAMETER(bSbiTmp);
	return lbRc;
}
Exemple #4
0
// Консоль любит глючить, при попытках запроса более определенного количества ячеек.
// MAX_CONREAD_SIZE подобрано экспериментально
BOOL ReadConsoleOutputEx(HANDLE hOut, CHAR_INFO *pData, COORD bufSize, SMALL_RECT rgn)
{
	BOOL lbRc = FALSE;

	DWORD nTick1 = GetTickCount(), nTick2 = 0, nTick3 = 0, nTick4 = 0, nTick5 = 0;

	static bool bDBCS = false, bDBCS_Checked = false;
	if (!bDBCS_Checked)
	{
		bDBCS = (GetSystemMetrics(SM_DBCSENABLED) != 0);
		bDBCS_Checked = true;
	}

	bool   bDBCS_CP = bDBCS;
	LPCSTR szLeads = NULL;
	UINT   MaxCharSize = 0;
	DWORD  nCP, nCP1, nMode;

	if (bDBCS)
	{
		nCP = GetConsoleOutputCP();
		nCP1 = GetConsoleCP();
		GetConsoleMode(hOut, &nMode);

		szLeads = GetCpInfoLeads(nCP, &MaxCharSize);
		if (!szLeads || !*szLeads || MaxCharSize < 2)
		{
			bDBCS_CP = false;
		}
	}

	size_t nBufWidth = bufSize.X;
	int nWidth = (rgn.Right - rgn.Left + 1);
	int nHeight = (rgn.Bottom - rgn.Top + 1);
	int nCurSize = nWidth * nHeight;

	_ASSERTE(bufSize.X >= nWidth);
	_ASSERTE(bufSize.Y >= nHeight);
	_ASSERTE(rgn.Top>=0 && rgn.Bottom>=rgn.Top);
	_ASSERTE(rgn.Left>=0 && rgn.Right>=rgn.Left);

	//MSectionLock RCS;
	//if (gpSrv->pReqSizeSection && !RCS.Lock(gpSrv->pReqSizeSection, TRUE, 30000))
	//{
	//	_ASSERTE(FALSE);
	//	SetLastError(ERROR_INVALID_PARAMETER);
	//	return FALSE;

	//}

	COORD bufCoord = {0,0};
	DWORD dwErrCode = 0;

	nTick2 = GetTickCount();

	if (!bDBCS_CP && (nCurSize <= MAX_CONREAD_SIZE))
	{
		if (ReadConsoleOutputW(hOut, pData, bufSize, bufCoord, &rgn))
			lbRc = TRUE;
		nTick3 = GetTickCount();
	}

	if (!lbRc)
	{
		// Придется читать построчно
		
		// Теоретически - можно и блоками, но оверхед очень маленький, а велик
		// шанс обломаться, если консоль "глючит". Поэтому построчно...

		//bufSize.X = TextWidth;
		bufSize.Y = 1;
		bufCoord.X = 0; bufCoord.Y = 0;
		//rgn = gpSrv->sbi.srWindow;

		int Y1 = rgn.Top;
		int Y2 = rgn.Bottom;

		CHAR_INFO* pLine = pData;
		if (!bDBCS_CP)
		{
			for (int y = Y1; y <= Y2; y++, rgn.Top++, pLine+=nBufWidth)
			{
				nTick3 = GetTickCount();
				rgn.Bottom = rgn.Top;
				lbRc = ReadConsoleOutputW(hOut, pLine, bufSize, bufCoord, &rgn);
				if (!lbRc)
				{
					dwErrCode = GetLastError();
					_ASSERTE(FALSE && "ReadConsoleOutputW failed in MyReadConsoleOutput");
					break;
				}
				nTick4 = GetTickCount();
			}
		}
		else
		{
			DWORD nAttrsMax = bufSize.X;
			DWORD nCharsMax = nAttrsMax/* *4 */; // -- максимум там вроде на некоторых CP - 4 байта
			wchar_t* pszChars = (wchar_t*)malloc(nCharsMax*sizeof(*pszChars));
			char* pszCharsA = (char*)malloc(nCharsMax*sizeof(*pszCharsA));
			WORD* pnAttrs = (WORD*)malloc(bufSize.X*sizeof(*pnAttrs));
			if (pszChars && pszCharsA && pnAttrs)
			{
				COORD crRead = {rgn.Left,Y1};
				DWORD nChars, nAttrs, nCharsA;
				CHAR_INFO* pLine = pData;
				for (; crRead.Y <= Y2; crRead.Y++, pLine+=nBufWidth)
				{
					nTick3 = GetTickCount();
					rgn.Bottom = rgn.Top;

					nChars = nCharsA = nAttrs = 0;
					BOOL lbRcTxt = ReadConsoleOutputCharacterA(hOut, pszCharsA, nCharsMax, crRead, &nCharsA);
					dwErrCode = GetLastError();
					if (!lbRcTxt || !nCharsA)
					{
						nCharsA = 0;
						lbRcTxt = ReadConsoleOutputCharacterW(hOut, pszChars, nCharsMax, crRead, &nChars);
						dwErrCode = GetLastError();
					}
					BOOL lbRcAtr = ReadConsoleOutputAttribute(hOut, pnAttrs, bufSize.X, crRead, &nAttrs);
					dwErrCode = GetLastError();
					
					lbRc = lbRcTxt && lbRcAtr;

					if (!lbRc)
					{
						dwErrCode = GetLastError();
						_ASSERTE(FALSE && "ReadConsoleOutputAttribute failed in MyReadConsoleOutput");

						CHAR_INFO* p = pLine;
						for (size_t i = 0; i < nAttrsMax; ++i, ++p)
						{
							p->Attributes = 4; // red on black
							p->Char.UnicodeChar = 0xFFFE; // not a character
						}

						break;
					}
					else
					{
						if (nCharsA)
						{
							nChars = MultiByteToWideChar(nCP, 0, pszCharsA, nCharsA, pszChars, nCharsMax);
						}
						CHAR_INFO* p = pLine;
						wchar_t* psz = pszChars;
						WORD* pn = pnAttrs;
						//int i = nAttrsMax;
						//while ((i--) > 0)
						//{
						//	p->Attributes = *(pn++);
						//	p->Char.UnicodeChar = *(psz++);
						//	p++;
						//}
						size_t x1 = min(nChars,nAttrsMax);
						size_t x2 = nAttrsMax;
						for (size_t i = 0; i < x1; ++i, ++p)
						{
							p->Attributes = *pn;
							p->Char.UnicodeChar = *psz;

							WARNING("Некорректно! pn может указывать на начало блока DBCS/QBCS");
							pn++; // += MaxCharSize;
							psz++;
						}
						WORD nLastAttr = pnAttrs[max(0,(int)nAttrs-1)];
						for (size_t i = x1; i < x2; ++i, ++p)
						{
							p->Attributes = nLastAttr;
							p->Char.UnicodeChar = L' ';
						}
					}
					nTick4 = GetTickCount();
				}
			}
			SafeFree(pszChars);
			SafeFree(pszCharsA);
			SafeFree(pnAttrs);
		}

		nTick5 = GetTickCount();
	}

	UNREFERENCED_PARAMETER(nTick1);
	UNREFERENCED_PARAMETER(nTick2);
	UNREFERENCED_PARAMETER(nTick3);
	UNREFERENCED_PARAMETER(nTick4);
	UNREFERENCED_PARAMETER(nTick5);
	return lbRc;
}