BOOL ProcessInputMessage(MSG64::MsgStr &msg, INPUT_RECORD &r) { memset(&r, 0, sizeof(r)); BOOL lbOk = FALSE; if (!UnpackInputRecord(&msg, &r)) { _ASSERT(FALSE); } else { TODO("Сделать обработку пачки сообщений, вдруг они накопились в очереди?"); //#ifdef _DEBUG //if (r.EventType == KEY_EVENT && (r.Event.KeyEvent.wVirtualKeyCode == 'C' || r.Event.KeyEvent.wVirtualKeyCode == VK_CANCEL)) //{ // DEBUGSTR(L" --- CtrlC/CtrlBreak recieved\n"); //} //#endif bool lbProcessEvent = false; bool lbIngoreKey = false; if (r.EventType == KEY_EVENT && r.Event.KeyEvent.bKeyDown && (r.Event.KeyEvent.wVirtualKeyCode == 'C' || r.Event.KeyEvent.wVirtualKeyCode == VK_CANCEL) && ( // Удерживается ТОЛЬКО Ctrl (r.Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS) && ((r.Event.KeyEvent.dwControlKeyState & ALL_MODIFIERS) == (r.Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS)) ) ) { lbProcessEvent = true; DEBUGSTR(L" --- CtrlC/CtrlBreak recieved\n"); DWORD dwMode = 0; GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwMode); // CTRL+C (and Ctrl+Break?) is processed by the system and is not placed in the input buffer if ((dwMode & ENABLE_PROCESSED_INPUT) == ENABLE_PROCESSED_INPUT) lbIngoreKey = lbProcessEvent = true; else lbProcessEvent = false; if (lbProcessEvent) { //BOOL lbRc = FALSE; #if 0 DWORD dwEvent = (r.Event.KeyEvent.wVirtualKeyCode == 'C') ? CTRL_C_EVENT : CTRL_BREAK_EVENT; #endif //&& (gpSrv->dwConsoleMode & ENABLE_PROCESSED_INPUT) #if 1 // Issue 590: GenerateConsoleCtrlEvent нифига не прерывает функцию ReadConsoleW SendMessage(ghConWnd, WM_KEYDOWN, r.Event.KeyEvent.wVirtualKeyCode, 0); //lbRc = TRUE; #endif #if 0 //The SetConsoleMode function can disable the ENABLE_PROCESSED_INPUT mode for a console's input buffer, //so CTRL+C is reported as keyboard input rather than as a signal. // CTRL+BREAK is always treated as a signal if ( // Удерживается ТОЛЬКО Ctrl (r.Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS) && ((r.Event.KeyEvent.dwControlKeyState & ALL_MODIFIERS) == (r.Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS)) ) { // Вроде работает, Главное не запускать процесс с флагом CREATE_NEW_PROCESS_GROUP // иначе у микрософтовской консоли (WinXP SP3) сносит крышу, и она реагирует // на Ctrl-Break, но напрочь игнорирует Ctrl-C lbRc = GenerateConsoleCtrlEvent(dwEvent, 0); // Это событие (Ctrl+C) в буфер помещается(!) иначе до фара не дойдет собственно клавиша C с нажатым Ctrl } #endif } if (lbIngoreKey) return FALSE; // CtrlBreak отсылаем СРАЗУ, мимо очереди, иначе макросы FAR нельзя стопнуть if (r.Event.KeyEvent.wVirtualKeyCode == VK_CANCEL) { // При получении CtrlBreak в реальной консоли - буфер ввода очищается // иначе фар, при попытке считать ввод получит старые, // еще не обработанные нажатия, и CtrlBreak проигнорирует FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); SendConsoleEvent(&r, 1); return FALSE; } } #ifdef _DEBUG if (r.EventType == KEY_EVENT && r.Event.KeyEvent.bKeyDown && r.Event.KeyEvent.wVirtualKeyCode == VK_F11) { DEBUGSTR(L" --- F11 recieved\n"); } #endif #ifdef _DEBUG if (r.EventType == MOUSE_EVENT) { static DWORD nLastEventTick = 0; if (nLastEventTick && (GetTickCount() - nLastEventTick) > 2000) { OutputDebugString(L".\n"); } wchar_t szDbg[60]; _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L" ConEmuC.MouseEvent(X=%i,Y=%i,Btns=0x%04x,Moved=%i)\n", r.Event.MouseEvent.dwMousePosition.X, r.Event.MouseEvent.dwMousePosition.Y, r.Event.MouseEvent.dwButtonState, (r.Event.MouseEvent.dwEventFlags & MOUSE_MOVED)); DEBUGLOGINPUT(szDbg); nLastEventTick = GetTickCount(); } #endif // Запомнить, когда была последняя активность пользователя if (r.EventType == KEY_EVENT || (r.EventType == MOUSE_EVENT && (r.Event.MouseEvent.dwButtonState || r.Event.MouseEvent.dwEventFlags || r.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))) { gpSrv->dwLastUserTick = GetTickCount(); } lbOk = TRUE; //SendConsoleEvent(&r, 1); } return lbOk; }
DWORD WINAPI DebugThread(LPVOID lpvParam) { DWORD nWait = WAIT_TIMEOUT; //DWORD nExternalExitCode = -1; wchar_t szInfo[1024]; if (gpSrv->DbgInfo.pszDebuggingCmdLine != NULL) { STARTUPINFO si = {sizeof(si)}; PROCESS_INFORMATION pi = {}; if (gpSrv->DbgInfo.bDebugProcessTree) { SetEnvironmentVariable(ENV_CONEMU_BLOCKCHILDDEBUGGERS, ENV_CONEMU_BLOCKCHILDDEBUGGERS_YES); } if (!CreateProcess(NULL, gpSrv->DbgInfo.pszDebuggingCmdLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE| DEBUG_PROCESS | (gpSrv->DbgInfo.bDebugProcessTree ? 0 : DEBUG_ONLY_THIS_PROCESS), NULL, NULL, &si, &pi)) { DWORD dwErr = GetLastError(); wchar_t szProc[64]; szProc[0] = 0; PROCESSENTRY32 pi = {sizeof(pi)}; if (GetProcessInfo(gpSrv->dwRootProcess, &pi)) _wcscpyn_c(szProc, countof(szProc), pi.szExeFile, countof(szProc)); _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't start debugging process. ErrCode=0x%08X\n", dwErr); lstrcpyn(szInfo+lstrlen(szInfo), gpSrv->DbgInfo.pszDebuggingCmdLine, 400); wcscat_c(szInfo, L"\n"); _wprintf(szInfo); return CERR_CANTSTARTDEBUGGER; } gpSrv->hRootProcess = pi.hProcess; gpSrv->hRootThread = pi.hThread; gpSrv->dwRootProcess = pi.dwProcessId; gpSrv->dwRootThread = pi.dwThreadId; gpSrv->dwRootStartTime = GetTickCount(); } /* ************************* */ int iDbgIdx = 0, iAttachedCount = 0; while (true) { HANDLE hDbgProcess = NULL; DWORD nDbgProcessID = 0; bool bFirstPID = ((iDbgIdx++) == 0); if (bFirstPID) { hDbgProcess = gpSrv->hRootProcess; nDbgProcessID = gpSrv->dwRootProcess; } else { // Взять из pDebugAttachProcesses if (!gpSrv->DbgInfo.pDebugAttachProcesses) break; if (!gpSrv->DbgInfo.pDebugAttachProcesses->pop_back(nDbgProcessID)) break; hDbgProcess = GetProcessHandleForDebug(nDbgProcessID); if (!hDbgProcess) { _ASSERTE(hDbgProcess!=NULL && "Can't open debugging process handle"); continue; } } _ASSERTE(hDbgProcess!=NULL && "Process handle must be opened"); // Битность отладчика должна соответствовать битности приложения! if (IsWindows64()) { int nBits = GetProcessBits(nDbgProcessID, hDbgProcess); if ((nBits == 32 || nBits == 64) && (nBits != WIN3264TEST(32,64))) { if (gpSrv->DbgInfo.pszDebuggingCmdLine != NULL) { _printf("Bitness of ConEmuC and debugging program does not match\n"); if (bFirstPID) return CERR_CANTSTARTDEBUGGER; else continue; } wchar_t szExe[MAX_PATH+16]; wchar_t szCmdLine[MAX_PATH*2]; if (GetModuleFileName(NULL, szExe, countof(szExe)-16)) { wchar_t* pszName = (wchar_t*)PointToName(szExe); _wcscpy_c(pszName, 16, (nBits == 32) ? L"ConEmuC.exe" : L"ConEmuC64.exe"); _wsprintf(szCmdLine, SKIPLEN(countof(szCmdLine)) L"\"%s\" /DEBUGPID=%u %s", szExe, nDbgProcessID, (gpSrv->DbgInfo.nDebugDumpProcess == 1) ? L"/DUMP" : (gpSrv->DbgInfo.nDebugDumpProcess == 2) ? L"/MINIDUMP" : (gpSrv->DbgInfo.nDebugDumpProcess == 3) ? L"/FULLDUMP" : L""); STARTUPINFO si = {sizeof(si)}; PROCESS_INFORMATION pi = {}; if (CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi)) { // Ждать НЕ будем, сразу на выход //HANDLE hEvents[2] = {pi.hProcess, ghExitQueryEvent}; //nWait = WaitForMultipleObjects(countof(hEvents), hEvents, FALSE, INFINITE); //if (nWait == WAIT_OBJECT_0) //{ // //GetExitCodeProcess(pi.hProcess, &nExternalExitCode); // nExternalExitCode = 0; //} //CloseHandle(pi.hProcess); //CloseHandle(pi.hThread); //if (nExternalExitCode == 0) //{ // goto done; //} // Может там еще процессы в списке на дамп? continue; } else { DWORD dwErr = GetLastError(); _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't start external debugger '%s'. ErrCode=0x%08X\n", szCmdLine, dwErr); _wprintf(szInfo); if (bFirstPID) return CERR_CANTSTARTDEBUGGER; else continue; } } wchar_t szProc[64]; szProc[0] = 0; PROCESSENTRY32 pi = {sizeof(pi)}; if (GetProcessInfo(nDbgProcessID, &pi)) _wcscpyn_c(szProc, countof(szProc), pi.szExeFile, countof(szProc)); _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Bits are incompatible. Can't debug '%s' PID=%i\n", szProc[0] ? szProc : L"not found", nDbgProcessID); _wprintf(szInfo); if (bFirstPID) return CERR_CANTSTARTDEBUGGER; else continue; } } if (gpSrv->DbgInfo.pszDebuggingCmdLine == NULL) { if (!DebugActiveProcess(nDbgProcessID)) { DWORD dwErr = GetLastError(); wchar_t szProc[64]; szProc[0] = 0; PROCESSENTRY32 pi = {sizeof(pi)}; if (GetProcessInfo(nDbgProcessID, &pi)) _wcscpyn_c(szProc, countof(szProc), pi.szExeFile, countof(szProc)); _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't attach debugger to '%s' PID=%i. ErrCode=0x%08X\n", szProc[0] ? szProc : L"not found", nDbgProcessID, dwErr); _wprintf(szInfo); return CERR_CANTSTARTDEBUGGER; } } iAttachedCount++; } if (iAttachedCount == 0) { return CERR_CANTSTARTDEBUGGER; } /* **************** */ // Дополнительная инициализация, чтобы закрытие дебагера (наш процесс) не привело // к закрытию "отлаживаемой" программы pfnDebugActiveProcessStop = (FDebugActiveProcessStop)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"DebugActiveProcessStop"); pfnDebugSetProcessKillOnExit = (FDebugSetProcessKillOnExit)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"DebugSetProcessKillOnExit"); if (pfnDebugSetProcessKillOnExit) pfnDebugSetProcessKillOnExit(FALSE/*KillOnExit*/); gpSrv->DbgInfo.bDebuggerActive = TRUE; PrintDebugInfo(); SetEvent(gpSrv->DbgInfo.hDebugReady); while (nWait == WAIT_TIMEOUT) { ProcessDebugEvent(); if (ghExitQueryEvent) nWait = WaitForSingleObject(ghExitQueryEvent, 0); } //done: gbRootAliveLess10sec = FALSE; gbInShutdown = TRUE; gbAlwaysConfirmExit = FALSE; _ASSERTE(gbTerminateOnCtrlBreak==FALSE); if (!nExitQueryPlace) nExitQueryPlace = 12+(nExitPlaceStep); SetTerminateEvent(ste_DebugThread); return 0; }
// gpSrv->dwRootProcess void WriteMiniDump(DWORD dwProcessId, DWORD dwThreadId, EXCEPTION_RECORD *pExceptionRecord, LPCSTR asConfirmText /*= NULL*/, BOOL bTreeBreak /*= FALSE*/) { MINIDUMP_TYPE dumpType = MiniDumpNormal; char szTitleA[64]; _wsprintfA(szTitleA, SKIPLEN(countof(szTitleA)) "ConEmuC Debugging PID=%u, Debugger PID=%u", dwProcessId, GetCurrentProcessId()); wchar_t szTitle[64]; _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"ConEmuC Debugging PID=%u, Debugger PID=%u", dwProcessId, GetCurrentProcessId()); int nBtn = 0; if (gpSrv->DbgInfo.nDebugDumpProcess == 2 || gpSrv->DbgInfo.nDebugDumpProcess == 3) nBtn = (gpSrv->DbgInfo.nDebugDumpProcess == 2) ? IDYES : IDNO; else nBtn = MessageBoxA(NULL, asConfirmText ? asConfirmText : "Create minidump (<No> - fulldump)?", szTitleA, MB_YESNOCANCEL|MB_SYSTEMMODAL); switch (nBtn) { case IDYES: break; case IDNO: dumpType = MiniDumpWithFullMemory; break; default: return; } // Т.к. в режиме "ProcessTree" мы пишем пачку дампов - спрашивать тип дампа будем один раз. if (gpSrv->DbgInfo.bDebugProcessTree && (gpSrv->DbgInfo.nDebugDumpProcess <= 1)) { gpSrv->DbgInfo.nDebugDumpProcess = (nBtn == IDNO) ? 3 : 2; } if (bTreeBreak) { GenerateTreeDebugBreak(dwProcessId); } bool bDumpSucceeded = false; HANDLE hDmpFile = NULL; //HMODULE hDbghelp = NULL; wchar_t szErrInfo[MAX_PATH*2]; wchar_t dmpfile[MAX_PATH]; dmpfile[0] = 0; typedef BOOL (WINAPI* MiniDumpWriteDump_t)(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam); MiniDumpWriteDump_t MiniDumpWriteDump_f = NULL; while (GetSaveDumpName(dwProcessId, (dumpType == MiniDumpWithFullMemory), dmpfile, countof(dmpfile))) { if (hDmpFile != INVALID_HANDLE_VALUE && hDmpFile != NULL) { CloseHandle(hDmpFile); hDmpFile = NULL; } hDmpFile = CreateFileW(dmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH, NULL); if (hDmpFile == INVALID_HANDLE_VALUE) { DWORD nErr = GetLastError(); _wsprintf(szErrInfo, SKIPLEN(countof(szErrInfo)) L"Can't create debug dump file\n%s\nErrCode=0x%08X\n\nChoose another name?", dmpfile, nErr); if (MessageBoxW(NULL, szErrInfo, szTitle, MB_YESNO|MB_SYSTEMMODAL|MB_ICONSTOP)!=IDYES) break; continue; // еще раз выбрать } if (!gpSrv->DbgInfo.hDbghelp) { gpSrv->DbgInfo.hDbghelp = LoadLibraryW(L"Dbghelp.dll"); if (gpSrv->DbgInfo.hDbghelp == NULL) { DWORD nErr = GetLastError(); _wsprintf(szErrInfo, SKIPLEN(countof(szErrInfo)) L"Can't load debug library 'Dbghelp.dll'\nErrCode=0x%08X\n\nTry again?", nErr); if (MessageBoxW(NULL, szErrInfo, szTitle, MB_YESNO|MB_SYSTEMMODAL|MB_ICONSTOP)!=IDYES) break; continue; // еще раз выбрать } } if (gpSrv->DbgInfo.MiniDumpWriteDump_f) { MiniDumpWriteDump_f = (MiniDumpWriteDump_t)gpSrv->DbgInfo.MiniDumpWriteDump_f; } else if (!MiniDumpWriteDump_f) { MiniDumpWriteDump_f = (MiniDumpWriteDump_t)GetProcAddress(gpSrv->DbgInfo.hDbghelp, "MiniDumpWriteDump"); if (!MiniDumpWriteDump_f) { DWORD nErr = GetLastError(); _wsprintf(szErrInfo, SKIPLEN(countof(szErrInfo)) L"Can't locate 'MiniDumpWriteDump' in library 'Dbghelp.dll', ErrCode=%u", nErr); MessageBoxW(NULL, szErrInfo, szTitle, MB_ICONSTOP|MB_SYSTEMMODAL); break; } gpSrv->DbgInfo.MiniDumpWriteDump_f = (FARPROC)MiniDumpWriteDump_f; } if (MiniDumpWriteDump_f) { MINIDUMP_EXCEPTION_INFORMATION mei = {dwThreadId}; EXCEPTION_POINTERS ep = {pExceptionRecord}; ep.ContextRecord = NULL; // Непонятно, откуда его можно взять mei.ExceptionPointers = &ep; mei.ClientPointers = FALSE; PMINIDUMP_EXCEPTION_INFORMATION pmei = NULL; // пока _printf("Creating minidump: "); _wprintf(dmpfile); _printf("..."); HANDLE hProcess = GetProcessHandleForDebug(dwProcessId); BOOL lbDumpRc = MiniDumpWriteDump_f( hProcess, dwProcessId, hDmpFile, dumpType, pmei, NULL, NULL); if (!lbDumpRc) { DWORD nErr = GetLastError(); _wsprintf(szErrInfo, SKIPLEN(countof(szErrInfo)) L"MiniDumpWriteDump failed.\nErrorCode=0x%08X", nErr); _printf("\nFailed, ErrorCode=0x%08X\n", nErr); MessageBoxW(NULL, szErrInfo, szTitle, MB_ICONSTOP|MB_SYSTEMMODAL); } else { _printf("\nMiniDumpWriteDump succeeded\n"); bDumpSucceeded = true; } break; } } // end while (GetSaveDumpName(dwProcessId, (dumpType == MiniDumpWithFullMemory), dmpfile, countof(dmpfile))) if (hDmpFile != INVALID_HANDLE_VALUE && hDmpFile != NULL) { CloseHandle(hDmpFile); } //if (hDbghelp) //{ // FreeLibrary(hDbghelp); //} //if (hCOMDLG32) //{ // FreeLibrary(hCOMDLG32); //} // В Win2k еще не было функции "отцепиться от процесса" if (bDumpSucceeded && gpSrv->DbgInfo.nDebugDumpProcess && !gpSrv->DbgInfo.bDebugProcessTree && (gnOsVer >= 0x0501)) { // Дело сделали, закрываемся SetTerminateEvent(ste_WriteMiniDump); //if (pfnGetConsoleProcessList) //{ // DWORD nCurCount = 0; // DWORD nConsolePids[128] = {}; // nCurCount = pfnGetConsoleProcessList(nConsolePids, countof(nConsolePids)); // // Но только если в консоли кроме нас никого нет // if (nCurCount == 0) // { // PostMessage(ghConWnd, WM_CLOSE, 0, 0); // } // else // { // SetTerminateEvent(); // } //} } }
wchar_t* RConStartArgs::CreateCommandLine(bool abForTasks /*= false*/) { wchar_t* pszFull = NULL; size_t cchMaxLen = (pszSpecialCmd ? (lstrlen(pszSpecialCmd) + 3) : 0); // только команда cchMaxLen += (pszStartupDir ? (lstrlen(pszStartupDir) + 20) : 0); // "-new_console:d:..." cchMaxLen += (pszRenameTab ? (lstrlen(pszRenameTab)*2 + 20) : 0); // "-new_console:t:..." cchMaxLen += (pszIconFile ? (lstrlen(pszIconFile) + 20) : 0); // "-new_console:C:..." cchMaxLen += (pszPalette ? (lstrlen(pszPalette)*2 + 20) : 0); // "-new_console:P:..." cchMaxLen += (pszWallpaper ? (lstrlen(pszWallpaper) + 20) : 0); // "-new_console:W:..." cchMaxLen += (bRunAsAdministrator ? 15 : 0); // -new_console:a cchMaxLen += (bRunAsRestricted ? 15 : 0); // -new_console:r cchMaxLen += (pszUserName ? (lstrlen(pszUserName) + 32 // "-new_console:u:<user>:<pwd>" + (pszDomain ? lstrlen(pszDomain) : 0) + (szUserPassword ? lstrlen(szUserPassword) : 0)) : 0); cchMaxLen += (bForceUserDialog ? 15 : 0); // -new_console:u cchMaxLen += (bBackgroundTab ? 15 : 0); // -new_console:b cchMaxLen += (bForegroungTab ? 15 : 0); // -new_console:f cchMaxLen += (bBufHeight ? 32 : 0); // -new_console:h<lines> cchMaxLen += (bLongOutputDisable ? 15 : 0); // -new_console:o cchMaxLen += (bOverwriteMode ? 15 : 0); // -new_console:w cchMaxLen += (nPTY ? 15 : 0); // -new_console:e cchMaxLen += (bInjectsDisable ? 15 : 0); // -new_console:i cchMaxLen += (eConfirmation ? 15 : 0); // -new_console:c / -new_console:n cchMaxLen += (bForceDosBox ? 15 : 0); // -new_console:x cchMaxLen += (bForceInherit ? 15 : 0); // -new_console:I cchMaxLen += (eSplit ? 64 : 0); // -new_console:s[<SplitTab>T][<Percents>](H|V) pszFull = (wchar_t*)malloc(cchMaxLen*sizeof(*pszFull)); if (!pszFull) { _ASSERTE(pszFull!=NULL); return NULL; } if (pszSpecialCmd) { if (bRunAsAdministrator && abForTasks) _wcscpy_c(pszFull, cchMaxLen, L"*"); else *pszFull = 0; // Не окавычиваем. Этим должен озаботиться пользователь _wcscat_c(pszFull, cchMaxLen, pszSpecialCmd); _wcscat_c(pszFull, cchMaxLen, L" "); } else { *pszFull = 0; } wchar_t szAdd[128] = L""; if (bRunAsAdministrator) wcscat_c(szAdd, L"a"); else if (bRunAsRestricted) wcscat_c(szAdd, L"r"); if (bForceUserDialog) wcscat_c(szAdd, L"u"); if (bBackgroundTab) wcscat_c(szAdd, L"b"); else if (bForegroungTab) wcscat_c(szAdd, L"f"); if (bForceDosBox) wcscat_c(szAdd, L"x"); if (bForceInherit) wcscat_c(szAdd, L"I"); if (eConfirmation == eConfAlways) wcscat_c(szAdd, L"c"); else if (eConfirmation == eConfNever) wcscat_c(szAdd, L"n"); if (bLongOutputDisable) wcscat_c(szAdd, L"o"); if (bOverwriteMode) wcscat_c(szAdd, L"w"); if (nPTY) wcscat_c(szAdd, (nPTY == 1) ? L"p1" : (nPTY == 2) ? L"p2" : L"p0"); if (bInjectsDisable) wcscat_c(szAdd, L"i"); if (bBufHeight) { if (nBufHeight) _wsprintf(szAdd+lstrlen(szAdd), SKIPLEN(16) L"h%u", nBufHeight); else wcscat_c(szAdd, L"h"); } // -new_console:s[<SplitTab>T][<Percents>](H|V) if (eSplit) { wcscat_c(szAdd, L"s"); if (nSplitPane) _wsprintf(szAdd+lstrlen(szAdd), SKIPLEN(16) L"%uT", nSplitPane); if (nSplitValue > 0 && nSplitValue < 1000) { UINT iPercent = (1000-nSplitValue)/10; _wsprintf(szAdd+lstrlen(szAdd), SKIPLEN(16) L"%u", max(1,min(iPercent,99))); } wcscat_c(szAdd, (eSplit == eSplitHorz) ? L"H" : L"V"); } if (szAdd[0]) { _wcscat_c(pszFull, cchMaxLen, bNewConsole ? L" -new_console:" : L" -cur_console:"); _wcscat_c(pszFull, cchMaxLen, szAdd); } struct CopyValues { wchar_t cOpt; bool bEscape; LPCWSTR pVal; } values[] = { {L'd', false, this->pszStartupDir}, {L't', true, this->pszRenameTab}, {L'C', false, this->pszIconFile}, {L'P', true, this->pszPalette}, {L'W', false, this->pszWallpaper}, {0} }; wchar_t szCat[32]; for (CopyValues* p = values; p->cOpt; p++) { if (p->pVal && *p->pVal) { bool bQuot = wcspbrk(p->pVal, L" \"") != NULL; if (bQuot) msprintf(szCat, countof(szCat), bNewConsole ? L" \"-new_console:%c:" : L" \"-cur_console:%c:", p->cOpt); else msprintf(szCat, countof(szCat), bNewConsole ? L" -new_console:%c:" : L" -cur_console:%c:", p->cOpt); _wcscat_c(pszFull, cchMaxLen, szCat); if (p->bEscape) { wchar_t* pD = pszFull + lstrlen(pszFull); const wchar_t* pS = p->pVal; while (*pS) { if (wcschr(L"<>()&|^\"", *pS)) *(pD++) = (*pS == L'"') ? L'"' : L'^'; *(pD++) = *(pS++); } _ASSERTE(pD < (pszFull+cchMaxLen)); *pD = 0; } else { _wcscat_c(pszFull, cchMaxLen, p->pVal); } if (bQuot) _wcscat_c(pszFull, cchMaxLen, L"\""); } } // "-new_console:u:<user>:<pwd>" if (pszUserName && *pszUserName) { _wcscat_c(pszFull, cchMaxLen, bNewConsole ? L" \"-new_console:u:" : L" \"-cur_console:u:"); if (pszDomain && *pszDomain) { _wcscat_c(pszFull, cchMaxLen, pszDomain); _wcscat_c(pszFull, cchMaxLen, L"\\"); } _wcscat_c(pszFull, cchMaxLen, pszUserName); if (szUserPassword) { _wcscat_c(pszFull, cchMaxLen, L":"); _wcscat_c(pszFull, cchMaxLen, szUserPassword); } _wcscat_c(pszFull, cchMaxLen, L"\""); } return pszFull; }
bool CDpiForDialog::Attach(HWND hWnd, HWND hCenterParent, CDynDialog* apDlgTemplate) { mh_Dlg = hWnd; wchar_t szLog[100]; mn_TemplateFontSize = apDlgTemplate ? apDlgTemplate->GetFontPointSize() : 8; mh_OldFont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0); if ((mh_OldFont != NULL) && (GetObject(mh_OldFont, sizeof(mlf_InitFont), &mlf_InitFont) > 0)) { _wsprintf(szLog, SKIPLEN(countof(szLog)) L"CDpiForDialog(x%08X) Font='%s' lfHeight=%i Points=%u", (DWORD)(DWORD_PTR)hWnd, mlf_InitFont.lfFaceName, mlf_InitFont.lfHeight, mn_TemplateFontSize); } else { ZeroStruct(mlf_InitFont); mlf_InitFont.lfHeight = GetFontSizeForDpi(NULL, 96); lstrcpyn(mlf_InitFont.lfFaceName, L"MS Shell Dlg", countof(mlf_InitFont.lfFaceName)); mlf_InitFont.lfWeight = 400; mlf_InitFont.lfCharSet = DEFAULT_CHARSET; _wsprintf(szLog, SKIPLEN(countof(szLog)) L"CDpiForDialog(x%08X) DefaultFont='%s' lfHeight=%i Points=%u", (DWORD)(DWORD_PTR)hWnd, mlf_InitFont.lfFaceName, mlf_InitFont.lfHeight, mn_TemplateFontSize); } LogString(szLog); // Up to Windows 8 - OS will care of dialog scaling // And what will happen in Windows 8.1? // If `Per-monitor` dpi was choosed in the OS settings, // we need to re-scale our dialog manually! // But if one dpi was chosen for all monitors? CDpiAware::QueryDpiForMonitor(NULL, &m_InitDpi); // Whole desktop DPI (in most cases that will be Primary monitor DPI) m_CurDpi.SetDpi(m_InitDpi); if (!m_Items.Initialized()) m_Items.Init(8); bool bPerMonitor = CDpiAware::IsPerMonitorDpi(); DEBUGTEST(bPerMonitor = true); if (bPerMonitor) { // When Windows 8.1 is in per-monitor mode // and application is marked as per-monitor-dpi aware // Windows does not resize dialogs automatically. // Our resources are designed for standard 96 dpi. MArray<DlgItem>* p = NULL; if (m_Items.Get(m_CurDpi.Ydpi, &p) && p) delete p; p = LoadDialogItems(hWnd); m_Items.Set(m_CurDpi.Ydpi, p); DpiValue CurMonDpi; CDpiAware::QueryDpi(hCenterParent ? hCenterParent : hWnd, &CurMonDpi); // Need to resize the dialog? if (m_CurDpi.Ydpi != CurMonDpi.Ydpi) { if (!SetDialogDPI(CurMonDpi)) return false; } } else { m_CurDpi.SetDpi(m_InitDpi.Xdpi, m_InitDpi.Ydpi); } return true; }
// Warning, напрямую НЕ вызывать. Пользоваться "общей" PostMacro void CPluginW1900::PostMacroApi(const wchar_t* asMacro, INPUT_RECORD* apRec, bool abShowParseErrors) { if (!InfoW1900 || !InfoW1900->AdvControl) return; MacroSendMacroText mcr = {sizeof(MacroSendMacroText)}; //mcr.Flags = 0; // По умолчанию - вывод на экран разрешен while ((asMacro[0] == L'@' || asMacro[0] == L'^') && asMacro[1] && asMacro[1] != L' ') { switch (*asMacro) { case L'@': mcr.Flags |= KMFLAGS_DISABLEOUTPUT; break; case L'^': mcr.Flags |= KMFLAGS_NOSENDKEYSTOPLUGINS; break; } asMacro++; } wchar_t* pszMacroCopy = NULL; //Far3 build 2576: удален $Text //т.к. макросы у нас фаро-независимые - нужны танцы с бубном pszMacroCopy = lstrdup(asMacro); CharUpperBuff(pszMacroCopy, lstrlen(pszMacroCopy)); if (wcsstr(pszMacroCopy, L"$TEXT") && !InfoW1900->MacroControl(&guid_ConEmu, MCTL_SENDSTRING, MSSC_CHECK, &mcr)) { SafeFree(pszMacroCopy); pszMacroCopy = (wchar_t*)calloc(lstrlen(asMacro)+1,sizeof(wchar_t)*2); wchar_t* psz = pszMacroCopy; while (*asMacro) { if (asMacro[0] == L'$' && (asMacro[1] == L'T' || asMacro[1] == L't') && (asMacro[2] == L'E' || asMacro[2] == L'e') && (asMacro[3] == L'X' || asMacro[3] == L'x') && (asMacro[4] == L'T' || asMacro[4] == L't')) { lstrcpy(psz, L"print("); psz += 6; // Пропустить spasing-symbols asMacro += 5; while (*asMacro == L' ' || *asMacro == L'\t' || *asMacro == L'\r' || *asMacro == L'\n') asMacro++; // Копировать строку или переменную if (*asMacro == L'@' && *(asMacro+1) == L'"') { *(psz++) = *(asMacro++); *(psz++) = *(asMacro++); while (*asMacro) { *(psz++) = *(asMacro++); if (*(asMacro-1) == L'"') { if (*asMacro != L'"') break; *(psz++) = *(asMacro++); } } } else if (*asMacro == L'"') { *(psz++) = *(asMacro++); while (*asMacro) { *(psz++) = *(asMacro++); if (*(asMacro-1) == L'\\' && *asMacro == L'"') { *(psz++) = *(asMacro++); } else if (*(asMacro-1) == L'"') { break; } } } else if (*asMacro == L'%') { *(psz++) = *(asMacro++); while (*asMacro) { if (wcschr(L" \t\r\n", *asMacro)) break; *(psz++) = *(asMacro++); } } else { SafeFree(pszMacroCopy); break; // ошибка } // закрыть скобку *(psz++) = L')'; } else { *(psz++) = *(asMacro++); } } // Если успешно пропатчили макрос if (pszMacroCopy) asMacro = pszMacroCopy; } mcr.SequenceText = asMacro; if (apRec) mcr.AKey = *apRec; mcr.Flags |= KMFLAGS_SILENTCHECK; if (!InfoW1900->MacroControl(&guid_ConEmu, MCTL_SENDSTRING, MSSC_CHECK, &mcr)) { if (abShowParseErrors) { wchar_t* pszErrText = NULL; size_t iRcSize = InfoW1900->MacroControl(&guid_ConEmu, MCTL_GETLASTERROR, 0, NULL); MacroParseResult* Result = iRcSize ? (MacroParseResult*)calloc(iRcSize,1) : NULL; if (Result) { Result->StructSize = sizeof(*Result); _ASSERTE(FALSE && "Check MCTL_GETLASTERROR"); InfoW1900->MacroControl(&guid_ConEmu, MCTL_GETLASTERROR, iRcSize, Result); size_t cchMax = (Result->ErrSrc ? lstrlen(Result->ErrSrc) : 0) + lstrlen(asMacro) + 255; pszErrText = (wchar_t*)malloc(cchMax*sizeof(wchar_t)); _wsprintf(pszErrText, SKIPLEN(cchMax) L"Error in Macro. Far %u.%u build %u r%u\n" L"ConEmu plugin %02u%02u%02u%s[%u] {1900}\n" L"Code: %u, Line: %u, Col: %u%s%s\n" L"----------------------------------\n" L"%s", gFarVersion.dwVerMajor, gFarVersion.dwVerMinor, gFarVersion.dwBuild, gFarVersion.Bis ? 1 : 0, MVV_1, MVV_2, MVV_3, _CRT_WIDE(MVV_4a), WIN3264TEST(32,64), Result->ErrCode, (UINT)(int)Result->ErrPos.Y+1, (UINT)(int)Result->ErrPos.X+1, Result->ErrSrc ? L", Hint: " : L"", Result->ErrSrc ? Result->ErrSrc : L"", asMacro); SafeFree(Result); } else { size_t cchMax = lstrlen(asMacro) + 255; pszErrText = (wchar_t*)malloc(cchMax*sizeof(wchar_t)); _wsprintf(pszErrText, SKIPLEN(cchMax) L"Error in Macro. Far %u.%u build %u r%u\n" L"ConEmu plugin %02u%02u%02u%s[%u] {1900}\n" L"----------------------------------\n" L"%s", gFarVersion.dwVerMajor, gFarVersion.dwVerMinor, gFarVersion.dwBuild, gFarVersion.Bis ? 1 : 0, MVV_1, MVV_2, MVV_3, _CRT_WIDE(MVV_4a), WIN3264TEST(32,64), asMacro); } if (pszErrText) { DWORD nTID; HANDLE h = apiCreateThread(BackgroundMacroError, pszErrText, &nTID, "BackgroundMacroError"); SafeCloseHandle(h); } } } else { //gFarVersion.dwBuild InfoW1900->MacroControl(&guid_ConEmu, MCTL_SENDSTRING, 0, &mcr); } SafeFree(pszMacroCopy); }
int DoInjectRemote(LPWSTR asCmdArg, bool abDefTermOnly) { gbInShutdown = TRUE; // чтобы не возникло вопросов при выходе gnRunMode = RM_SETHOOK64; LPWSTR pszNext = asCmdArg; LPWSTR pszEnd = NULL; DWORD nRemotePID = wcstoul(pszNext, &pszEnd, 10); wchar_t szStr[16]; wchar_t szTitle[128]; wchar_t szInfo[120]; wchar_t szParentPID[32]; #ifdef _DEBUG extern int ShowInjectRemoteMsg(int nRemotePID, LPCWSTR asCmdArg); if (ShowInjectRemoteMsg(nRemotePID, asCmdArg) != IDOK) { return CERR_HOOKS_FAILED; } #endif if (nRemotePID) { #if defined(SHOW_ATTACH_MSGBOX) if (!IsDebuggerPresent()) { wchar_t szTitle[100]; _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"%s PID=%u /INJECT", gsModuleName, gnSelfPID); const wchar_t* pszCmdLine = GetCommandLineW(); MessageBox(NULL,pszCmdLine,szTitle,MB_SYSTEMMODAL); } #endif CEStr lsName, lsPath; { CProcessData processes; processes.GetProcessName(nRemotePID, lsName.GetBuffer(MAX_PATH), MAX_PATH, lsPath.GetBuffer(MAX_PATH*2), MAX_PATH*2, NULL); CEStr lsLog(L"Remote: PID=", _ultow(nRemotePID, szStr, 10), L" Name=`", lsName, L"` Path=`", lsPath, L"`"); LogString(lsLog); } // Go to hook // InjectRemote waits for thread termination DWORD nErrCode = 0; CINFILTRATE_EXIT_CODES iHookRc = InjectRemote(nRemotePID, abDefTermOnly, &nErrCode); _wsprintf(szInfo, SKIPCOUNT(szInfo) L"InjectRemote result: %i (%s)", iHookRc, (iHookRc == CIR_OK) ? L"CIR_OK" : (iHookRc == CIR_AlreadyInjected) ? L"CIR_AlreadyInjected" : L"?"); LogString(szInfo); if (iHookRc == CIR_OK/*0*/ || iHookRc == CIR_AlreadyInjected/*1*/) { return iHookRc ? CERR_HOOKS_WAS_ALREADY_SET : CERR_HOOKS_WAS_SET; } else if ((iHookRc == CIR_ProcessWasTerminated) || (iHookRc == CIR_OpenProcess)) { // Don't show error message to user. These codes are logged to file only. return CERR_HOOKS_FAILED; } DWORD nSelfPID = GetCurrentProcessId(); PROCESSENTRY32 self = {sizeof(self)}, parent = {sizeof(parent)}; // Not optimal, needs refactoring if (GetProcessInfo(nSelfPID, &self)) GetProcessInfo(self.th32ParentProcessID, &parent); // Ошибку (пока во всяком случае) лучше показать, для отлова возможных проблем //_ASSERTE(iHookRc == 0); -- ассерт не нужен, есть MsgBox _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"%s %s, PID=%u", gsModuleName, gsVersion, nSelfPID); _wsprintf(szInfo, SKIPCOUNT(szInfo) L"Injecting remote FAILED, code=%i:0x%08X\n" L"%s %s, PID=%u\n" L"RemotePID=%u ", iHookRc, nErrCode, gsModuleName, gsVersion, nSelfPID, nRemotePID); _wsprintf(szParentPID, SKIPCOUNT(szParentPID) L"\n" L"ParentPID=%u ", self.th32ParentProcessID); CEStr lsError(lstrmerge( szInfo, lsPath.IsEmpty() ? lsName.IsEmpty() ? L"<Unknown>" : lsName.ms_Val : lsPath.ms_Val, szParentPID, parent.szExeFile)); LogString(lsError); MessageBoxW(NULL, lsError, szTitle, MB_SYSTEMMODAL); } else { //_ASSERTE(pi.hProcess && pi.hThread && pi.dwProcessId && pi.dwThreadId); wchar_t szDbgMsg[512], szTitle[128]; _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"ConEmuC, PID=%u", GetCurrentProcessId()); _wsprintf(szDbgMsg, SKIPLEN(countof(szDbgMsg)) L"ConEmuC.X, PID=%u\nCmdLine parsing FAILED (%u)!\n%s", GetCurrentProcessId(), nRemotePID, asCmdArg); LogString(szDbgMsg); MessageBoxW(NULL, szDbgMsg, szTitle, MB_SYSTEMMODAL); } return CERR_HOOKS_FAILED; }
// gpSrv->dwRootProcess void WriteMiniDump(DWORD dwProcessId, DWORD dwThreadId, EXCEPTION_RECORD *pExceptionRecord, LPCSTR asConfirmText /*= NULL*/, BOOL bTreeBreak /*= FALSE*/) { // 2 - minidump, 3 - fulldump int nConfirmDumpType = ConfirmDumpType(dwProcessId, asConfirmText); if (nConfirmDumpType < 2) { // Отмена return; } MINIDUMP_TYPE dumpType = (nConfirmDumpType == 2) ? MiniDumpNormal : MiniDumpWithFullMemory; // Т.к. в режиме "ProcessTree" мы пишем пачку дампов - спрашивать тип дампа будем один раз. if (IsDumpMulti() // several processes were attached && (gpSrv->DbgInfo.nDebugDumpProcess <= 1)) // 2 - minidump, 3 - fulldump { gpSrv->DbgInfo.nDebugDumpProcess = nConfirmDumpType; } if (bTreeBreak) { GenerateTreeDebugBreak(dwProcessId); } bool bDumpSucceeded = false; HANDLE hDmpFile = NULL; //HMODULE hDbghelp = NULL; wchar_t szErrInfo[MAX_PATH*2]; wchar_t szTitle[64]; _wsprintf(szTitle, SKIPLEN(countof(szTitle)) CE_CONEMUC_NAME_W L" Debugging PID=%u, Debugger PID=%u", dwProcessId, GetCurrentProcessId()); wchar_t dmpfile[MAX_PATH] = L""; dmpfile[0] = 0; FormatDumpName(dmpfile, countof(dmpfile), dwProcessId, false, (dumpType == MiniDumpWithFullMemory)); typedef BOOL (WINAPI* MiniDumpWriteDump_t)(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam); MiniDumpWriteDump_t MiniDumpWriteDump_f = NULL; while (GetSaveDumpName(dwProcessId, (dumpType == MiniDumpWithFullMemory), dmpfile, countof(dmpfile))) { if (hDmpFile != INVALID_HANDLE_VALUE && hDmpFile != NULL) { CloseHandle(hDmpFile); hDmpFile = NULL; } hDmpFile = CreateFileW(dmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH, NULL); if (hDmpFile == INVALID_HANDLE_VALUE) { DWORD nErr = GetLastError(); _wsprintf(szErrInfo, SKIPLEN(countof(szErrInfo)) L"Can't create debug dump file\n%s\nErrCode=0x%08X\n\nChoose another name?", dmpfile, nErr); if (MessageBoxW(NULL, szErrInfo, szTitle, MB_YESNO|MB_SYSTEMMODAL|MB_ICONSTOP)!=IDYES) break; continue; // еще раз выбрать } if (!gpSrv->DbgInfo.hDbghelp) { gpSrv->DbgInfo.hDbghelp = LoadLibraryW(L"Dbghelp.dll"); if (gpSrv->DbgInfo.hDbghelp == NULL) { DWORD nErr = GetLastError(); _wsprintf(szErrInfo, SKIPLEN(countof(szErrInfo)) L"Can't load debug library 'Dbghelp.dll'\nErrCode=0x%08X\n\nTry again?", nErr); if (MessageBoxW(NULL, szErrInfo, szTitle, MB_YESNO|MB_SYSTEMMODAL|MB_ICONSTOP)!=IDYES) break; continue; // еще раз выбрать } } if (gpSrv->DbgInfo.MiniDumpWriteDump_f) { MiniDumpWriteDump_f = (MiniDumpWriteDump_t)gpSrv->DbgInfo.MiniDumpWriteDump_f; } else if (!MiniDumpWriteDump_f) { MiniDumpWriteDump_f = (MiniDumpWriteDump_t)GetProcAddress(gpSrv->DbgInfo.hDbghelp, "MiniDumpWriteDump"); if (!MiniDumpWriteDump_f) { DWORD nErr = GetLastError(); _wsprintf(szErrInfo, SKIPLEN(countof(szErrInfo)) L"Can't locate 'MiniDumpWriteDump' in library 'Dbghelp.dll', ErrCode=%u", nErr); MessageBoxW(NULL, szErrInfo, szTitle, MB_ICONSTOP|MB_SYSTEMMODAL); break; } gpSrv->DbgInfo.MiniDumpWriteDump_f = (FARPROC)MiniDumpWriteDump_f; } if (MiniDumpWriteDump_f) { MINIDUMP_EXCEPTION_INFORMATION mei = {dwThreadId}; EXCEPTION_POINTERS ep = {pExceptionRecord}; ep.ContextRecord = NULL; // Непонятно, откуда его можно взять mei.ExceptionPointers = &ep; mei.ClientPointers = FALSE; PMINIDUMP_EXCEPTION_INFORMATION pmei = NULL; // пока _printf("Creating minidump: "); _wprintf(dmpfile); _printf("..."); HANDLE hProcess = GetProcessHandleForDebug(dwProcessId); BOOL lbDumpRc = MiniDumpWriteDump_f( hProcess, dwProcessId, hDmpFile, dumpType, pmei, NULL, NULL); if (!lbDumpRc) { DWORD nErr = GetLastError(); _wsprintf(szErrInfo, SKIPLEN(countof(szErrInfo)) L"MiniDumpWriteDump failed.\nErrorCode=0x%08X", nErr); _printf("\nFailed, ErrorCode=0x%08X\n", nErr); MessageBoxW(NULL, szErrInfo, szTitle, MB_ICONSTOP|MB_SYSTEMMODAL); } else { int iLeft = (gpSrv->DbgInfo.nWaitTreeBreaks > 0) ? (gpSrv->DbgInfo.nWaitTreeBreaks - 1) : 0; _wsprintf(szErrInfo, SKIPLEN(countof(szErrInfo)) L"\nMiniDumpWriteDump succeeded, %i left\n", iLeft); bDumpSucceeded = true; } break; } } // end while (GetSaveDumpName(dwProcessId, (dumpType == MiniDumpWithFullMemory), dmpfile, countof(dmpfile))) if (hDmpFile != INVALID_HANDLE_VALUE && hDmpFile != NULL) { CloseHandle(hDmpFile); } // В Win2k еще не было функции "отцепиться от процесса" if ((gnOsVer >= 0x0501) && bDumpSucceeded && gpSrv->DbgInfo.bUserRequestDump // И все дампы были созданы && (gpSrv->DbgInfo.nWaitTreeBreaks <= 1) // И это не ключи /DEBUGEXE или /DEBUGTREE && !gpSrv->DbgInfo.pszDebuggingCmdLine ) { // По завершении создания дампов - выйти SetTerminateEvent(ste_WriteMiniDump); } }
//void SettingsXML::Save(const wchar_t *regName, const wchar_t *value) //{ // if (!value) value = L""; // сюда мог придти и NULL // // Save(regName, (LPCBYTE)value, REG_SZ, (_tcslen(value)+1)*sizeof(wchar_t)); //} void SettingsXML::Save(const wchar_t *regName, LPCBYTE value, DWORD nType, DWORD nSize) { HRESULT hr = S_OK; IXMLDOMNamedNodeMap* pAttrs = NULL; IXMLDOMNodeList* pList = NULL; IXMLDOMAttribute *pIXMLDOMAttribute = NULL; IXMLDOMNode *pNode = NULL; IXMLDOMNode* pChild = NULL; IXMLDOMNode *pNodeRmv = NULL; BSTR bsValue = NULL; BSTR bsType = NULL; bool bNeedSetType = false; // nType: // REG_DWORD: сохранение числа в 16-ричном или 10-чном формате, в зависимости от того, что сейчас указано в xml ("dword"/"ulong"/"long") // REG_BINARY: строго в hex (FF,FF,...) // REG_SZ: ASCIIZ строка, можно проконтролировать, чтобы nSize/2 не был меньше длины строки // REG_MULTI_SZ: ASCIIZZ. При формировании <list...> нужно убедиться, что мы не вылезли за пределы nSize pChild = FindItem(mp_Key, L"value", regName, true); // создать, если его еще нету if (!pChild) goto wrap; hr = pChild->get_attributes(&pAttrs); if (FAILED(hr) || !pAttrs) goto wrap; bsType = GetAttr(pChild, pAttrs, L"type"); switch(nType) { case REG_DWORD: { wchar_t szValue[32]; if (bsType && (bsType[0] == L'u' || bsType[0] == L'U')) { _wsprintf(szValue, SKIPLEN(countof(szValue)) L"%u", *(LPDWORD)value); } else if (bsType && (bsType[0] == L'l' || bsType[0] == L'L')) { _wsprintf(szValue, SKIPLEN(countof(szValue)) L"%i", *(int*)value); } else { _wsprintf(szValue, SKIPLEN(countof(szValue)) L"%08x", *(LPDWORD)value); if (bsType) ::SysFreeString(bsType); // нужно добавить/установить тип bsType = ::SysAllocString(L"dword"); bNeedSetType = true; } bsValue = ::SysAllocString(szValue); } break; case REG_BINARY: { if (nSize == 1 && bsType && (bsType[0] == L'u' || bsType[0] == L'U')) { wchar_t szValue[4]; BYTE bt = *value; _wsprintf(szValue, SKIPLEN(countof(szValue)) L"%u", (DWORD)bt); bsValue = ::SysAllocString(szValue); } else if (nSize == 1 && bsType && (bsType[0] == L'l' || bsType[0] == L'L')) { wchar_t szValue[4]; char bt = *value; _wsprintf(szValue, SKIPLEN(countof(szValue)) L"%i", (int)bt); bsValue = ::SysAllocString(szValue); } else { DWORD nLen = nSize*2 + (nSize-1); // по 2 символа на байт + ',' между ними bsValue = ::SysAllocStringLen(NULL, nLen); nLen ++; // Чтобы далее не добавлять WCHAR на '\0' wchar_t* psz = (wchar_t*)bsValue; LPCBYTE ptr = value; while(nSize) { _wsprintf(psz, SKIPLEN(nLen-(psz-bsValue)) L"%02x", (DWORD)*ptr); ptr++; nSize--; psz+=2; if (nSize) *(psz++) = L','; } if (bsType && lstrcmp(bsType, L"hex")) { // Допустим только "hex" ::SysFreeString(bsType); bsType = NULL; } if (!bsType) { // нужно добавить/установить тип bsType = ::SysAllocString(L"hex"); bNeedSetType = true; } } } break; case REG_SZ: { wchar_t* psz = (wchar_t*)value; bsValue = ::SysAllocString(psz); if (bsType && lstrcmp(bsType, L"string")) { // Допустим только "string" ::SysFreeString(bsType); bsType = NULL; } if (!bsType) { // нужно добавить/установить тип bsType = ::SysAllocString(L"string"); bNeedSetType = true; } } break; case REG_MULTI_SZ: { if (bsType && lstrcmp(bsType, L"multi")) { // Допустим только "multi" ::SysFreeString(bsType); bsType = NULL; } if (!bsType) { // нужно добавить/установить тип bsType = ::SysAllocString(L"multi"); bNeedSetType = true; } } break; default: goto wrap; // не поддерживается } if (bNeedSetType) { _ASSERTE(bsType!=NULL); SetAttr(pChild, pAttrs, L"type", bsType); ::SysFreeString(bsType); bsType = NULL; } // Теперь собственно значение if (nType != REG_MULTI_SZ) { _ASSERTE(bsValue != NULL); SetAttr(pChild, pAttrs, L"data", bsValue); ::SysFreeString(bsValue); bsValue = NULL; } else // Тут нужно формировать список элементов <list> { VARIANT_BOOL bHasChild = VARIANT_FALSE; DOMNodeType nodeType = NODE_INVALID; // Если ранее был параметр "data" - удалить его из списка атрибутов hr = pAttrs->getNamedItem(L"data", &pNode); if (SUCCEEDED(hr) && pNode) { hr = pChild->removeChild(pNode, &pNodeRmv); pNode->Release(); pNode = NULL; if (pNodeRmv) { pNodeRmv->Release(); pNodeRmv = NULL; } } //TODO: может оставить перевод строки? // Сначала почистим #ifdef _DEBUG hr = pChild->get_nodeType(&nodeType); #endif hr = pChild->hasChildNodes(&bHasChild); if (bHasChild) { while((hr = pChild->get_firstChild(&pNode)) == S_OK && pNode) { hr = pNode->get_nodeType(&nodeType); #ifdef _DEBUG BSTR bsDebug = NULL; pNode->get_text(&bsDebug); if (bsDebug) ::SysFreeString(bsDebug); bsDebug = NULL; #endif hr = pChild->removeChild(pNode, &pNodeRmv); if (pNodeRmv) { pNodeRmv->Release(); pNodeRmv = NULL; } pNode->Release(); pNode = NULL; } } // Теперь - добавляем список wchar_t* psz = (wchar_t*)value; BSTR bsNodeType = ::SysAllocString(L"line"); VARIANT vtType; vtType.vt = VT_I4; vtType.lVal = NODE_ELEMENT; long nAllLen = nSize/2; // длина в wchar_t long nLen = 0; while(psz && *psz && nAllLen > 0) { hr = mp_File->createNode(vtType, bsNodeType, L"", &pNode); if (FAILED(hr) || !pNode) break; if (!SetAttr(pNode, L"data", psz)) break; hr = pChild->appendChild(pNode, &pNodeRmv); pNode->Release(); pNode = NULL; if (pNodeRmv) { pNodeRmv->Release(); pNodeRmv = NULL; } if (FAILED(hr)) break; nLen = _tcslen(psz)+1; psz += nLen; nAllLen -= nLen; } _ASSERTE(nAllLen <= 1); } mb_Modified = true; wrap: if (pIXMLDOMAttribute) { pIXMLDOMAttribute->Release(); pIXMLDOMAttribute = NULL; } if (pNode) { pNode->Release(); pNode = NULL; } if (pNodeRmv) { pNodeRmv->Release(); pNodeRmv = NULL; } if (pChild) { pChild->Release(); pChild = NULL; } if (pAttrs) { pAttrs->Release(); pAttrs = NULL; } if (bsValue) { ::SysFreeString(bsValue); bsValue = NULL; } if (bsType) { ::SysFreeString(bsType); bsType = NULL; } }
LRESULT CFrameHolder::OnPaint(HWND hWnd, HDC hdc, UINT uMsg) { if (hdc == NULL) { LRESULT lRc = 0; PAINTSTRUCT ps = {0}; hdc = BeginPaint(hWnd, &ps); if (hdc != NULL) { lRc = OnPaint(hWnd, hdc, uMsg); EndPaint(hWnd, &ps); } else { _ASSERTE(hdc != NULL); } return lRc; } #ifdef _DEBUG RECT rcClientReal = {}; GetClientRect(hWnd, &rcClientReal); MapWindowPoints(hWnd, NULL, (LPPOINT)&rcClientReal, 2); #endif // Если "завис" PostUpdate if (gpConEmu->mp_TabBar->NeedPostUpdate()) gpConEmu->mp_TabBar->Update(); // Go RECT wr, cr; RecalculateFrameSizes(); wr = gpConEmu->GetGuiClientRect(); #ifdef _DEBUG wchar_t szPaint[140]; _wsprintf(szPaint, SKIPCOUNT(szPaint) L"MainClient %s at {%i,%i}-{%i,%i} screen coords, size (%ix%i) calc (%ix%i)", (uMsg == WM_PAINT) ? L"WM_PAINT" : (uMsg == WM_PRINTCLIENT) ? L"WM_PRINTCLIENT" : L"UnknownMsg", LOGRECTCOORDS(rcClientReal), LOGRECTSIZE(rcClientReal), LOGRECTSIZE(wr)); DEBUGSTRPAINT(szPaint); #endif #if defined(CONEMU_TABBAR_EX) #ifdef RED_CLIENT_FILL HBRUSH h = CreateSolidBrush(RGB(255,0,0)); FillRect(hdc, &wr, h); DeleteObject(h); return 0; #endif #endif if (gpSet->isStatusBarShow) { int nHeight = gpSet->StatusBarHeight(); if (nHeight < (wr.bottom - wr.top)) { RECT rcStatus = {wr.left, wr.bottom - nHeight, wr.right, wr.bottom}; gpConEmu->mp_Status->PaintStatus(hdc, &rcStatus); wr.bottom = rcStatus.top; } } cr = wr; DEBUGTEST(FrameDrawStyle dt = gpConEmu->DrawType()); #if defined(CONEMU_TABBAR_EX) RECT tr = {}; if (!gpSet->isTabsInCaption) { _ASSERTE(gpConEmu->GetDwmClientRectTopOffset() == 0); // CheckIt, must be zero if (gpSet->isTabs) { RECT captrect = gpConEmu->CalcRect(CER_TAB, wr, CER_MAINCLIENT); //CalculateCaptionPosition(cr, &captrect); CalculateTabPosition(cr, captrect, &tr); PaintDC dc = {false}; RECT pr = {captrect.left, 0, captrect.right, captrect.bottom}; gpConEmu->BeginBufferedPaint(hdc, pr, dc); gpConEmu->mp_TabBar->PaintTabs(dc, captrect, tr); gpConEmu->EndBufferedPaint(dc, TRUE); } } else if (dt == fdt_Aero || dt == fdt_Win8) { _ASSERTE(gpSet->isTabsInCaption); int nOffset = gpConEmu->GetDwmClientRectTopOffset(); // "Рамка" расширена на клиентскую область, поэтому // нужно зарисовать заголовок черной кистью, иначе идет // искажение цвета для кнопок Min/Max/Close if (gpSet->isTabs) { RECT captrect = gpConEmu->CalcRect(CER_TAB, wr, CER_MAINCLIENT); //CalculateCaptionPosition(cr, &captrect); CalculateTabPosition(cr, captrect, &tr); PaintDC dc = {false}; RECT pr = {captrect.left, 0, captrect.right, captrect.bottom}; gpConEmu->BeginBufferedPaint(hdc, pr, dc); gpConEmu->mp_TabBar->PaintTabs(dc, captrect, tr); gpConEmu->EndBufferedPaint(dc, TRUE); // There is no "Glass" in Win8 mb_WasGlassDraw = IsWindows7 && !IsWindows8; } cr.top += nOffset; } #endif #ifdef _DEBUG int nWidth = (cr.right-cr.left); int nHeight = (cr.bottom-cr.top); #endif WARNING("Пока табы рисуем не сами и ExtendDWM отсутствует - дополнительные изыски с временным DC не нужны"); #if 0 if (!gpSet->isTabsInCaption) { //OnPaintClient(hdc/*, nWidth, nHeight*/); } else // Создадим временный DC, для удобства отрисовки в Glass-режиме и для фикса глюка DWM(?) см.ниже // В принципе, для режима Win2k/XP временный DC можно не создавать, если это будет тормозить { //_ASSERTE(FALSE && "Need to be rewritten"); HDC hdcPaint = CreateCompatibleDC(hdc); HBITMAP hbmp = CreateCompatibleBitmap(hdc, nWidth, nHeight); HBITMAP hOldBmp = (HBITMAP)SelectObject(hdcPaint, hbmp); //OnPaintClient(hdcPaint/*, nWidth, nHeight*/); if ((dt == fdt_Aero) || !(mb_WasGlassDraw && gpConEmu->isZoomed())) { BitBlt(hdc, cr.left, cr.top, nWidth, nHeight, hdcPaint, 0, 0, SRCCOPY); } else { //mb_WasGlassDraw = FALSE; // Какой-то странный глюк DWM. При отключении Glass несколько верхних строк // клиентской области оказываются "разрушенными" - у них остается атрибут "прозрачности" // хотя прозрачность (Glass) уже отключена. В результате эти строки - белесые BITMAPINFOHEADER bi = {sizeof(BITMAPINFOHEADER)}; bi.biWidth = cr.right-cr.left+1; bi.biHeight = GetFrameHeight()+1; bi.biPlanes = 1; bi.biBitCount = 32; COLORREF *pPixels = NULL; HDC hdcTmp = CreateCompatibleDC(hdc); HBITMAP hTmp = CreateDIBSection(hdcTmp, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&pPixels, NULL, 0); if (hTmp == NULL) { _ASSERTE(hTmp == NULL); BitBlt(hdc, cr.left, cr.top, nWidth, nHeight, hdcPaint, 0, 0, SRCCOPY); } else { HBITMAP hOldTmp = (HBITMAP)SelectObject(hdcTmp, hTmp); BitBlt(hdcTmp, 0, 0, bi.biWidth, bi.biHeight, hdcPaint, 0, 0, SRCCOPY); int i = 0; for (int y = 0; y < bi.biHeight; y++) { for (int x = 0; x < bi.biWidth; x++) { pPixels[i++] |= 0xFF000000; } } BitBlt(hdc, cr.left, cr.top, bi.biWidth, bi.biHeight, hdcTmp, 0, 0, SRCCOPY); if (nHeight > bi.biHeight) BitBlt(hdc, cr.left, cr.top+bi.biHeight, nWidth, nHeight-bi.biHeight, hdcPaint, 0, bi.biHeight, SRCCOPY); SelectObject(hdcTmp, hOldTmp); DeleteObject(hbmp); } DeleteDC(hdcTmp); } SelectObject(hdcPaint, hOldBmp); DeleteObject(hbmp); DeleteDC(hdcPaint); } #endif return 0; }
DWORD WINAPI DebugThread(LPVOID lpvParam) { DWORD nWait = WAIT_TIMEOUT; wchar_t szInfo[1024]; wchar_t szPID[20]; int iAttachedCount = 0; CEStr szOtherBitPids, szOtherDebugCmd; // Дополнительная инициализация, чтобы закрытие дебагера (наш процесс) не привело // к закрытию "отлаживаемой" программы pfnDebugActiveProcessStop = (FDebugActiveProcessStop)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"DebugActiveProcessStop"); pfnDebugSetProcessKillOnExit = (FDebugSetProcessKillOnExit)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"DebugSetProcessKillOnExit"); // Affect GetProcessHandleForDebug gpSrv->DbgInfo.bDebuggerActive = TRUE; // If dump was requested if (gpSrv->DbgInfo.nDebugDumpProcess) { gpSrv->DbgInfo.bUserRequestDump = TRUE; } // "/DEBUGEXE" or "/DEBUGTREE" if (gpSrv->DbgInfo.pszDebuggingCmdLine != NULL) { STARTUPINFO si = {sizeof(si)}; PROCESS_INFORMATION pi = {}; if (gpSrv->DbgInfo.bDebugProcessTree) { SetEnvironmentVariable(ENV_CONEMU_BLOCKCHILDDEBUGGERS_W, ENV_CONEMU_BLOCKCHILDDEBUGGERS_YES); } if (!CreateProcess(NULL, gpSrv->DbgInfo.pszDebuggingCmdLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE| DEBUG_PROCESS | (gpSrv->DbgInfo.bDebugProcessTree ? 0 : DEBUG_ONLY_THIS_PROCESS), NULL, NULL, &si, &pi)) { DWORD dwErr = GetLastError(); wchar_t szProc[64]; szProc[0] = 0; PROCESSENTRY32 pi = {sizeof(pi)}; if (GetProcessInfo(gpSrv->dwRootProcess, &pi)) _wcscpyn_c(szProc, countof(szProc), pi.szExeFile, countof(szProc)); _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't start debugging process. ErrCode=0x%08X\n", dwErr); CEStr lsInfo(lstrmerge(szInfo, gpSrv->DbgInfo.pszDebuggingCmdLine, L"\n")); _wprintf(lsInfo); return CERR_CANTSTARTDEBUGGER; } gpSrv->hRootProcess = pi.hProcess; gpSrv->hRootThread = pi.hThread; gpSrv->dwRootProcess = pi.dwProcessId; gpSrv->dwRootThread = pi.dwThreadId; gpSrv->dwRootStartTime = GetTickCount(); // Let's know that at least one process is debugging iAttachedCount++; } /* ************************* */ int iDbgIdx = 0; bool bSetKillOnExit = true; while (true) { HANDLE hDbgProcess = NULL; DWORD nDbgProcessID = 0; if ((iDbgIdx++) == 0) { hDbgProcess = gpSrv->hRootProcess; nDbgProcessID = gpSrv->dwRootProcess; } else { // Взять из pDebugAttachProcesses if (!gpSrv->DbgInfo.pDebugAttachProcesses) break; if (!gpSrv->DbgInfo.pDebugAttachProcesses->pop_back(nDbgProcessID)) break; hDbgProcess = GetProcessHandleForDebug(nDbgProcessID); if (!hDbgProcess) { _ASSERTE(hDbgProcess!=NULL && "Can't open debugging process handle"); continue; } } _ASSERTE(hDbgProcess!=NULL && "Process handle must be opened"); // Битность отладчика должна соответствовать битности приложения! if (IsWindows64()) { int nBits = GetProcessBits(nDbgProcessID, hDbgProcess); if ((nBits == 32 || nBits == 64) && (nBits != WIN3264TEST(32,64))) { // If /DEBUGEXE or /DEBUGTREE was used if (gpSrv->DbgInfo.pszDebuggingCmdLine != NULL) { _printf("Bitness of ConEmuC and debugging program does not match\n"); continue; } // Добавить процесс в список для запуска альтернативного дебаггера соотвествующей битности // Force trailing "," even if only one PID specified ( --> bDebugMultiProcess = TRUE) lstrmerge(&szOtherBitPids.ms_Arg, _itow(nDbgProcessID, szPID, 10), L","); // Может там еще процессы в списке на дамп? continue; } } if (gpSrv->DbgInfo.pszDebuggingCmdLine == NULL) { if (DebugActiveProcess(nDbgProcessID)) { iAttachedCount++; } else { DWORD dwErr = GetLastError(); wchar_t szProc[64]; szProc[0] = 0; PROCESSENTRY32 pi = {sizeof(pi)}; if (GetProcessInfo(nDbgProcessID, &pi)) _wcscpyn_c(szProc, countof(szProc), pi.szExeFile, countof(szProc)); _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't attach debugger to '%s' PID=%i. ErrCode=0x%08X\n", szProc[0] ? szProc : L"not found", nDbgProcessID, dwErr); _wprintf(szInfo); // Может другие подцепить получится? continue; } } // To avoid debugged processes killing if (bSetKillOnExit && pfnDebugSetProcessKillOnExit) { // affects all current and future debuggees connected to the calling thread if (pfnDebugSetProcessKillOnExit(FALSE/*KillOnExit*/)) { bSetKillOnExit = false; } } } // Different bitness, need to start appropriate debugger if (szOtherBitPids.ms_Arg && *szOtherBitPids.ms_Arg) { wchar_t szExe[MAX_PATH+5], *pszName; if (!GetModuleFileName(NULL, szExe, MAX_PATH)) { _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"GetModuleFileName(NULL) failed. ErrCode=0x%08X\n", GetLastError()); _wprintf(szInfo); } else if (!(pszName = (wchar_t*)PointToName(szExe))) { _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"GetModuleFileName(NULL) returns invalid path\n%s\n", szExe); _wprintf(szInfo); } else { *pszName = 0; // Reverted to current bitness wcscat_c(szExe, WIN3264TEST(L"ConEmuC64.exe", L"ConEmuC.exe")); szOtherDebugCmd.Attach(lstrmerge(L"\"", szExe, L"\" " L"/DEBUGPID=", szOtherBitPids.ms_Arg, (gpSrv->DbgInfo.nDebugDumpProcess == 1) ? L" /DUMP" : (gpSrv->DbgInfo.nDebugDumpProcess == 2) ? L" /MINIDUMP" : (gpSrv->DbgInfo.nDebugDumpProcess == 3) ? L" /FULLDUMP" : L"")); STARTUPINFO si = {sizeof(si)}; PROCESS_INFORMATION pi = {}; if (CreateProcess(NULL, szOtherDebugCmd.ms_Arg, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi)) { // Ждать не будем } else { DWORD dwErr = GetLastError(); _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Can't start external debugger, ErrCode=0x%08X\n", dwErr); CEStr lsInfo(lstrmerge(szInfo, szOtherDebugCmd, L"\n")); _wprintf(lsInfo); } } } //_ASSERTE(FALSE && "Continue to dump"); // If neither /DEBUG[EXE|TREE] nor /DEBUGPID was not succeeded if (iAttachedCount == 0) { gpSrv->DbgInfo.bDebuggerActive = FALSE; return CERR_CANTSTARTDEBUGGER; } else if (iAttachedCount > 1) { _ASSERTE(gpSrv->DbgInfo.bDebugMultiProcess && "Already must be set from arguments parser"); gpSrv->DbgInfo.bDebugMultiProcess = TRUE; } if (gpSrv->DbgInfo.bUserRequestDump) { gpSrv->DbgInfo.nWaitTreeBreaks = iAttachedCount; } /* **************** */ // To avoid debugged processes killing (JIC, must be called already) if (bSetKillOnExit && pfnDebugSetProcessKillOnExit) { // affects all current and future debuggees connected to the calling thread if (pfnDebugSetProcessKillOnExit(FALSE/*KillOnExit*/)) { bSetKillOnExit = false; } } PrintDebugInfo(); SetEvent(gpSrv->DbgInfo.hDebugReady); while (nWait == WAIT_TIMEOUT) { ProcessDebugEvent(); if (ghExitQueryEvent) nWait = WaitForSingleObject(ghExitQueryEvent, 0); } //done: gbRootAliveLess10sec = FALSE; gbInShutdown = TRUE; gbAlwaysConfirmExit = FALSE; _ASSERTE(gbTerminateOnCtrlBreak==FALSE); if (!nExitQueryPlace) nExitQueryPlace = 12+(nExitPlaceStep); SetTerminateEvent(ste_DebugThread); return 0; }
// Не интересуется результатом команды! BOOL CConEmuPipe::Execute(int nCmd, LPCVOID apData, UINT anDataSize) { WARNING("Если указан mdw_Timeout - создать нить и выполнять команду в ней. Ожидать нить не более и прибить ее, если пришел Timeout"); MCHKHEAP if (nCmd<(int)CMD_FIRST_FAR_CMD || nCmd>(int)CMD_LAST_FAR_CMD) { TCHAR szError[128]; _wsprintf(szError, SKIPLEN(countof(szError)) _T("Invalid command id (%i)!"), nCmd); MBoxA(szError); return FALSE; } #ifdef _DEBUG WCHAR szMsg[64]; _wsprintf(szMsg, SKIPLEN(countof(szMsg)) _T("Pipe:Execute(%i)\n"), nCmd); DEBUGSTR(szMsg); #endif int nAllSize = sizeof(CESERVER_REQ_HDR)+anDataSize; CESERVER_REQ* pIn = ExecuteNewCmd(nCmd, nAllSize); if (!pIn) { _ASSERTE(pIn!=NULL); TCHAR szError[128]; _wsprintf(szError, SKIPLEN(countof(szError)) _T("Pipe: Can't allocate memory (%i) bytes, Cmd = %i!"), nAllSize, nCmd); MBoxA(szError); Close(); return FALSE; } if (apData && anDataSize) { memmove(pIn->Data, apData, anDataSize); } DWORD dwTickStart = timeGetTime(); BYTE cbReadBuf[512]; BOOL fSuccess; DWORD cbRead, dwErr; // Send a message to the pipe server and read the response. fSuccess = TransactNamedPipe( mh_Pipe, // pipe handle pIn, // message to server pIn->hdr.cbSize, // message length cbReadBuf, // buffer to receive reply sizeof(cbReadBuf), // size of read buffer &cbRead, // bytes read NULL); // not overlapped dwErr = GetLastError(); gpSetCls->debugLogCommand(pIn, FALSE, dwTickStart, timeGetTime()-dwTickStart, ms_PipeName); if (!fSuccess && dwErr == ERROR_BROKEN_PIPE) { // Плагин не вернул данных, но обработал команду Close(); return TRUE; } else if (!fSuccess && (dwErr != ERROR_MORE_DATA)) { DEBUGSTR(L" - FAILED!\n"); TCHAR szError[128]; _wsprintf(szError, SKIPLEN(countof(szError)) _T("Pipe: TransactNamedPipe failed, Cmd = %i, ErrCode = 0x%08X!"), nCmd, dwErr); MBoxA(szError); Close(); return FALSE; } if (cbRead < sizeof(DWORD)) { pOut = NULL; Close(); return FALSE; } pOut = (CESERVER_REQ*)cbReadBuf; // Проверка размера if (pOut->hdr.cbSize <= sizeof(pOut->hdr)) { _ASSERTE(pOut->hdr.cbSize == 0); pOut = NULL; Close(); return FALSE; } if (pOut->hdr.nVersion != CESERVER_REQ_VER) { gpConEmu->ReportOldCmdVersion(pOut->hdr.nCmd, pOut->hdr.nVersion, -1, pOut->hdr.nSrcPID, pOut->hdr.hModule, pOut->hdr.nBits); pOut = NULL; Close(); return FALSE; } nAllSize = pOut->hdr.cbSize; pOut = NULL; if (nAllSize==0) { DEBUGSTR(L" - FAILED!\n"); DisplayLastError(L"Empty data recieved from server", 0); Close(); return FALSE; } pOut = (CESERVER_REQ*)calloc(nAllSize,1); _ASSERTE(pOut!=NULL); memmove(pOut, cbReadBuf, cbRead); _ASSERTE(pOut->hdr.nVersion==CESERVER_REQ_VER); LPBYTE ptrData = ((LPBYTE)pOut)+cbRead; nAllSize -= cbRead; while(nAllSize>0) { //_tprintf(TEXT("%s\n"), chReadBuf); // Break if TransactNamedPipe or ReadFile is successful if (fSuccess) break; // Read from the pipe if there is more data in the message. fSuccess = ReadFile( mh_Pipe, // pipe handle ptrData, // buffer to receive reply nAllSize, // size of buffer &cbRead, // number of bytes read NULL); // not overlapped // Exit if an error other than ERROR_MORE_DATA occurs. if (!fSuccess && (GetLastError() != ERROR_MORE_DATA)) break; ptrData += cbRead; nAllSize -= cbRead; } TODO("Может возникнуть ASSERT, если консоль была закрыта в процессе чтения"); _ASSERTE(nAllSize==0); SafeCloseHandle(mh_Pipe); SafeFree(pIn); lpCursor = pOut->Data; dwMaxDataSize = pOut->hdr.cbSize - sizeof(CESERVER_REQ_HDR); return TRUE; }
// // Wrapper around WM_SETCONSOLEINFO. We need to create the // necessary section (file-mapping) object in the context of the // process which owns the console, before posting the message // BOOL SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci) { DWORD dwConsoleOwnerPid, dwCurProcId; PVOID ptrView = 0; DWORD dwLastError=0; WCHAR ErrText[255]; // // Retrieve the process which "owns" the console // dwCurProcId = GetCurrentProcessId(); DEBUGTEST(DWORD dwConsoleThreadId =) GetWindowThreadProcessId(hwndConsole, &dwConsoleOwnerPid); // We'll fail, if console was created by other process if (dwConsoleOwnerPid != dwCurProcId) { #ifdef _DEBUG // Wine related PROCESSENTRY32W pi = {}; GetProcessInfo(dwConsoleOwnerPid, &pi); if (lstrcmpi(pi.szExeFile, L"wineconsole.exe")!=0) { wchar_t szDbgMsg[512], szTitle[128]; szDbgMsg[0] = 0; GetModuleFileName(NULL, szDbgMsg, countof(szDbgMsg)); msprintf(szTitle, countof(szTitle), L"%s: PID=%u", PointToName(szDbgMsg), GetCurrentProcessId()); msprintf(szDbgMsg, countof(szDbgMsg), L"GetWindowThreadProcessId()\nPID=%u, TID=%u, %s\n%s", dwConsoleOwnerPid, dwConsoleThreadId, pi.szExeFile, szTitle); MessageBox(NULL, szDbgMsg, szTitle, MB_SYSTEMMODAL); } //_ASSERTE(dwConsoleOwnerPid == dwCurProcId); #endif return FALSE; } // // Create a SECTION object backed by page-file, then map a view of // this section into the owner process so we can write the contents // of the CONSOLE_INFO buffer into it // if (!ghConsoleSection) { ghConsoleSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, gnConsoleSectionSize, 0); if (!ghConsoleSection) { dwLastError = GetLastError(); _wsprintf(ErrText, SKIPLEN(countof(ErrText)) L"Can't CreateFileMapping(ghConsoleSection). ErrCode=%i", dwLastError); MessageBox(NULL, ErrText, L"ConEmu", MB_OK|MB_ICONSTOP|MB_SETFOREGROUND); return FALSE; } _ASSERTE(OnShutdownConsole==NULL || OnShutdownConsole==ShutdownConsole); OnShutdownConsole = ShutdownConsole; } // // Copy our console structure into the section-object // ptrView = MapViewOfFile(ghConsoleSection, FILE_MAP_WRITE|FILE_MAP_READ, 0, 0, gnConsoleSectionSize); if (!ptrView) { dwLastError = GetLastError(); _wsprintf(ErrText, SKIPLEN(countof(ErrText)) L"Can't MapViewOfFile. ErrCode=%i", dwLastError); MessageBox(NULL, ErrText, L"ConEmu", MB_OK|MB_ICONSTOP|MB_SETFOREGROUND); } else { _ASSERTE(pci->Length==sizeof(CONSOLE_INFO)); //2010-09-19 что-то на XP стало окошко мелькать. // при отсылке WM_SETCONSOLEINFO консоль отображается :( BOOL lbWasVisible = IsWindowVisible(hwndConsole); RECT rcOldPos = {0}, rcAllMonRect = {0}; if (!lbWasVisible) { GetWindowRect(hwndConsole, &rcOldPos); // В много-мониторных конфигурациях координаты на некоторых могут быть отрицательными! rcAllMonRect = GetAllMonitorsWorkspace(); pci->AutoPosition = FALSE; pci->WindowPosX = rcAllMonRect.left - 1280; pci->WindowPosY = rcAllMonRect.top - 1024; } memcpy(ptrView, pci, pci->Length); //-V106 UnmapViewOfFile(ptrView); // Send console window the "update" message DEBUGTEST(LRESULT dwConInfoRc =) SendMessage(hwndConsole, WM_SETCONSOLEINFO, (WPARAM)ghConsoleSection, 0); DEBUGTEST(DWORD dwConInfoErr = GetLastError()); if (!lbWasVisible && IsWindowVisible(hwndConsole)) { //DEBUGTEST(Sleep(10)); apiShowWindow(hwndConsole, SW_HIDE); //SetWindowPos(hwndConsole, NULL, rcOldPos.left, rcOldPos.top, 0,0, SWP_NOSIZE|SWP_NOZORDER); // -- чтобы на некоторых системах не возникала проблема с позиционированием -> {0,0} // Issue 274: Окно реальной консоли позиционируется в неудобном месте SetWindowPos(hwndConsole, NULL, 0, 0, 0,0, SWP_NOSIZE|SWP_NOZORDER); } } return TRUE; }
bool TermX::GetSubstitute(const KEY_EVENT_RECORD& k, wchar_t (&szSubst)[16]) { _ASSERTE(szSubst[0] == 0); static UINT F1Codes[24] = { 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 28, 29, 31, 32, 33, 34, 42, 43, 44, 45 }; typedef DWORD XTermCtrls; const XTermCtrls xtc_Shift = 1, xtc_Alt = 2, xtc_Ctrl = 4, xtc_None = 0; struct processor { XTermCtrls Mods; void SetKey(wchar_t (&szSubst)[16], wchar_t c) { if (!Mods) { //wcscpy_c(szSubst, L"\033O*A"); msprintf(szSubst, countof(szSubst), L"\033O%c", c); } else { msprintf(szSubst, countof(szSubst), L"\033[1;%c%c", Mods+L'1', c); } } } Processor = {xtc_None}; if (k.dwControlKeyState & (SHIFT_PRESSED)) Processor.Mods |= xtc_Shift; if (k.dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) Processor.Mods |= xtc_Alt; if (k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) Processor.Mods |= xtc_Ctrl; switch (k.wVirtualKeyCode) { case VK_UP: Processor.SetKey(szSubst, L'A'); return true; case VK_DOWN: Processor.SetKey(szSubst, L'B'); return true; case VK_RIGHT: Processor.SetKey(szSubst, L'C'); return true; case VK_LEFT: Processor.SetKey(szSubst, L'D'); return true; case VK_F1: case VK_F2: case VK_F3: case VK_F4: case VK_F5: case VK_F6: case VK_F7: case VK_F8: case VK_F9: case VK_F10: case VK_F11: case VK_F12: case VK_F13: case VK_F14: case VK_F15: case VK_F16: case VK_F17: case VK_F18: case VK_F19: case VK_F20: case VK_F21: case VK_F22: case VK_F23: case VK_F24: // "\033[11;*~" .. L"\033[15;*~", and so on: F1Codes[] _wsprintf(szSubst, SKIPCOUNT(szSubst) L"\033[%u;*~", F1Codes[(k.wVirtualKeyCode-VK_F1)]); return true; case VK_INSERT: wcscpy_c(szSubst, L"\033[2;*~"); return true; case VK_HOME: wcscpy_c(szSubst, L"\033[1;*H"); return true; case VK_END: wcscpy_c(szSubst, L"\033[1;*F"); return true; case VK_PRIOR: wcscpy_c(szSubst, L"\033[5;*~"); return true; case VK_NEXT: wcscpy_c(szSubst, L"\033[6;*~"); return true; case VK_DELETE: wcscpy_c(szSubst, L"\033[3;*~"); // ??? return true; case VK_TAB: if (!(k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED|LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))) { wcscpy_c(szSubst, (k.dwControlKeyState & SHIFT_PRESSED) ? L"\033[Z" : L"\t"); } return true; /* NumPad with NumLock ON */ case VK_NUMPAD0: case VK_NUMPAD1: case VK_NUMPAD2: case VK_NUMPAD3: case VK_NUMPAD4: case VK_NUMPAD5: case VK_NUMPAD6: case VK_NUMPAD7: case VK_NUMPAD8: case VK_NUMPAD9: case VK_DECIMAL: // VK_OEM_PERIOD}, // Actually, this may be comma case VK_DIVIDE: case VK_MULTIPLY: case VK_SUBTRACT: case VK_ADD: if (k.uChar.UnicodeChar) { // Just a digits '0'..'9' and symbols +-/*. szSubst[0] = k.uChar.UnicodeChar; szSubst[1] = 0; } return true; } // Ctrl+Char? A-->1, ..., J-->10, ... return false; }
bool GetAliases(wchar_t* asExeName, wchar_t** rsAliases, LPDWORD rnAliasesSize) { bool lbRc = false; DWORD nAliasRC, nAliasErr, nAliasAErr = 0, nSizeA = 0; _ASSERTE(asExeName && rsAliases && rnAliasesSize); _ASSERTE(*rsAliases == NULL); *rnAliasesSize = GetConsoleAliasesLength(asExeName); if (*rnAliasesSize == 0) { lbRc = true; } else { *rsAliases = (wchar_t*)calloc(*rnAliasesSize+2,1); nAliasRC = GetConsoleAliases(*rsAliases,*rnAliasesSize,asExeName); if (nAliasRC) { lbRc = true; } else { nAliasErr = GetLastError(); if (nAliasErr == ERROR_NOT_ENOUGH_MEMORY) { // Попробовать ANSI функции UINT nCP = CP_OEMCP; char szExeName[MAX_PATH+1]; char *pszAliases = NULL; WideCharToMultiByte(nCP,0,asExeName,-1,szExeName,MAX_PATH+1,0,0); nSizeA = GetConsoleAliasesLengthA(szExeName); if (nSizeA) { pszAliases = (char*)calloc(nSizeA+1,1); nAliasRC = GetConsoleAliasesA(pszAliases,nSizeA,szExeName); if (nAliasRC) { lbRc = true; MultiByteToWideChar(nCP,0,pszAliases,nSizeA,*rsAliases,((*rnAliasesSize)/2)+1); } else { nAliasAErr = GetLastError(); } free(pszAliases); } } if (!nAliasRC) { if ((*rnAliasesSize) < 255) { free(*rsAliases); *rsAliases = (wchar_t*)calloc(128,2); } _wsprintf(*rsAliases, SKIPLEN(127) L"\nConEmuC: GetConsoleAliases failed, ErrCode=0x%08X(0x%08X), AliasesLength=%i(%i)\n\n", nAliasErr, nAliasAErr, *rnAliasesSize, nSizeA); } } } return lbRc; }
IXMLDOMDocument* SettingsXML::CreateDomDocument(wchar_t* pszErr /*= NULL*/, size_t cchErrMax /*= 0*/) { HRESULT hr; IXMLDOMDocument* pFile = NULL; static HMODULE hMsXml3 = NULL; typedef HRESULT (__stdcall* DllGetClassObject_t)(REFCLSID rclsid, REFIID riid, LPVOID *ppv); static DllGetClassObject_t lpfnGetClassObject = NULL; wchar_t szDllErr[128] = {}; hr = CoInitialize(NULL); // Если в прошлый раз обломались, и загрузили "msxml3.dll" - то и не дергаться if (hMsXml3 && (hMsXml3 != (HMODULE)INVALID_HANDLE_VALUE)) hr = REGDB_E_CLASSNOTREG; else hr = CoCreateInstance(CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER, //-V519 IID_IXMLDOMDocument, (void**)&pFile); // Если msxml3.dll (Msxml2.DOMDocument.3.0) не зарегистрирована - будет такая ошибка if (FAILED(hr)) // (hr == REGDB_E_CLASSNOTREG) { HRESULT hFact; // Попробовать грузануть ее ручками if (!hMsXml3) { wchar_t szDll[MAX_PATH+16]; struct FindPlaces { LPCWSTR sDir, sSlash; } findPlaces[] = { {gpConEmu->ms_ConEmuExeDir, L"\\"}, {gpConEmu->ms_ConEmuBaseDir, L"\\"}, {L"", L""}, {NULL}}; for (FindPlaces* fp = findPlaces; fp->sDir; fp++) { _wsprintf(szDll, SKIPLEN(countof(szDll)) L"%s%smsxml3.dll", fp->sDir, fp->sSlash); hMsXml3 = LoadLibrary(szDll); hFact = hMsXml3 ? 0 : (HRESULT)GetLastError(); if (hMsXml3) break; //if (!hMsXml3 // && (((DWORD)hFact) == ERROR_MOD_NOT_FOUND // || ((DWORD)hFact) == ERROR_BAD_EXE_FORMAT // || ((DWORD)hFact) == ERROR_FILE_NOT_FOUND)) } //_wsprintf(szDll, SKIPLEN(countof(szDll)) L"%s\\msxml3.dll", gpConEmu->ms_ConEmuExeDir); //hMsXml3 = LoadLibrary(szDll); //hFact = hMsXml3 ? 0 : (HRESULT)GetLastError(); //if (!hMsXml3 // && (((DWORD)hFact) == ERROR_MOD_NOT_FOUND // || ((DWORD)hFact) == ERROR_BAD_EXE_FORMAT // || ((DWORD)hFact) == ERROR_FILE_NOT_FOUND)) //{ // _wsprintf(szDll, SKIPLEN(countof(szDll)) L"%s\\msxml3.dll", gpConEmu->ms_ConEmuBaseDir); // hMsXml3 = LoadLibrary(szDll); // hFact = hMsXml3 ? 0 : (HRESULT)GetLastError(); //} if (!hMsXml3) { hMsXml3 = (HMODULE)INVALID_HANDLE_VALUE; _wsprintf(szDllErr, SKIPLEN(countof(szDllErr)) L"\nLoadLibrary(\"msxml3.dll\") failed\nErrCode=0x%08X", (DWORD)hFact); } } if (hMsXml3 && (hMsXml3 != (HMODULE)INVALID_HANDLE_VALUE)) { if (!lpfnGetClassObject) lpfnGetClassObject = (DllGetClassObject_t)GetProcAddress(hMsXml3, "DllGetClassObject"); if (!lpfnGetClassObject) { hFact = (HRESULT)GetLastError(); _wsprintf(szDllErr, SKIPLEN(countof(szDllErr)) L"\nGetProcAddress(\"DllGetClassObject\") failed\nErrCode=0x%08X", (DWORD)hFact); } else { IClassFactory* pFact = NULL; hFact = lpfnGetClassObject(CLSID_DOMDocument30, IID_IClassFactory, (void**)&pFact); if (SUCCEEDED(hFact) && pFact) { hFact = pFact->CreateInstance(NULL, IID_IXMLDOMDocument, (void**)&pFile); if (SUCCEEDED(hFact)) hr = hFact; else _wsprintf(szDllErr, SKIPLEN(countof(szDllErr)) L"\nCreateInstance(IID_IXMLDOMDocument) failed\nErrCode=0x%08X", (DWORD)hFact); pFact->Release(); } else { _wsprintf(szDllErr, SKIPLEN(countof(szDllErr)) L"\nGetClassObject(CLSID_DOMDocument30) failed\nErrCode=0x%08X", (DWORD)hFact); } } } } if (FAILED(hr) || !pFile) { wchar_t szErr[512]; bool bShowError = (pszErr == NULL); if (pszErr == NULL) { pszErr = szErr; cchErrMax = countof(szErr); } _wsprintf(pszErr, SKIPLEN(cchErrMax) L"XML setting file can not be used!\n" L"Dynamic libraries 'msxml3.dll'/'msxml3r.dll' was not found!\n\n" L"Can't create IID_IXMLDOMDocument!\n" L"ErrCode=0x%08X %s", (DWORD)hr, szDllErr); if (bShowError) { static bool bWarned = false; if (!bWarned) { // Не задалбывать пользователя ошибками. Один раз - и хватит bWarned = true; MBoxError(szErr); } } return NULL; } return pFile; }
void UpdateComspec(ConEmuComspec* pOpt, bool DontModifyPath /*= false*/) { if (!pOpt) { _ASSERTE(pOpt!=NULL); return; } if (pOpt->isUpdateEnv && (pOpt->csType != cst_EnvVar)) { //if (pOpt->csType == cst_AutoTccCmd) -- always, if isUpdateEnv { LPCWSTR pszNew = NULL; switch (pOpt->csBits) { case csb_SameOS: pszNew = IsWindows64() ? pOpt->Comspec64 : pOpt->Comspec32; break; case csb_SameApp: pszNew = WIN3264TEST(pOpt->Comspec32,pOpt->Comspec64); break; case csb_x32: pszNew = pOpt->Comspec32; break; default: _ASSERTE(pOpt->csBits==csb_SameOS || pOpt->csBits==csb_SameApp || pOpt->csBits==csb_x32); pszNew = NULL; } if (pszNew && *pszNew) { #ifdef SHOW_COMSPEC_CHANGE wchar_t szCurrent[MAX_PATH]; GetEnvironmentVariable(L"ComSpec", szCurrent, countof(szCurrent)); if (lstrcmpi(szCurrent, pszNew)) { wchar_t szMsg[MAX_PATH*4], szProc[MAX_PATH] = {}, szPid[MAX_PATH]; GetModuleFileName(NULL, szProc, countof(szProc)); _wsprintf(szPid, SKIPLEN(countof(szPid)) L"PID=%u, '%s'", GetCurrentProcessId(), PointToName(szProc)); _wsprintf(szMsg, SKIPLEN(countof(szMsg)) L"Changing %%ComSpec%% in %s\nCur=%s\nNew=%s", szPid , szCurrent, pszNew); MessageBox(NULL, szMsg, szPid, MB_SYSTEMMODAL); } #endif _ASSERTE(wcschr(pszNew, L'%')==NULL); SetEnvVarExpanded(L"ComSpec", pszNew); } } } if (pOpt->AddConEmu2Path && !DontModifyPath) { if ((pOpt->ConEmuBaseDir[0] == 0) || (pOpt->ConEmuExeDir[0] == 0)) { _ASSERTE(pOpt->ConEmuBaseDir[0] != 0); _ASSERTE(pOpt->ConEmuExeDir[0] != 0); } else { wchar_t* pszCur = GetEnvVar(L"PATH"); if (!pszCur) pszCur = lstrdup(L""); DWORD n = lstrlen(pszCur); wchar_t* pszUpr = lstrdup(pszCur); wchar_t* pszDirUpr = (wchar_t*)malloc(MAX_PATH*sizeof(*pszCur)); MCHKHEAP; if (!pszUpr || !pszDirUpr) { _ASSERTE(pszUpr && pszDirUpr); } else { bool bChanged = false; wchar_t* pszAdd = NULL; CharUpperBuff(pszUpr, n); for (int i = 0; i <= 1; i++) { // Put '%ConEmuExeDir' on first place switch (i) { case 1: if (!(pOpt->AddConEmu2Path & CEAP_AddConEmuExeDir)) continue; pszAdd = pOpt->ConEmuExeDir; break; case 0: if (!(pOpt->AddConEmu2Path & CEAP_AddConEmuBaseDir)) continue; if (lstrcmp(pOpt->ConEmuExeDir, pOpt->ConEmuBaseDir) == 0) continue; // второй раз ту же директорию не добавляем pszAdd = pOpt->ConEmuBaseDir; break; } int nDirLen = lstrlen(pszAdd); lstrcpyn(pszDirUpr, pszAdd, MAX_PATH); CharUpperBuff(pszDirUpr, nDirLen); MCHKHEAP; // Need to find exact match! bool bFound = false; LPCWSTR pszFind = wcsstr(pszUpr, pszDirUpr); while (pszFind) { if (pszFind[nDirLen] == L';' || pszFind[nDirLen] == 0) { // OK, found bFound = true; break; } // Next try (may be partial match of subdirs...) pszFind = wcsstr(pszFind+nDirLen, pszDirUpr); } if (!bFound) { wchar_t* pszNew = lstrmerge(pszAdd, L";", pszCur); if (!pszNew) { _ASSERTE(pszNew && "Failed to reallocate PATH variable"); break; } MCHKHEAP; SafeFree(pszCur); pszCur = pszNew; bChanged = true; // Set flag, check next dir } } MCHKHEAP; if (bChanged) { SetEnvironmentVariable(L"PATH", pszCur); } } MCHKHEAP; SafeFree(pszUpr); SafeFree(pszDirUpr); MCHKHEAP; SafeFree(pszCur); } } }
bool SettingsXML::OpenKey(const wchar_t *regPath, uint access, BOOL abSilent /*= FALSE*/) { _ASSERTE(!gpConEmu->IsResetBasicSettings() || ((access & KEY_WRITE)!=KEY_WRITE)); bool lbRc = false; HRESULT hr = S_OK; wchar_t szErr[512]; szErr[0] = 0; wchar_t szName[MAX_PATH]; const wchar_t* psz = NULL; VARIANT_BOOL bSuccess; IXMLDOMParseError* pErr = NULL; //IXMLDOMNodeList* pList = NULL; IXMLDOMNode* pKey = NULL; IXMLDOMNode* pChild = NULL; VARIANT vt; VariantInit(&vt); bool bAllowCreate = (access & KEY_WRITE) == KEY_WRITE; CloseKey(); // на всякий if (!regPath || !*regPath) { return false; } HANDLE hFile = NULL; DWORD dwAccess = GENERIC_READ; if ((access & KEY_WRITE) == KEY_WRITE) dwAccess |= GENERIC_WRITE; LPCWSTR pszXmlFile; if (m_Storage.pszFile && *m_Storage.pszFile) { pszXmlFile = m_Storage.pszFile; } else { _ASSERTE(m_Storage.pszFile && *m_Storage.pszFile); m_Storage.pszFile = pszXmlFile = gpConEmu->ConEmuXml(); } if (!pszXmlFile || !*pszXmlFile) { return false; } hFile = CreateFile(pszXmlFile, dwAccess, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); // XML-файл отсутсвует if (hFile == INVALID_HANDLE_VALUE) { return false; } else { BY_HANDLE_FILE_INFORMATION bfi = {0}; if (GetFileInformationByHandle(hFile, &bfi)) mb_Empty = (bfi.nFileSizeHigh == 0 && bfi.nFileSizeLow == 0); CloseHandle(hFile); hFile = NULL; if (mb_Empty && bAllowCreate) { hFile = CreateFile(pszXmlFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { LPCSTR pszDefault = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<key name=\"Software\">\r\n\t<key name=\"ConEmu\">\r\n\t</key>\r\n</key>\r\n"; DWORD nLen = lstrlenA(pszDefault); WriteFile(hFile, pszDefault, nLen, &nLen, NULL); CloseHandle(hFile); } hFile = NULL; } } if (mb_Empty && !bAllowCreate) return false; SAFETRY { _ASSERTE(mp_File == NULL); mp_File = CreateDomDocument(szErr, countof(szErr)); if (FAILED(hr) || !mp_File) { //Ошибка уже в szErr //_wsprintf(szErr, SKIPLEN(countof(szErr)) L"Can't create IID_IXMLDOMDocument!\nErrCode=0x%08X", (DWORD)hr); goto wrap; } hr = mp_File->put_preserveWhiteSpace(VARIANT_TRUE); hr = mp_File->put_async(VARIANT_FALSE); // Загрузить xml-ку bSuccess = VARIANT_FALSE; vt.vt = VT_BSTR; vt.bstrVal = ::SysAllocString(pszXmlFile); hr = mp_File->load(vt, &bSuccess); VariantClear(&vt); if (hr == S_FALSE) { mb_Empty = true; // Файл пуст (может только заголовок?) } else if (FAILED(hr) || !bSuccess) { _wsprintf(szErr, SKIPLEN(countof(szErr)) L"Failed to load ConEmu.xml!\nHR=0x%08X\n", (DWORD)hr); hr = mp_File->get_parseError(&pErr); if (pErr) { long errorCode = 0; // Contains the error code of the last parse error. Read-only. long line = 0; // Specifies the line number that contains the error. Read-only. long linepos = 0; // Contains the character position within the line where the error occurred. Read-only. hr = pErr->get_errorCode(&errorCode); hr = pErr->get_line(&line); hr = pErr->get_linepos(&linepos); wsprintf(szErr+_tcslen(szErr), L"XmlErrCode=%i, Line=%i, Pos=%i", errorCode, line, linepos); } goto wrap; } hr = mp_File->QueryInterface(IID_IXMLDOMNode, (void **)&pKey); if (FAILED(hr)) { _wsprintf(szErr, SKIPLEN(countof(szErr)) L"XML: Root node not found!\nErrCode=0x%08X", (DWORD)hr); goto wrap; } mi_Level = 0; while(*regPath) { // Получить следующий токен psz = wcschr(regPath, L'\\'); if (!psz) psz = regPath + _tcslen(regPath); lstrcpyn(szName, regPath, psz-regPath+1); // Найти в структуре XML pChild = FindItem(pKey, L"key", szName, bAllowCreate); pKey->Release(); pKey = pChild; pChild = NULL; mi_Level++; if (!pKey) { if (bAllowCreate) { _wsprintf(szErr, SKIPLEN(countof(szErr)) L"XML: Can't create key <%s>!", szName); } else { //_wsprintf(szErr, SKIPLEN(countof(szErr)) L"XML: key <%s> not found!", szName); szErr[0] = 0; // ошибку не показывать - настройки по умолчанию } goto wrap; } if (*psz == L'\\') { regPath = psz + 1; } else { break; } } // Нашли, запомнили mp_Key = pKey; pKey = NULL; if (mp_Key) { SYSTEMTIME st; wchar_t szTime[32]; GetLocalTime(&st); _wsprintf(szTime, SKIPLEN(countof(szTime)) L"%04i-%02i-%02i %02i:%02i:%02i", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); SetAttr(mp_Key, L"modified", szTime); SetAttr(mp_Key, L"build", gpConEmu->ms_ConEmuBuild); } lbRc = true; } SAFECATCH { lstrcpy(szErr, L"Exception in SettingsXML::OpenKey"); lbRc = false; } wrap: if (pErr) { pErr->Release(); pErr = NULL; } if (pChild) { pChild->Release(); pChild = NULL; } if (pKey) { pKey->Release(); pKey = NULL; } if (!lbRc && szErr[0] && !abSilent) { MBoxA(szErr); } return lbRc; }
int DoInjectHooks(LPWSTR asCmdArg) { gbInShutdown = TRUE; // чтобы не возникло вопросов при выходе gnRunMode = RM_SETHOOK64; LPWSTR pszNext = asCmdArg; LPWSTR pszEnd = NULL; BOOL lbForceGui = FALSE; PROCESS_INFORMATION pi = {NULL}; pi.hProcess = (HANDLE)wcstoul(pszNext, &pszEnd, 16); if (pi.hProcess && pszEnd && *pszEnd) { pszNext = pszEnd+1; pi.dwProcessId = wcstoul(pszNext, &pszEnd, 10); } if (pi.dwProcessId && pszEnd && *pszEnd) { pszNext = pszEnd+1; pi.hThread = (HANDLE)wcstoul(pszNext, &pszEnd, 16); } if (pi.hThread && pszEnd && *pszEnd) { pszNext = pszEnd+1; pi.dwThreadId = wcstoul(pszNext, &pszEnd, 10); } if (pi.dwThreadId && pszEnd && *pszEnd) { pszNext = pszEnd+1; lbForceGui = wcstoul(pszNext, &pszEnd, 10); } #ifdef SHOW_INJECT_MSGBOX wchar_t szDbgMsg[512], szTitle[128]; PROCESSENTRY32 pinf; GetProcessInfo(pi.dwProcessId, &pinf); _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"ConEmuCD PID=%u", GetCurrentProcessId()); _wsprintf(szDbgMsg, SKIPLEN(countof(szDbgMsg)) L"InjectsTo PID=%s {%s}\nConEmuCD PID=%u", asCmdArg ? asCmdArg : L"", pinf.szExeFile, GetCurrentProcessId()); MessageBoxW(NULL, szDbgMsg, szTitle, MB_SYSTEMMODAL); #endif if (pi.hProcess && pi.hThread && pi.dwProcessId && pi.dwThreadId) { // Аргумент abForceGui не использовался CINJECTHK_EXIT_CODES iHookRc = InjectHooks(pi, /*lbForceGui,*/ gbLogProcess); if (iHookRc == CIH_OK/*0*/) { return CERR_HOOKS_WAS_SET; } // Ошибку (пока во всяком случае) лучше показать, для отлова возможных проблем DWORD nErrCode = GetLastError(); //_ASSERTE(iHookRc == 0); -- ассерт не нужен, есть MsgBox wchar_t szDbgMsg[255], szTitle[128]; _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"ConEmuC[%u], PID=%u", WIN3264TEST(32,64), GetCurrentProcessId()); _wsprintf(szDbgMsg, SKIPLEN(countof(szDbgMsg)) L"ConEmuC.X, PID=%u\nInjecting hooks into PID=%u\nFAILED, code=%i:0x%08X", GetCurrentProcessId(), pi.dwProcessId, iHookRc, nErrCode); MessageBoxW(NULL, szDbgMsg, szTitle, MB_SYSTEMMODAL); } else { //_ASSERTE(pi.hProcess && pi.hThread && pi.dwProcessId && pi.dwThreadId); wchar_t szDbgMsg[512], szTitle[128]; _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"ConEmuC, PID=%u", GetCurrentProcessId()); _wsprintf(szDbgMsg, SKIPLEN(countof(szDbgMsg)) L"ConEmuC.X, PID=%u\nCmdLine parsing FAILED (%u,%u,%u,%u,%u)!\n%s", GetCurrentProcessId(), LODWORD(pi.hProcess), LODWORD(pi.hThread), pi.dwProcessId, pi.dwThreadId, lbForceGui, //-V205 asCmdArg); MessageBoxW(NULL, szDbgMsg, szTitle, MB_SYSTEMMODAL); } return CERR_HOOKS_FAILED; }
// IDYES - Close All consoles // IDNO - Close active console only // IDCANCEL - As is int ConfirmCloseConsoles(const ConfirmCloseParam& Parm) { DontEnable de; wchar_t szText[512], *pszText; int nBtn = IDCANCEL; static LONG lCounter = 0; LONG l = InterlockedIncrement(&lCounter); if (l > 1) { if (l == 2) { _ASSERTE(FALSE && "Confirm stack overflow!"); } goto wrap; } if (Parm.rpLeaveConEmuOpened) *Parm.rpLeaveConEmuOpened = false; // Use TaskDialog? if (gOSVer.dwMajorVersion >= 6) { // must be already initialized: CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); wchar_t szMessage[128]; lstrcpyn(szMessage, Parm.asSingleConsole ? Parm.asSingleConsole : Parm.bForceKill ? L"Confirm killing?" : L"Confirm closing?", countof(szMessage)); wchar_t szWWW[MAX_PATH]; _wsprintf(szWWW, SKIPLEN(countof(szWWW)) L"<a href=\"%s\">%s</a>", gsHomePage, gsHomePage); wchar_t szCloseAll[MAX_PATH*2]; wchar_t *pszText; if (Parm.asSingleConsole) { wcscpy_c(szCloseAll, L"Yes\n"); pszText = szCloseAll + _tcslen(szCloseAll); lstrcpyn(pszText, Parm.asSingleTitle, min(MAX_PATH,(countof(szCloseAll)-(pszText-szCloseAll)))); pszText += _tcslen(pszText); } else { _wsprintf(szCloseAll, SKIPLEN(countof(szCloseAll)) (Parm.bGroup && (Parm.nConsoles>1)) ? ((Parm.bGroup == ConfirmCloseParam::eGroup) ? L"Close group (%u console%s)" : L"Close (%u console%s)") : L"Close all %u console%s.", Parm.nConsoles, (Parm.nConsoles>1)?L"s":L""); pszText = szCloseAll + _tcslen(szCloseAll); } if ((Parm.asSingleConsole == NULL) || (Parm.nOperations || Parm.nUnsavedEditors)) { //if (nOperations) { _wsprintf(pszText, SKIPLEN(countof(szCloseAll)-(pszText-szCloseAll)) L"\nIncomplete operations: %i", Parm.nOperations); pszText += _tcslen(pszText); } //if (nUnsavedEditors) { _wsprintf(pszText, SKIPLEN(countof(szCloseAll)-(pszText-szCloseAll)) L"\nUnsaved editor windows: %i", Parm.nUnsavedEditors); pszText += _tcslen(pszText); } } wchar_t szCloseOne[MAX_PATH]; wcscpy_c(szCloseOne, L"Close active console only"); if (Parm.nConsoles > 1) { CVConGuard VCon; int iCon = gpConEmu->GetActiveVCon(&VCon); if (iCon >= 0) { pszText = szCloseOne + _tcslen(szCloseOne); _wsprintf(pszText, SKIPLEN(countof(szCloseOne)-(pszText-szCloseOne)) L"\n#%u: ", (iCon+1)); pszText += _tcslen(pszText); lstrcpyn(pszText, VCon->RCon()->GetTitle(true), countof(szCloseOne)-(pszText-szCloseOne)); } } const wchar_t* szCancel = L"Cancel\nDon't close anything"; int nButtonPressed = 0; TASKDIALOGCONFIG config = {sizeof(config)}; TASKDIALOG_BUTTON buttons[] = { { IDYES, szCloseAll }, { IDNO, szCloseOne }, { IDCANCEL, szCancel }, }; config.cButtons = countof(buttons); if (Parm.nConsoles <= 1) { buttons[1] = buttons[2]; config.cButtons--; } config.hwndParent = ghWnd; config.hInstance = NULL /*g_hInstance*/; config.dwFlags = TDF_USE_HICON_MAIN|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION |TDF_ENABLE_HYPERLINKS; //|TDIF_SIZE_TO_CONTENT|TDF_CAN_BE_MINIMIZED; //config.pszMainIcon = MAKEINTRESOURCE(IDI_ICON1); config.hMainIcon = hClassIcon; config.pszWindowTitle = gpConEmu->GetDefaultTitle(); config.pszMainInstruction = szMessage; //config.pszContent = L"..."; config.pButtons = buttons; config.nDefaultButton = IDYES; config.pszFooter = szWWW; //{ // config.dwFlags |= TDF_VERIFICATION_FLAG_CHECKED; // config.pszVerificationText = L"Text on checkbox"; //} HRESULT hr = TaskDialog(&config, &nButtonPressed, NULL, NULL); if (hr == S_OK) { switch (nButtonPressed) { case IDCANCEL: // user cancelled the dialog case IDYES: case IDNO: nBtn = nButtonPressed; goto wrap; default: _ASSERTE(nButtonPressed==IDCANCEL||nButtonPressed==IDYES||nButtonPressed==IDNO); break; // should never happen } } } // Иначе - через стандартный MessageBox if (Parm.asSingleConsole) { lstrcpyn(szText, Parm.asSingleConsole ? Parm.asSingleConsole : Parm.bForceKill ? L"Confirm killing?" : L"Confirm closing?", min(128,countof(szText))); wcscat_c(szText, L"\r\n\r\n"); int nLen = lstrlen(szText); lstrcpyn(szText+nLen, Parm.asSingleTitle, countof(szText)-nLen); } else { _wsprintf(szText, SKIPLEN(countof(szText)) L"About to close %u console%s.\r\n", Parm.nConsoles, (Parm.nConsoles>1)?L"s":L""); } pszText = szText+_tcslen(szText); if (Parm.nOperations || Parm.nUnsavedEditors) { *(pszText++) = L'\r'; *(pszText++) = L'\n'; *(pszText) = 0; if (Parm.nOperations) { _wsprintf(pszText, SKIPLEN(countof(szText)-(pszText-szText)) L"Incomplete operations: %i\r\n", Parm.nOperations); pszText += _tcslen(pszText); } if (Parm.nUnsavedEditors) { _wsprintf(pszText, SKIPLEN(countof(szText)-(pszText-szText)) L"Unsaved editor windows: %i\r\n", Parm.nUnsavedEditors); pszText += _tcslen(pszText); } } if (Parm.nConsoles > 1) { wcscat_c(szText, L"\r\nPress button <No> to close active console only\r\n" L"\r\nProceed with close ConEmu?"); } nBtn = MsgBox(szText, (/*rpPanes ? MB_OKCANCEL :*/ (Parm.nConsoles>1) ? MB_YESNOCANCEL : MB_OKCANCEL)|MB_ICONEXCLAMATION, gpConEmu->GetDefaultTitle(), ghWnd); if (nBtn == IDOK) { nBtn = IDYES; // для однозначности } wrap: InterlockedDecrement(&lCounter); return nBtn; }
wchar_t* CreateCommand(LPCWSTR asSource, LPCWSTR asTarget, UINT& iRc) { wchar_t* pszCommand = NULL; if (!szCmdStringFormat || !*szCmdStringFormat) { wchar_t szConEmuC[MAX_PATH] = L"", *psz; wchar_t szOTimeout[20] = L"", szTimeout[20] = L""; if (mb_OTimeout) _wsprintf(szOTimeout, SKIPCOUNT(szOTimeout) L"%u", mn_OTimeout); if (mb_Timeout) _wsprintf(szTimeout, SKIPCOUNT(szTimeout) L"%u", mn_Timeout); struct _Switches { LPCWSTR pszName, pszValue; } Switches[] = { {L"-login", m_Server.szUser}, {L"-password", m_Server.szPassword}, {L"-proxy", m_Proxy.szProxy}, {L"-proxylogin", m_Proxy.szProxyUser}, {L"-proxypassword", m_Proxy.szProxyPassword}, {L"-async", mb_AsyncMode ? L"Y" : L"N"}, {L"-otimeout", szOTimeout}, {L"-timeout", szTimeout}, }; if (!asSource || !*asSource || !asTarget || !*asTarget) { iRc = E_INVALIDARG; goto wrap; } if (!GetModuleFileName(ghOurModule, szConEmuC, countof(szConEmuC)) || !(psz = wcsrchr(szConEmuC, L'\\'))) { //ReportMessage(dc_LogCallback, L"GetModuleFileName(ghOurModule) failed, code=%u", at_Uint, GetLastError(), at_None); iRc = E_HANDLE; goto wrap; } psz[1] = 0; wcscat_c(szConEmuC, WIN3264TEST(L"ConEmuC.exe",L"ConEmuC64.exe")); /* ConEmuC /download [-login <name> -password <pwd>] [-proxy <address:port> [-proxylogin <name> -proxypassword <pwd>]] [-async Y|N] [-otimeout <ms>] [-timeout <ms>] "full_url_to_file" "local_path_name" */ if (!(pszCommand = lstrmerge(L"\"", szConEmuC, L"\" -download "))) { iRc = E_OUTOFMEMORY; goto wrap; } #if defined(_DEBUG) lstrmerge(&pszCommand, L"-debug "); #endif for (INT_PTR i = 0; i < countof(Switches); i++) { LPCWSTR pszValue = Switches[i].pszValue; if (pszValue && ((*pszValue) || (lstrcmp(Switches[i].pszName, L"-proxy") == 0) // Pass empty string for proxy autoconfig ) && !lstrmerge(&pszCommand, Switches[i].pszName, L" \"", pszValue, L"\" ")) { iRc = E_OUTOFMEMORY; goto wrap; } } if (!lstrmerge(&pszCommand, asSource, L" \"", asTarget, L"\"")) { iRc = E_OUTOFMEMORY; goto wrap; } } else { // Environment string? Expand it wchar_t* pszExp = ExpandEnvStr(szCmdStringFormat); // "curl -L %1 -o %2" // "wget %1 -O %2" LPCWSTR Values[] = {asSource, asTarget}; pszCommand = ExpandMacroValues((pszExp && *pszExp) ? pszExp : szCmdStringFormat, Values, countof(Values)); SafeFree(pszExp); if (!pszCommand) { iRc = E_OUTOFMEMORY; goto wrap; } } wrap: return pszCommand; }
size_t CConEmuCtrl::GetOpenedTabs(CESERVER_REQ_GETALLTABS::TabInfo*& pTabs) { _ASSERTE(pTabs==NULL); int nConCount = gpConEmu->GetConCount(); int nActiveCon = gpConEmu->ActiveConNum(); size_t cchMax = nConCount*16; size_t cchCount = 0; CVirtualConsole* pVCon; pTabs = (CESERVER_REQ_GETALLTABS::TabInfo*)calloc(cchMax, sizeof(*pTabs)); for (int V = 0; (pVCon = gpConEmu->GetVCon(V)) != NULL; V++) { if (!pTabs) { _ASSERTE(pTabs!=NULL); break; } CRealConsole* pRCon = pVCon->RCon(); if (!pRCon) continue; CTab tab; wchar_t szMark[6]; for (int T = 0; pRCon->GetTab(T, tab); T++) { if (cchCount >= cchMax) { pTabs = (CESERVER_REQ_GETALLTABS::TabInfo*)realloc(pTabs, (cchMax+32)*sizeof(*pTabs)); if (!pTabs) { _ASSERTE(pTabs!=NULL); break; } cchMax += 32; _ASSERTE(cchCount<cchMax); } pTabs[cchCount].ActiveConsole = (V == nActiveCon); pTabs[cchCount].ActiveTab = ((tab->Flags() & fwt_CurrentFarWnd) == fwt_CurrentFarWnd); pTabs[cchCount].Disabled = ((tab->Flags() & fwt_Disabled) == fwt_Disabled); pTabs[cchCount].ConsoleIdx = V; pTabs[cchCount].TabIdx = T; // Text //wcscpy_c(szMark, tab.Modified ? L" * " : L" "); switch (tab->Type()) { case fwt_Editor: wcscpy_c(szMark, (tab->Flags() & fwt_ModifiedFarWnd) ? L" * " : L" E "); break; case fwt_Viewer: wcscpy_c(szMark, L" V "); break; default: wcscpy_c(szMark, L" "); } if (V == nActiveCon) { if (T <= 9) _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/&%i]%s", V+1, T, szMark); //else if (T == 9) // _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/1&0]%s", V+1, szMark); else _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/%i]%s", V+1, T, szMark); } else { _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/%i]%s", V+1, T, szMark); } int nCurLen = lstrlen(pTabs[cchCount].Title); lstrcpyn(pTabs[cchCount].Title+nCurLen, tab->Name.Ptr(), countof(pTabs[cchCount].Title)-nCurLen); cchCount++; } } return cchCount; }
//// Эта функция пайп не закрывает! //void CGuiServer::GuiServerThreadCommand(HANDLE hPipe) BOOL CGuiServer::GuiServerCommand(LPVOID pInst, CESERVER_REQ* pIn, CESERVER_REQ* &ppReply, DWORD &pcbReplySize, DWORD &pcbMaxReplySize, LPARAM lParam) { BOOL lbRc = FALSE; CGuiServer* pGSrv = (CGuiServer*)lParam; if (!pGSrv) { _ASSERTE(((CGuiServer*)lParam)!=NULL); pGSrv = &gpConEmu->m_GuiServer; } if (pIn->hdr.bAsync) pGSrv->mp_GuiServer->BreakConnection(pInst); gpSetCls->debugLogCommand(pIn, TRUE, timeGetTime(), 0, pGSrv ? pGSrv->ms_ServerPipe : NULL); #ifdef _DEBUG UINT nDataSize = pIn->hdr.cbSize - sizeof(CESERVER_REQ_HDR); #endif // Все данные из пайпа получены, обрабатываем команду и возвращаем (если нужно) результат #ifdef ALLOW_WINE_MSG if (gbIsWine) { wchar_t szMsg[128]; msprintf(szMsg, countof(szMsg), L"CGuiServer::GuiServerCommand.\nGUI TID=%u\nSrcPID=%u, SrcTID=%u, Cmd=%u", GetCurrentThreadId(), pIn->hdr.nSrcPID, pIn->hdr.nSrcThreadId, pIn->hdr.nCmd); MessageBox(szMsg, MB_ICONINFORMATION); } #endif switch (pIn->hdr.nCmd) { case CECMD_NEWCMD: { // Приходит из другой копии ConEmu.exe, когда она запущена с ключом /single, /showhide, /showhideTSA DEBUGSTR(L"GUI recieved CECMD_NEWCMD\n"); if (pIn->NewCmd.isAdvLogging && !gpSetCls->isAdvLogging) { gpSetCls->isAdvLogging = pIn->NewCmd.isAdvLogging; gpConEmu->CreateLog(); } if (gpSetCls->isAdvLogging && (pIn->NewCmd.isAdvLogging > gpSetCls->isAdvLogging)) { wchar_t szLogLevel[80]; _wsprintf(szLogLevel, SKIPLEN(countof(szLogLevel)) L"Changing log level! Old=%u, New=%u", (UINT)gpSetCls->isAdvLogging, (UINT)pIn->NewCmd.isAdvLogging); gpConEmu->LogString(szLogLevel); gpSetCls->isAdvLogging = pIn->NewCmd.isAdvLogging; } if (gpSetCls->isAdvLogging) { size_t cchAll = 120 + _tcslen(pIn->NewCmd.szConEmu) + _tcslen(pIn->NewCmd.szCurDir) + _tcslen(pIn->NewCmd.szCommand); wchar_t* pszInfo = (wchar_t*)malloc(cchAll*sizeof(*pszInfo)); if (pszInfo) { _wsprintf(pszInfo, SKIPLEN(cchAll) L"CECMD_NEWCMD: Wnd=x%08X, Act=%u, ConEmu=%s, Dir=%s, Cmd=%s", (DWORD)(DWORD_PTR)pIn->NewCmd.hFromConWnd, pIn->NewCmd.ShowHide, pIn->NewCmd.szConEmu, pIn->NewCmd.szCurDir, pIn->NewCmd.szCommand); gpConEmu->LogString(pszInfo); free(pszInfo); } } BOOL bAccepted = FALSE; if (pIn->NewCmd.szConEmu[0]) { bAccepted = (lstrcmpi(gpConEmu->ms_ConEmuExeDir, pIn->NewCmd.szConEmu) == 0); } else { bAccepted = TRUE; } if (bAccepted) { bool bCreateTab = (pIn->NewCmd.ShowHide == sih_None || pIn->NewCmd.ShowHide == sih_StartDetached) // Issue 1275: When minimized into TSA (on all VCon are closed) we need to restore and run new tab || (pIn->NewCmd.szCommand[0] && !CVConGroup::isVConExists(0)); gpConEmu->DoMinimizeRestore(bCreateTab ? sih_SetForeground : pIn->NewCmd.ShowHide); // Может быть пусто if (bCreateTab && pIn->NewCmd.szCommand[0]) { RConStartArgs *pArgs = new RConStartArgs; pArgs->bDetached = (pIn->NewCmd.ShowHide == sih_StartDetached); pArgs->pszSpecialCmd = lstrdup(pIn->NewCmd.szCommand); if (pIn->NewCmd.szCurDir[0] == 0) { _ASSERTE(pIn->NewCmd.szCurDir[0] != 0); } else { pArgs->pszStartupDir = lstrdup(pIn->NewCmd.szCurDir); } if (gpSetCls->IsMulti() || CVConGroup::isDetached()) { gpConEmu->PostCreateCon(pArgs); } else { // Если хотят в одном окне - только одну консоль gpConEmu->CreateWnd(pArgs); SafeDelete(pArgs); } } else { _ASSERTE(pIn->NewCmd.ShowHide==sih_ShowMinimize || pIn->NewCmd.ShowHide==sih_ShowHideTSA || pIn->NewCmd.ShowHide==sih_Show); } } pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(BYTE); lbRc = ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize); if (lbRc) { ppReply->Data[0] = bAccepted; } break; } //CECMD_NEWCMD case CECMD_TABSCMD: { // 0: спрятать/показать табы, 1: перейти на следующую, 2: перейти на предыдущую, 3: commit switch DEBUGSTR(L"GUI recieved CECMD_TABSCMD\n"); _ASSERTE(nDataSize>=1); DWORD nTabCmd = pIn->Data[0]; gpConEmu->TabCommand((ConEmuTabCommand)nTabCmd); pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(BYTE); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->Data[0] = TRUE; } break; } // CECMD_TABSCMD #if 0 case CECMD_GETALLTABS: { int nConCount = gpConEmu->GetConCount(); int nActiveCon = gpConEmu->ActiveConNum(); size_t cchMax = nConCount*16; size_t cchCount = 0; CVirtualConsole* pVCon; CESERVER_REQ_GETALLTABS::TabInfo* pTabs = (CESERVER_REQ_GETALLTABS::TabInfo*)calloc(cchMax, sizeof(*pTabs)); for (int V = 0; (pVCon = gpConEmu->GetVCon(V)) != NULL; V++) { if (!pTabs) { _ASSERTE(pTabs!=NULL); break; } CRealConsole* pRCon = pVCon->RCon(); if (!pRCon) continue; ConEmuTab tab; wchar_t szModified[4]; for (int T = 0; pRCon->GetTab(T, &tab); T++) { if (cchCount >= cchMax) { pTabs = (CESERVER_REQ_GETALLTABS::TabInfo*)realloc(pTabs, (cchMax+32)*sizeof(*pTabs)); if (!pTabs) { _ASSERTE(pTabs!=NULL); break; } cchMax += 32; _ASSERTE(cchCount<cchMax); } pTabs[cchCount].ActiveConsole == (V == nActiveCon); pTabs[cchCount].ActiveTab == (tab.Current != 0); pTabs[cchCount].Disabled = ((tab.Type & fwt_Disabled) == fwt_Disabled); pTabs[cchCount].ConsoleIdx = V; pTabs[cchCount].TabIdx = T; // Text wcscpy_c(szModified, tab.Modified ? L" * " : L" "); if (V == nActiveCon) { if (T < 9) _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/&%i]%s", V+1, T+1, szModified); else if (T == 9) _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/1&0]%s", V+1, szModified); else _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/%i]%s", V+1, T+1, szModified); } else { _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/%i]%s", V+1, T+1, szModified); } cchCount++; } } if (cchCount && pTabs) { pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_GETALLTABS)+((cchCount-1)*sizeof(CESERVER_REQ_GETALLTABS::TabInfo)); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->GetAllTabs.Count = cchCount; memmove(ppReply->GetAllTabs.Tabs, pTabs, cchCount*sizeof(*pTabs)); } } SafeFree(pTabs); break; } // CECMD_GETALLTABS case CECMD_ACTIVATETAB: { BOOL lbTabOk = FALSE; CVirtualConsole *pVCon = gpConEmu->GetVCon(pIn->dwData[0]); if (pVCon && pVCon->RCon()) { lbTabOk = pVCon->RCon()->ActivateFarWindow(pIn->dwData[1]); } pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = lbTabOk; } break; } // CECMD_ACTIVATETAB #endif case CECMD_ATTACH2GUI: { // Получен запрос на Attach из сервера pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_STARTSTOPRET); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; //CESERVER_REQ* pOut = ExecuteNewCmd(CECMD_ATTACH2GUI, sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_STARTSTOPRET)); gpConEmu->AttachRequested(pIn->StartStop.hWnd, &(pIn->StartStop), &(ppReply->StartStopRet)); _ASSERTE((ppReply->StartStopRet.nBufferHeight == 0) || ((int)ppReply->StartStopRet.nBufferHeight > (pIn->StartStop.sbi.srWindow.Bottom-pIn->StartStop.sbi.srWindow.Top))); lbRc = TRUE; //ExecuteFreeResult(pOut); break; } // CECMD_ATTACH2GUI case CECMD_SRVSTARTSTOP: { pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_STARTSTOPRET); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; if (pIn->SrvStartStop.Started == srv_Started) { // Запущен процесс сервера HWND hConWnd = (HWND)pIn->dwData[1]; _ASSERTE(hConWnd && IsWindow(hConWnd)); DWORD nStartTick = timeGetTime(); //LRESULT l = 0; //DWORD_PTR dwRc = 0; //2010-05-21 Поскольку это критично - лучше ждать до упора, хотя может быть DeadLock? //l = SendMessageTimeout(ghWnd, gpConEmu->mn_MsgSrvStarted, (WPARAM)hConWnd, pIn->hdr.nSrcPID, // SMTO_BLOCK, 5000, &dwRc); //111002 - вернуть должен HWND окна отрисовки (дочернее окно ConEmu) MsgSrvStartedArg arg = {hConWnd, pIn->hdr.nSrcPID, pIn->SrvStartStop.dwKeybLayout, nStartTick}; SendMessage(ghWnd, gpConEmu->mn_MsgSrvStarted, 0, (LPARAM)&arg); HWND hWndDC = arg.hWndDc; HWND hWndBack = arg.hWndBack; _ASSERTE(hWndDC!=NULL); #ifdef _DEBUG DWORD dwErr = GetLastError(), nEndTick = timeGetTime(), nDelta = nEndTick - nStartTick; if (hWndDC && nDelta >= EXECUTE_CMD_WARN_TIMEOUT) { if (!IsDebuggerPresent()) { //_ASSERTE(nDelta <= EXECUTE_CMD_WARN_TIMEOUT || (pIn->hdr.nCmd == CECMD_CMDSTARTSTOP && nDelta <= EXECUTE_CMD_WARN_TIMEOUT2)); _ASSERTEX(nDelta <= EXECUTE_CMD_WARN_TIMEOUT); } } #endif //pIn->dwData[0] = (DWORD)ghWnd; //-V205 //pIn->dwData[1] = (DWORD)dwRc; //-V205 //pIn->dwData[0] = (l == 0) ? 0 : 1; ppReply->StartStopRet.hWnd = ghWnd; ppReply->StartStopRet.hWndDc = hWndDC; ppReply->StartStopRet.hWndBack = hWndBack; ppReply->StartStopRet.dwPID = GetCurrentProcessId(); } else if (pIn->SrvStartStop.Started == srv_Stopped) { // Процесс сервера завершается CRealConsole* pRCon = NULL; CVConGuard VCon; for (size_t i = 0;; i++) { if (!CVConGroup::GetVCon(i, &VCon)) break; pRCon = VCon->RCon(); if (pRCon && (pRCon->GetServerPID(true) == pIn->hdr.nSrcPID || pRCon->GetServerPID(false) == pIn->hdr.nSrcPID)) { break; } pRCon = NULL; } if (pRCon) pRCon->OnServerClosing(pIn->hdr.nSrcPID); //pIn->dwData[0] = 1; } else { _ASSERTE((pIn->dwData[0] == 1) || (pIn->dwData[0] == 101)); } lbRc = TRUE; //// Отправляем //fSuccess = WriteFile( // hPipe, // handle to pipe // pOut, // buffer to write from // pOut->hdr.cbSize, // number of bytes to write // &cbWritten, // number of bytes written // NULL); // not overlapped I/O //ExecuteFreeResult(pOut); break; } // CECMD_SRVSTARTSTOP case CECMD_ASSERT: { DWORD nBtn = MessageBox(NULL, pIn->AssertInfo.szDebugInfo, pIn->AssertInfo.szTitle, pIn->AssertInfo.nBtns); pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = nBtn; } //ExecutePrepareCmd(&pIn->hdr, CECMD_ASSERT, sizeof(CESERVER_REQ_HDR) + sizeof(DWORD)); //pIn->dwData[0] = nBtn; //// Отправляем //fSuccess = WriteFile( // hPipe, // handle to pipe // pIn, // buffer to write from // pIn->hdr.cbSize, // number of bytes to write // &cbWritten, // number of bytes written // NULL); // not overlapped I/O break; } // CECMD_ASSERT case CECMD_ATTACHGUIAPP: { pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_ATTACHGUIAPP); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; ppReply->AttachGuiApp = pIn->AttachGuiApp; //CESERVER_REQ Out; //ExecutePrepareCmd(&Out.hdr, CECMD_ATTACHGUIAPP, sizeof(CESERVER_REQ_HDR)+sizeof(Out.AttachGuiApp)); //Out.AttachGuiApp = pIn->AttachGuiApp; #ifdef SHOW_GUIATTACH_START if (pIn->AttachGuiApp.hWindow == NULL) { wchar_t szDbg[1024]; _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"AttachGuiApp requested from:\n%s\nPID=%u", pIn->AttachGuiApp.sAppFileName, pIn->AttachGuiApp.nPID); //MBoxA(szDbg); MessageBox(NULL, szDbg, L"ConEmu", MB_SYSTEMMODAL); } #endif // Уведомить ожидающую вкладку CRealConsole* pRCon = gpConEmu->AttachRequestedGui(pIn->AttachGuiApp.sAppFileName, pIn->AttachGuiApp.nPID); if (pRCon) { CVConGuard VCon(pRCon->VCon()); RECT rcPrev = ppReply->AttachGuiApp.rcWindow; HWND hBack = pRCon->VCon()->GetBack(); //// Размер должен быть независим от возможности наличия прокрутки в VCon //GetWindowRect(hBack, &ppReply->AttachGuiApp.rcWindow); //ppReply->AttachGuiApp.rcWindow.right -= ppReply->AttachGuiApp.rcWindow.left; //ppReply->AttachGuiApp.rcWindow.bottom -= ppReply->AttachGuiApp.rcWindow.top; //ppReply->AttachGuiApp.rcWindow.left = ppReply->AttachGuiApp.rcWindow.top = 0; ////MapWindowPoints(NULL, hBack, (LPPOINT)&ppReply->AttachGuiApp.rcWindow, 2); //pRCon->CorrectGuiChildRect(ppReply->AttachGuiApp.nStyle, ppReply->AttachGuiApp.nStyleEx, ppReply->AttachGuiApp.rcWindow); // Уведомить RCon и ConEmuC, что гуй подцепился // Вызывается два раза. Первый (при запуске exe) ahGuiWnd==NULL, второй - после фактического создания окна pRCon->SetGuiMode(pIn->AttachGuiApp.nFlags, pIn->AttachGuiApp.hAppWindow, pIn->AttachGuiApp.Styles.nStyle, pIn->AttachGuiApp.Styles.nStyleEx, pIn->AttachGuiApp.sAppFileName, pIn->AttachGuiApp.nPID, rcPrev); ppReply->AttachGuiApp.nFlags = agaf_Success | (pRCon->isActive(false) ? 0 : agaf_Inactive); ppReply->AttachGuiApp.nPID = pRCon->GetServerPID(); ppReply->AttachGuiApp.hConEmuDc = pRCon->GetView(); ppReply->AttachGuiApp.hConEmuBack = hBack; ppReply->AttachGuiApp.hConEmuWnd = ghWnd; ppReply->AttachGuiApp.hAppWindow = pIn->AttachGuiApp.hAppWindow; ppReply->AttachGuiApp.hSrvConWnd = pRCon->ConWnd(); ppReply->AttachGuiApp.hkl = (DWORD)(LONG)(LONG_PTR)GetKeyboardLayout(gpConEmu->mn_MainThreadId); ZeroStruct(ppReply->AttachGuiApp.Styles.Shifts); CRealConsole::CorrectGuiChildRect(pIn->AttachGuiApp.Styles.nStyle, pIn->AttachGuiApp.Styles.nStyleEx, ppReply->AttachGuiApp.Styles.Shifts); } else { ppReply->AttachGuiApp.nFlags = agaf_Fail; } lbRc = TRUE; //// Отправляем //fSuccess = WriteFile( // hPipe, // handle to pipe // &Out, // buffer to write from // Out.hdr.cbSize, // number of bytes to write // &cbWritten, // number of bytes written // NULL); // not overlapped I/O break; } // CECMD_ATTACHGUIAPP case CECMD_GUICLIENTSHIFT: { pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(GuiStylesAndShifts); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; ppReply->GuiAppShifts = pIn->GuiAppShifts; ZeroStruct(ppReply->GuiAppShifts.Shifts); CRealConsole::CorrectGuiChildRect(pIn->GuiAppShifts.nStyle, pIn->GuiAppShifts.nStyleEx, ppReply->GuiAppShifts.Shifts); lbRc = TRUE; break; } // CECMD_GUICLIENTSHIFT case CECMD_GUIMACRO: { // Допустимо, если GuiMacro пытаются выполнить извне CVConGuard VCon; CVConGroup::GetActiveVCon(&VCon); DWORD nFarPluginPID = VCon->RCon()->GetFarPID(true); LPWSTR pszResult = CConEmuMacro::ExecuteMacro(pIn->GuiMacro.sMacro, VCon->RCon(), (nFarPluginPID==pIn->hdr.nSrcPID)); int nLen = pszResult ? _tcslen(pszResult) : 0; pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_GUIMACRO)+nLen*sizeof(wchar_t); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; if (pszResult) { lstrcpy(ppReply->GuiMacro.sMacro, pszResult); ppReply->GuiMacro.nSucceeded = 1; free(pszResult); } else { ppReply->GuiMacro.sMacro[0] = 0; ppReply->GuiMacro.nSucceeded = 0; } break; } // CECMD_GUIMACRO //case CECMD_DEFTERMSTARTED: //{ // if (gpConEmu->mp_DefTrm) // gpConEmu->mp_DefTrm->OnDefTermStarted(pIn); // pcbReplySize = sizeof(CESERVER_REQ_HDR); // if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) // goto wrap; // lbRc = TRUE; // break; //} // CECMD_DEFTERMSTARTED default: _ASSERTE(FALSE && "Command was not handled in CGuiServer::GuiServerCommand"); } //// Освободить память //if (pIn && (LPVOID)pIn != (LPVOID)&in) //{ // free(pIn); pIn = NULL; //} wrap: return lbRc; }
// Эту функцию нужно позвать из DllMain плагина bool StartupHooks(HMODULE ahOurDll) { WARNING("Добавить в аргументы строковый параметр - инфа об ошибке"); if (ghHooksModule == NULL) { wchar_t szHkModule[64]; #ifdef WIN64 wcscpy_c(szHkModule, L"ConEmuHk64.dll"); #else wcscpy_c(szHkModule, L"ConEmuHk.dll"); #endif ghHooksModule = GetModuleHandle(szHkModule); if ((ghHooksModule == NULL) && (ghConEmuWndDC != NULL)) { // Попробовать выполнить LoadLibrary? в некоторых случаях GetModuleHandle может обламываться ghHooksModule = LoadLibrary(szHkModule); if (ghHooksModule) gbHooksModuleLoaded = TRUE; } if (ghHooksModule == NULL) { if (ghConEmuWndDC != NULL) { _ASSERTE(ghHooksModule!=NULL); wchar_t szErrMsg[128]; DWORD nErrCode = GetLastError(); _wsprintf(szErrMsg, SKIPLEN(countof(szErrMsg)) L"ConEmuHk was not loaded, but ConEmu found!\nFar PID=%u, ErrCode=0x%08X", GetCurrentProcessId(), nErrCode); MessageBox(NULL, szErrMsg, L"ConEmu plugin", MB_ICONSTOP|MB_SYSTEMMODAL); } return false; } } _ASSERTE(ghConEmuWndDC!=NULL); if (!SetHookCallbacks || !SetLoadLibraryCallback) { SetHookCallbacks = (SetHookCallbacks_t)GetProcAddress(ghHooksModule, "SetHookCallbacks"); SetLoadLibraryCallback = (SetLoadLibraryCallback_t)GetProcAddress(ghHooksModule, "SetLoadLibraryCallback"); SetFarHookMode = (SetFarHookMode_t)GetProcAddress(ghHooksModule, "SetFarHookMode"); if (!SetHookCallbacks || !SetLoadLibraryCallback || !SetFarHookMode) { wchar_t szTitle[64], szText[255]; _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"ConEmu plugin, PID=%u", GetCurrentProcessId()); _wsprintf(szText, SKIPLEN(countof(szText)) L"ConEmuHk is broken, export (%s) not found!", (!SetHookCallbacks) ? L"SetHookCallbacks" : (!SetLoadLibraryCallback) ? L"SetLoadLibraryCallback" : L"SetFarHookMode"); MessageBox(NULL, szText, szTitle, MB_ICONSTOP|MB_SYSTEMMODAL); return FALSE; } } if (!ghExtConModule) { ghExtConModule = GetModuleHandle(WIN3264TEST(L"ExtendedConsole.dll",L"ExtendedConsole64.dll")); } if (ghExtConModule && !SetHookCallbacksExt) { SetHookCallbacksExt = (SetHookCallbacks_t)GetProcAddress(ghExtConModule, "SetHookCallbacksExt"); } SetLoadLibraryCallback(ghPluginModule, CPluginBase::OnLibraryLoaded, NULL/*OnLibraryUnLoaded*/); SetHookCallbacks("FreeConsole", kernel32, ghPluginModule, CPluginBase::OnConsoleDetaching, NULL, NULL); SetHookCallbacks("AllocConsole", kernel32, ghPluginModule, NULL, CPluginBase::OnConsoleWasAttached, NULL); SetHookCallbacks("PeekConsoleInputA", kernel32, ghPluginModule, CPluginBase::OnConsolePeekInput, CPluginBase::OnConsolePeekInputPost, NULL); SetHookCallbacks("PeekConsoleInputW", kernel32, ghPluginModule, CPluginBase::OnConsolePeekInput, CPluginBase::OnConsolePeekInputPost, NULL); SetHookCallbacks("ReadConsoleInputA", kernel32, ghPluginModule, CPluginBase::OnConsoleReadInput, CPluginBase::OnConsoleReadInputPost, NULL); SetHookCallbacks("ReadConsoleInputW", kernel32, ghPluginModule, CPluginBase::OnConsoleReadInput, CPluginBase::OnConsoleReadInputPost, NULL); SetHookCallbacks("WriteConsoleOutputA", kernel32, ghPluginModule, CPluginBase::OnWriteConsoleOutput, NULL, NULL); SetHookCallbacks("WriteConsoleOutputW", kernel32, ghPluginModule, CPluginBase::OnWriteConsoleOutput, NULL, NULL); if (SetHookCallbacksExt) SetHookCallbacksExt("WriteConsoleOutputW", kernel32, ghPluginModule, CPluginBase::OnWriteConsoleOutput, NULL, NULL); SetHookCallbacks("GetNumberOfConsoleInputEvents", kernel32, ghPluginModule, NULL, CPluginBase::OnGetNumberOfConsoleInputEventsPost, NULL); SetHookCallbacks("ShellExecuteExW", shell32, ghPluginModule, NULL, NULL, CPluginBase::OnShellExecuteExW_Except); gFarMode.OnCurDirChanged = CPluginBase::OnCurDirChanged; SetFarHookMode(&gFarMode); return true; }
bool CDpiForDialog::SetDialogDPI(const DpiValue& newDpi, LPRECT lprcSuggested /*= NULL*/) { wchar_t szLog[160]; RECT rcClient = {}, rcCurWnd = {}; #ifdef _DEBUG if (gbSkipSetDialogDPI) { GetClientRect(mh_Dlg, &rcClient); GetWindowRect(mh_Dlg, &rcCurWnd); _wsprintf(szLog, SKIPCOUNT(szLog) L"SKIPPED CDpiForDialog::SetDialogDPI x%08X, OldDpi={%i,%i}, NewDpi={%i,%i}, CurSize={%i,%i}, CurClient={%i,%i}", (DWORD)(DWORD_PTR)mh_Dlg, m_CurDpi.Xdpi, m_CurDpi.Ydpi, newDpi.Xdpi, newDpi.Ydpi, (rcCurWnd.right - rcCurWnd.left), (rcCurWnd.bottom - rcCurWnd.top), (rcClient.right - rcClient.left), (rcClient.bottom - rcClient.top)); LogString(szLog); return false; } #endif if (mn_InSet > 0) return false; if (newDpi.Ydpi <= 0 || newDpi.Xdpi <= 0) return false; if (m_CurDpi.Ydpi <= 0 || m_CurDpi.Xdpi <= 0) return false; // When overall DPI is very large but new dpi is small // (example: primary mon is 192 high-dpi, new mon is 96 dpi) // Windows goes crazy... HUGE caption, scrollbars, checkbox marks and so on... // So huge difference makes dialog unattractive, let's try to smooth that DpiValue setDpi(newDpi); if (m_InitDpi.Ydpi > MulDiv(setDpi.Ydpi, 144, 96)) { // Increase DPI one step up setDpi.Ydpi = MulDiv(setDpi.Ydpi, 120, 96); setDpi.Xdpi = MulDiv(setDpi.Xdpi, 120, 96); // Log it _wsprintf(szLog, SKIPCOUNT(szLog) L"CDpiForDialog::SetDialogDPI x%08X forces larger dpi value from {%i,%i} to {%i,%i}", (DWORD)(DWORD_PTR)mh_Dlg, newDpi.Xdpi, newDpi.Ydpi, setDpi.Xdpi, setDpi.Ydpi); LogString(szLog); } if (m_CurDpi.Equals(setDpi)) return false; bool bRc = false; MArray<DlgItem>* p = NULL; DpiValue curDpi(m_CurDpi); HFONT hf = NULL; wchar_t szClass[100]; #ifdef _DEBUG LOGFONT lftest1 = {}, lftest2 = {}; HFONT hftest; int itest1, itest2; #endif // To avoid several nested passes InterlockedIncrement(&mn_InSet); m_CurDpi.SetDpi(setDpi); // Eval mn_CurFontHeight = GetFontSizeForDpi(NULL, m_CurDpi.Ydpi); //(m_CurDpi.Ydpi && m_InitDpi.Ydpi) ? (mn_InitFontHeight * m_CurDpi.Ydpi / m_InitDpi.Ydpi) : -11; mlf_CurFont = mlf_InitFont; mlf_CurFont.lfHeight = mn_CurFontHeight; mlf_CurFont.lfWidth = 0; // Font mapper fault if (mn_CurFontHeight == 0) goto wrap; if (!m_Items.Get(m_CurDpi.Ydpi, &p)) { MArray<DlgItem>* pOrig = NULL; int iOrigDpi = 0; if (!m_Items.GetNext(NULL, &iOrigDpi, &pOrig) || !pOrig || (iOrigDpi <= 0)) goto wrap; int iNewDpi = m_CurDpi.Ydpi; p = new MArray<DlgItem>(); DWORD dwStyle = GetWindowLong(mh_Dlg, GWL_STYLE); DWORD dwStyleEx = GetWindowLong(mh_Dlg, GWL_EXSTYLE); if (!GetClientRect(mh_Dlg, &rcClient) || !GetWindowRect(mh_Dlg, &rcCurWnd)) { delete p; goto wrap; } _ASSERTE(rcClient.left==0 && rcClient.top==0); int calcDlgWidth = rcClient.right * m_CurDpi.Xdpi / curDpi.Xdpi; int calcDlgHeight = rcClient.bottom * m_CurDpi.Ydpi / curDpi.Ydpi; DlgItem i = {mh_Dlg}; // Windows DWM manager do not resize NonClient areas of per-monitor dpi aware applications // So, we can not use AdjustWindowRectEx to determine full window rectangle // Just use current NonClient dimensions i.r.right = calcDlgWidth + ((rcCurWnd.right - rcCurWnd.left) - rcClient.right); i.r.bottom = calcDlgHeight + ((rcCurWnd.bottom - rcCurWnd.top) - rcClient.bottom); // .right and .bottom are width and height of the dialog _ASSERTE(i.r.left==0 && i.r.top==0); p->push_back(i); for (INT_PTR k = 1; k < pOrig->size(); k++) { const DlgItem& iOrig = (*pOrig)[k]; i.h = iOrig.h; i.r.left = iOrig.r.left * iNewDpi / iOrigDpi; i.r.top = iOrig.r.top * iNewDpi / iOrigDpi; i.r.right = iOrig.r.right * iNewDpi / iOrigDpi; i.r.bottom = iOrig.r.bottom * iNewDpi / iOrigDpi; p->push_back(i); } m_Items.Set(iNewDpi, p); } if (p->size() <= 0) { _ASSERTE(FALSE && "No elements"); goto wrap; } else { const DlgItem& di = (*p)[0]; _wsprintf(szLog, SKIPCOUNT(szLog) L"CDpiForDialog::SetDialogDPI x%08X, OldDpi={%i,%i}, NewDpi={%i,%i}, OldSize={%i,%i}, NewSize={%i,%i}, NewFont=%i", (DWORD)(DWORD_PTR)mh_Dlg, curDpi.Xdpi, curDpi.Ydpi, newDpi.Xdpi, newDpi.Ydpi, (rcCurWnd.right - rcCurWnd.left), (rcCurWnd.bottom - rcCurWnd.top), di.r.right, di.r.bottom, mlf_CurFont.lfHeight); LogString(szLog); } hf = CreateFontIndirect(&mlf_CurFont); if (hf == NULL) { goto wrap; } for (INT_PTR k = p->size() - 1; k >= 1; k--) { const DlgItem& di = (*p)[k]; GetClassName(di.h, szClass, countof(szClass)); DWORD nCtrlID = GetWindowLong(di.h, GWL_ID); DWORD nStyles = GetWindowLong(di.h, GWL_STYLE); bool bResizeCombo = (lstrcmpi(szClass, L"ComboBox") == 0); int iComboFieldHeight = 0, iComboWasHeight = 0; LONG_PTR lFieldHeight = 0, lNewHeight = 0; RECT rcCur = {}; HWND hComboEdit = NULL; RECT rcEdit = {}, rcClient = {}; if (bResizeCombo && (nStyles & CBS_OWNERDRAWFIXED)) { GetWindowRect(di.h, &rcCur); hComboEdit = FindWindowEx(di.h, NULL, L"Edit", NULL); GetClientRect(di.h, &rcClient); GetClientRect(hComboEdit, &rcEdit); iComboWasHeight = (rcCur.bottom - rcCur.top); lFieldHeight = SendMessage(di.h, CB_GETITEMHEIGHT, -1, 0); if (lFieldHeight < iComboWasHeight) { iComboFieldHeight = lFieldHeight; } } int newW = di.r.right - di.r.left; int newH = di.r.bottom - di.r.top; MoveWindow(di.h, di.r.left, di.r.top, newW, newH, FALSE); SendMessage(di.h, WM_SETFONT, (WPARAM)hf, FALSE/*immediately*/); if (bResizeCombo) { if ((nStyles & CBS_OWNERDRAWFIXED) && (iComboWasHeight > 0) && (iComboFieldHeight > 0)) { RECT rcEdit2 = {}, rcClient2 = {}; GetClientRect(di.h, &rcClient2); GetClientRect(hComboEdit, &rcEdit2); lNewHeight = newH*iComboFieldHeight/iComboWasHeight; _wsprintf(szLog, SKIPCOUNT(szLog) L"CDpiForDialog::Combo height changed - OldHeight=%i, ItemHeight=%i, NewHeight=%i, NewItemHeight=%i", (rcCur.bottom - rcCur.top), lFieldHeight, newH, lNewHeight); LogString(szLog); SendMessage(di.h, CB_SETITEMHEIGHT, -1, lNewHeight); } SendMessage(di.h, CB_SETEDITSEL, 0, MAKELPARAM(-1,0)); } EditIconHint_ResChanged(di.h); InvalidateRect(di.h, NULL, TRUE); #ifdef _DEBUG itest1 = GetObject(hf, sizeof(lftest1), &lftest1); hftest = (HFONT)SendMessage(di.h, WM_GETFONT, 0, 0); itest2 = GetObject(hftest, sizeof(lftest2), &lftest2); #endif } if (p->size() > 0) { const DlgItem& di = (*p)[0]; SendMessage(mh_Dlg, WM_SETFONT, (WPARAM)hf, FALSE); DWORD nWndFlags = SWP_NOZORDER | (lprcSuggested ? 0 : SWP_NOMOVE); SetWindowPos(mh_Dlg, NULL, lprcSuggested ? lprcSuggested->left : 0, lprcSuggested ? lprcSuggested->top : 0, di.r.right, di.r.bottom, nWndFlags); RECT rc = {}; GetClientRect(mh_Dlg, &rc); InvalidateRect(mh_Dlg, NULL, TRUE); RedrawWindow(mh_Dlg, &rc, NULL, /*RDW_ERASE|*/RDW_ALLCHILDREN/*|RDW_INVALIDATE|RDW_UPDATENOW|RDW_INTERNALPAINT*/); } if (mh_CurFont != hf) DeleteObject(mh_CurFont); mh_CurFont = hf; bRc = true; wrap: InterlockedDecrement(&mn_InSet); return bRc; }
//Arguments: // hConWnd - Хэндл КОНСОЛЬНОГО окна (по нему формируется имя пайпа для GUI) // pIn - выполняемая команда // nTimeout- таймаут подключения //Returns: // CESERVER_REQ. Его необходимо освободить через free(...); //WARNING!!! // Эта процедура не может получить с сервера более 600 байт данных! // В заголовке hOwner в дебаге может быть отображена ошибка CESERVER_REQ* ExecuteCmd(const wchar_t* szPipeName, CESERVER_REQ* pIn, DWORD nWaitPipe, HWND hOwner, BOOL bAsyncNoResult, DWORD nServerPID, BOOL bIgnoreAbsence /*= FALSE*/) { CESERVER_REQ* pOut = NULL; HANDLE hPipe = NULL; BYTE cbReadBuf[600]; // чтобы CESERVER_REQ_OUTPUTFILE поместился wchar_t szErr[MAX_PATH*2]; szErr[0] = 0; BOOL fSuccess = FALSE; DWORD cbRead = 0, /*dwMode = 0,*/ dwErr = 0; int nAllSize; LPBYTE ptrData; #ifdef _DEBUG bool bIsAltSrvCmd; wchar_t szDbgPrefix[64], szDbgResult[64], *pszDbgMsg = NULL; #endif if (!pIn || !szPipeName) { _ASSERTE(pIn && szPipeName); pOut = NULL; goto wrap; } #ifdef _DEBUG _wsprintf(szDbgPrefix, SKIPLEN(countof(szDbgPrefix)) L">> ExecCmd: PID=%5u TID=%5u Cmd=%3u ", GetCurrentProcessId(), GetCurrentThreadId(), pIn->hdr.nCmd); pszDbgMsg = lstrmerge(szDbgPrefix, szPipeName, L"\n"); if (pszDbgMsg) { DEBUGSTRCMD(pszDbgMsg); free(pszDbgMsg); } #endif pIn->hdr.bAsync = bAsyncNoResult; _ASSERTE(pIn->hdr.nSrcPID && pIn->hdr.nSrcThreadId); _ASSERTE(pIn->hdr.cbSize >= sizeof(pIn->hdr)); hPipe = ExecuteOpenPipe(szPipeName, szErr, NULL/*Сюда хорошо бы имя модуля подкрутить*/, nServerPID, nWaitPipe, FALSE, NULL, bIgnoreAbsence); if (hPipe == NULL || hPipe == INVALID_HANDLE_VALUE) { #ifdef _DEBUG dwErr = GetLastError(); // в заголовке "чисто" запущенного фара появляются отладочные(?) сообщения // по идее - не должны, т.к. все должно быть через мэппинг // *** _ASSERTEX(hPipe != NULL && hPipe != INVALID_HANDLE_VALUE); - no need in assert, it was already shown #ifdef CONEMU_MINIMAL SetConsoleTitle(szErr); #else if (hOwner) { if (hOwner == myGetConsoleWindow()) SetConsoleTitle(szErr); else SetWindowText(hOwner, szErr); } #endif #endif pOut = NULL; goto wrap; } #ifdef _DEBUG bIsAltSrvCmd = (pIn->hdr.nCmd==CECMD_ALTBUFFER || pIn->hdr.nCmd==CECMD_ALTBUFFERSTATE || pIn->hdr.nCmd==CECMD_SETCONSCRBUF || pIn->hdr.nCmd == CECMD_LOCKSTATION || pIn->hdr.nCmd == CECMD_UNLOCKSTATION); _ASSERTE(pIn->hdr.nSrcThreadId==GetCurrentThreadId() || (bIsAltSrvCmd && pIn->hdr.nSrcPID!=GetCurrentProcessId())); #endif if (bAsyncNoResult) { // Если нас не интересует возврат и нужно сразу вернуться fSuccess = WriteFile(hPipe, pIn, pIn->hdr.cbSize, &cbRead, NULL); #ifdef _DEBUG dwErr = GetLastError(); _ASSERTE(fSuccess && (cbRead == pIn->hdr.cbSize)); #endif // -- Do not close hPipe, otherwise the reader may fail with that packet // -- with error ‘pipe was closed before end’. // -- Handle leak, yeah, however this is rarely used op. // -- Must be refactored, but not so critical... // -- CloseHandle(hPipe); pOut = NULL; goto wrap; } else { WARNING("При Overlapped часто виснет в этом месте."); // Send a message to the pipe server and read the response. fSuccess = TransactNamedPipe( hPipe, // pipe handle (LPVOID)pIn, // message to server pIn->hdr.cbSize, // message length cbReadBuf, // buffer to receive reply sizeof(cbReadBuf), // size of read buffer &cbRead, // bytes read NULL); // not overlapped dwErr = GetLastError(); //CloseHandle(hPipe); if (!fSuccess && (dwErr != ERROR_MORE_DATA)) { //_ASSERTE(fSuccess || (dwErr == ERROR_MORE_DATA)); CloseHandle(hPipe); pOut = NULL; goto wrap; } } if (cbRead < sizeof(CESERVER_REQ_HDR)) { CloseHandle(hPipe); pOut = NULL; goto wrap; } pOut = (CESERVER_REQ*)cbReadBuf; // temporary if (pOut->hdr.cbSize < cbRead) { CloseHandle(hPipe); if (pOut->hdr.cbSize) { _ASSERTE(pOut->hdr.cbSize == 0 || pOut->hdr.cbSize >= cbRead); DEBUGSTR(L"!!! Wrong nSize received from GUI server !!!\n"); } pOut = NULL; goto wrap; } if (pOut->hdr.nVersion != CESERVER_REQ_VER) { CloseHandle(hPipe); DEBUGSTR(L"!!! Wrong nVersion received from GUI server !!!\n"); pOut = NULL; goto wrap; } nAllSize = pOut->hdr.cbSize; pOut = (CESERVER_REQ*)malloc(nAllSize); _ASSERTE(pOut); if (!pOut) { CloseHandle(hPipe); _ASSERTE(pOut == NULL); goto wrap; } memmove(pOut, cbReadBuf, cbRead); ptrData = ((LPBYTE)pOut)+cbRead; nAllSize -= cbRead; while (nAllSize>0) { // Break if TransactNamedPipe or ReadFile is successful if (fSuccess) break; // Read from the pipe if there is more data in the message. fSuccess = ReadFile( hPipe, // pipe handle ptrData, // buffer to receive reply nAllSize, // size of buffer &cbRead, // number of bytes read NULL); // not overlapped // Exit if an error other than ERROR_MORE_DATA occurs. if (!fSuccess && ((dwErr = GetLastError()) != ERROR_MORE_DATA)) break; ptrData += cbRead; nAllSize -= cbRead; } CloseHandle(hPipe); if (pOut && (pOut->hdr.nCmd != pIn->hdr.nCmd)) { _ASSERTE(pOut->hdr.nCmd == pIn->hdr.nCmd); if (pOut->hdr.nCmd == 0) { ExecuteFreeResult(pOut); pOut = NULL; } } wrap: #ifdef _DEBUG if (pOut) _wsprintf(szDbgResult, SKIPLEN(countof(szDbgResult)) L"- Data=%5u Err=%u\n", pOut->DataSize(), dwErr); else lstrcpyn(szDbgResult, L"[NULL]\n", countof(szDbgResult)); pszDbgMsg = lstrmerge(szDbgPrefix, szDbgResult); if (pszDbgMsg) { DEBUGSTRCMD(pszDbgMsg); free(pszDbgMsg); } #endif return pOut; }
bool GetSaveDumpName(DWORD dwProcessId, bool bFull, wchar_t* dmpfile, DWORD cchMaxDmpFile) { bool bRc = false; HMODULE hCOMDLG32 = NULL; typedef BOOL (WINAPI* GetSaveFileName_t)(LPOPENFILENAMEW lpofn); GetSaveFileName_t _GetSaveFileName = NULL; if (!gpSrv->DbgInfo.bDebugProcessTree) { if (!hCOMDLG32) hCOMDLG32 = LoadLibraryW(L"COMDLG32.dll"); if (hCOMDLG32 && !_GetSaveFileName) _GetSaveFileName = (GetSaveFileName_t)GetProcAddress(hCOMDLG32, "GetSaveFileNameW"); if (_GetSaveFileName) { OPENFILENAMEW ofn; memset(&ofn,0,sizeof(ofn)); ofn.lStructSize=sizeof(ofn); ofn.hwndOwner = NULL; ofn.lpstrFilter = L"Debug dumps (*.mdmp)\0*.mdmp;*.dmp\0Debug dumps (*.dmp)\0*.dmp;*.mdmp\0\0"; ofn.nFilterIndex = bFull ? 2 : 1; ofn.lpstrFile = dmpfile; ofn.nMaxFile = cchMaxDmpFile; ofn.lpstrTitle = bFull ? L"Save debug full-dump" : L"Save debug mini-dump"; ofn.lpstrDefExt = bFull ? L"dmp" : L"mdmp"; ofn.Flags = OFN_ENABLESIZING|OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST|OFN_EXPLORER|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT; if (_GetSaveFileName(&ofn)) { bRc = true; } } if (hCOMDLG32) { FreeLibrary(hCOMDLG32); } } if (gpSrv->DbgInfo.bDebugProcessTree || !_GetSaveFileName) { HRESULT dwErr = SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0/*SHGFP_TYPE_CURRENT*/, dmpfile); if (FAILED(dwErr)) { memset(dmpfile, 0, cchMaxDmpFile*sizeof(*dmpfile)); if (GetTempPath(cchMaxDmpFile-32, dmpfile) && *dmpfile) dwErr = S_OK; } if (FAILED(dwErr)) { _printf("\nGetSaveDumpName called, get desktop folder failed, code=%u\n", (DWORD)dwErr); } else { if (*dmpfile && dmpfile[lstrlen(dmpfile)-1] != L'\\') _wcscat_c(dmpfile, cchMaxDmpFile, L"\\"); _wcscat_c(dmpfile, cchMaxDmpFile, L"ConEmuTrap"); CreateDirectory(dmpfile, NULL); INT_PTR nLen = lstrlen(dmpfile); wchar_t szMinor[8] = L""; lstrcpyn(szMinor, _T(MVV_4a), countof(szMinor)); _wsprintf(dmpfile+nLen, SKIPLEN(cchMaxDmpFile-nLen) L"\\Trap-%02u%02u%02u%s-%u.%s", MVV_1, MVV_2, MVV_3,szMinor, dwProcessId, bFull ? L"dmp" : L"mdmp"); bRc = true; } } return bRc; }
void ComspecDone(int aiRc) { #ifdef _DEBUG xf_dump_chk(); xf_validate(NULL); #endif //WARNING("Послать в GUI CONEMUCMDSTOPPED"); LogSize(NULL, "ComspecDone"); // Это необходимо делать, т.к. при смене буфера (SetConsoleActiveScreenBuffer) приложением, // дескриптор нужно закрыть, иначе conhost может не вернуть предыдущий буфер //ConOutCloseHandle() // Поддержка алиасов if (gpSrv->szComSpecName[0] && gpSrv->szSelfName[0]) { // Скопировать алиасы из cmd.exe в conemuc.exe wchar_t *pszPostAliases = NULL; DWORD nPostAliasSize; BOOL lbChanged = (gpSrv->pszPreAliases == NULL); if (!GetAliases(gpSrv->szComSpecName, &pszPostAliases, &nPostAliasSize)) { if (pszPostAliases) _wprintf(pszPostAliases); } else { if (!lbChanged) { lbChanged = (gpSrv->nPreAliasSize!=nPostAliasSize); } if (!lbChanged && gpSrv->nPreAliasSize && gpSrv->pszPreAliases && pszPostAliases) { lbChanged = memcmp(gpSrv->pszPreAliases,pszPostAliases,gpSrv->nPreAliasSize)!=0; } if (lbChanged) { xf_dump_chk(); if (gnMainServerPID) { MCHKHEAP; CESERVER_REQ* pIn = ExecuteNewCmd(CECMD_SAVEALIASES,sizeof(CESERVER_REQ_HDR)+nPostAliasSize); if (pIn) { MCHKHEAP; memmove(pIn->Data, pszPostAliases, nPostAliasSize); MCHKHEAP; CESERVER_REQ* pOut = ExecuteSrvCmd(gnMainServerPID, pIn, GetConEmuHWND(2)); MCHKHEAP; if (pOut) ExecuteFreeResult(pOut); ExecuteFreeResult(pIn); MCHKHEAP; } } xf_dump_chk(); wchar_t *pszNewName = pszPostAliases, *pszNewTarget, *pszNewLine; while (pszNewName && *pszNewName) { pszNewLine = pszNewName + lstrlen(pszNewName); pszNewTarget = wcschr(pszNewName, L'='); if (pszNewTarget) { *pszNewTarget = 0; pszNewTarget++; } if (*pszNewTarget == 0) pszNewTarget = NULL; AddConsoleAlias(pszNewName, pszNewTarget, gpSrv->szSelfName); pszNewName = pszNewLine+1; } xf_dump_chk(); } } if (pszPostAliases) { free(pszPostAliases); pszPostAliases = NULL; } } xf_dump_chk(); //TODO("Уведомить плагин через пайп (если родитель - FAR) что процесс завершен. Плагин должен считать и запомнить содержимое консоли и только потом вернуть управление в ConEmuC!"); DWORD dwErr1 = 0; //, dwErr2 = 0; HANDLE hOut1 = NULL, hOut2 = NULL; BOOL lbRc1 = FALSE, lbRc2 = FALSE; CONSOLE_SCREEN_BUFFER_INFO sbi1 = {{0,0}}, sbi2 = {{0,0}}; #ifdef _DEBUG HWND hWndCon = GetConEmuHWND(2); #endif // Тут нужна реальная, а не скорректированная информация! if (!gbNonGuiMode) { // Если GUI не сможет через сервер вернуть высоту буфера - это нужно сделать нам! lbRc1 = GetConsoleScreenBufferInfo(hOut1 = GetStdHandle(STD_OUTPUT_HANDLE), &sbi1); if (!lbRc1) dwErr1 = GetLastError(); xf_dump_chk(); } //PRAGMA_ERROR("Размер должен возвращать сам GUI, через серверный ConEmuC!"); #ifdef SHOW_STARTED_MSGBOX MessageBox(GetConEmuHWND(2), L"ConEmuC (comspec mode) is about to TERMINATE", L"ConEmuC.ComSpec", 0); #endif #ifdef _DEBUG xf_dump_chk(); xf_validate(NULL); #endif if (!gbNonGuiMode && (gpSrv->dwParentFarPID != 0)) { //// Вернуть размер буфера (высота И ширина) //if (gpSrv->sbi.dwSize.X && gpSrv->sbi.dwSize.Y) { // SMALL_RECT rc = {0}; // SetConsoleSize(0, gpSrv->sbi.dwSize, rc, "ComspecDone"); //} //ConOutCloseHandle() CONSOLE_SCREEN_BUFFER_INFO l_csbi = {{0}}; lbRc2 = GetConsoleScreenBufferInfo(hOut2 = GetStdHandle(STD_OUTPUT_HANDLE), &l_csbi); CESERVER_REQ *pOut = SendStopped(&l_csbi); if (pOut) { if (!pOut->StartStopRet.bWasBufferHeight) { //gpSrv->sbi.dwSize = pIn->StartStop.sbi.dwSize; lbRc1 = FALSE; // Консольное приложение самостоятельно сбросило буферный режим. Не дергаться... } else { lbRc1 = TRUE; } ExecuteFreeResult(pOut); pOut = NULL; } if (!gbWasBufferHeight) { lbRc2 = GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbi2); #ifdef _DEBUG if (sbi2.dwSize.Y > 200) { wchar_t szTitle[128]; _wsprintf(szTitle, SKIPLEN(countof(szTitle)) L"ConEmuC (PID=%i)", GetCurrentProcessId()); MessageBox(NULL, L"BufferHeight was not turned OFF", szTitle, MB_SETFOREGROUND|MB_SYSTEMMODAL); } #endif if (lbRc1 && lbRc2 && sbi2.dwSize.Y == sbi1.dwSize.Y) { // GUI не смог вернуть высоту буфера... // Это плохо, т.к. фар высоту буфера не меняет и будет сильно глючить на N сотнях строк... int nNeedHeight = gpSrv->sbi.dwSize.Y; if (nNeedHeight < 10) { nNeedHeight = (sbi2.srWindow.Bottom-sbi2.srWindow.Top+1); } if (sbi2.dwSize.Y != nNeedHeight) { _ASSERTE(sbi2.dwSize.Y == nNeedHeight); PRINT_COMSPEC(L"Error: BufferHeight was not changed from %i\n", sbi2.dwSize.Y); SMALL_RECT rc = {0}; sbi2.dwSize.Y = nNeedHeight; if (gpLogSize) LogSize(&sbi2.dwSize, ":ComspecDone.RetSize.before"); SetConsoleSize(0, sbi2.dwSize, rc, "ComspecDone.Force"); if (gpLogSize) LogSize(NULL, ":ComspecDone.RetSize.after"); } } } } if (gpSrv->pszPreAliases) { free(gpSrv->pszPreAliases); gpSrv->pszPreAliases = NULL; } //SafeCloseHandle(ghCtrlCEvent); //SafeCloseHandle(ghCtrlBreakEvent); }
// Main function of this class decodes gesture information // in: // hWnd window handle // wParam message parameter (message-specific) // lParam message parameter (message-specific) bool CGestures::ProcessGestureMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult) { if ((uMsg != WM_GESTURENOTIFY) && (uMsg != WM_GESTURE)) return false; if (!_isGestures) { _ASSERTE(_isGestures); gpConEmu->LogString(L"Gesture message received but not allowed, skipping"); return false; } if (uMsg == WM_GESTURENOTIFY) { // This is the right place to define the list of gestures that this // application will support. By populating GESTURECONFIG structure // and calling SetGestureConfig function. We can choose gestures // that we want to handle in our application. In this app we // decide to handle all gestures. GESTURECONFIG gc[] = { {GID_ZOOM, GC_ZOOM}, {GID_ROTATE, GC_ROTATE}, {GID_PAN, GC_PAN|GC_PAN_WITH_GUTTER|GC_PAN_WITH_INERTIA, GC_PAN_WITH_SINGLE_FINGER_VERTICALLY|GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY }, {GID_PRESSANDTAP, GC_PRESSANDTAP}, {GID_TWOFINGERTAP, GC_TWOFINGERTAP}, }; BOOL bResult = _SetGestureConfig(hWnd, 0, countof(gc), gc, sizeof(GESTURECONFIG)); DWORD dwErr = GetLastError(); if (gpSetCls->isAdvLogging) { wchar_t szNotify[60]; _wsprintf(szNotify, SKIPLEN(countof(szNotify)) L"SetGestureConfig -> %u,%u", bResult, dwErr); gpConEmu->LogString(szNotify); } if (!bResult) { DisplayLastError(L"Error in execution of SetGestureConfig", dwErr); } lResult = ::DefWindowProc(hWnd, WM_GESTURENOTIFY, wParam, lParam); return true; } // Остался только WM_GESTURE Assert(uMsg==WM_GESTURE); // helper variables POINT ptZoomCenter; double k; GESTUREINFO gi = {sizeof(gi)}; // Checking for compiler alignment errors if (gi.cbSize != WIN3264TEST(48,56)) { // Struct member alignment must be 8bytes even on x86 Assert(sizeof(GESTUREINFO)==WIN3264TEST(48,56)); _isGestures = false; return false; } BOOL bResult = _GetGestureInfo((HGESTUREINFO)lParam, &gi); if (!bResult) { //_ASSERT(L"_GetGestureInfo failed!" && 0); DWORD dwErr = GetLastError(); DisplayLastError(L"Error in execution of _GetGestureInfo", dwErr); return FALSE; } bool bLog = (gpSetCls->isAdvLogging >= 2); #ifdef USE_DUMPGEST bLog = true; #endif #define DUMPGEST(tp) DumpGesture(tp, gi) //#ifdef USE_DUMPGEST // wchar_t szDump[256]; // #define DUMPGEST(tp) \ // _wsprintf(szDump, SKIPLEN(countof(szDump)) \ // L"Gesture(x%08X {%i,%i} %s", \ // (DWORD)gi.hwndTarget, gi.ptsLocation.x, gi.ptsLocation.y, \ // tp); \ // if (gi.dwID==GID_PRESSANDTAP) { \ // DWORD h = LODWORD(gi.ullArguments); _wsprintf(szDump+_tcslen(szDump), SKIPLEN(32) \ // L" Dist={%i,%i}", (int)(short)LOWORD(h), (int)(short)HIWORD(h)); } \ // if (gi.dwID==GID_ROTATE) { \ // DWORD h = LODWORD(gi.ullArguments); _wsprintf(szDump+_tcslen(szDump), SKIPLEN(32) \ // L" %i", (int)LOWORD(h)); } \ // if (gi.dwFlags&GF_BEGIN) wcscat_c(szDump, L" GF_BEGIN"); \ // if (gi.dwFlags&GF_END) wcscat_c(szDump, L" GF_END"); \ // if (gi.dwFlags&GF_INERTIA) { wcscat_c(szDump, L" GF_INERTIA"); \ // DWORD h = HIDWORD(gi.ullArguments); _wsprintf(szDump+_tcslen(szDump), SKIPLEN(32) \ // L" {%i,%i}", (int)(short)LOWORD(h), (int)(short)HIWORD(h)); } \ // wcscat_c(szDump, L")\n"); \ // DEBUGSTR(szDump) //#else //#define DUMPGEST(s) //#endif switch (gi.dwID) { case GID_BEGIN: DUMPGEST(L"GID_BEGIN"); break; case GID_END: DUMPGEST(L"GID_END"); break; case GID_ZOOM: DUMPGEST(L"GID_ZOOM"); if (gi.dwFlags & GF_BEGIN) { _dwArguments = LODWORD(gi.ullArguments); _ptFirst.x = gi.ptsLocation.x; _ptFirst.y = gi.ptsLocation.y; ScreenToClient(hWnd,&_ptFirst); } else { // We read here the second point of the gesture. This is middle point between // fingers in this new position. _ptSecond.x = gi.ptsLocation.x; _ptSecond.y = gi.ptsLocation.y; ScreenToClient(hWnd,&_ptSecond); // We have to calculate zoom center point ptZoomCenter.x = (_ptFirst.x + _ptSecond.x)/2; ptZoomCenter.y = (_ptFirst.y + _ptSecond.y)/2; // The zoom factor is the ratio between the new and the old distance. // The new distance between two fingers is stored in gi.ullArguments // (lower DWORD) and the old distance is stored in _dwArguments. k = (double)(LODWORD(gi.ullArguments))/(double)(_dwArguments); // Now we process zooming in/out of the object ProcessZoom(hWnd, k, ptZoomCenter.x, ptZoomCenter.y); // Now we have to store new information as a starting information // for the next step in this gesture. _ptFirst = _ptSecond; _dwArguments = LODWORD(gi.ullArguments); } break; case GID_PAN: DUMPGEST(L"GID_PAN"); if (gi.dwFlags & GF_BEGIN) { _ptFirst.x = gi.ptsLocation.x; _ptFirst.y = gi.ptsLocation.y; _ptBegin.x = gi.ptsLocation.x; _ptBegin.y = gi.ptsLocation.y; ScreenToClient(hWnd, &_ptFirst); } else { // We read the second point of this gesture. It is a middle point // between fingers in this new position _ptSecond.x = gi.ptsLocation.x; _ptSecond.y = gi.ptsLocation.y; ScreenToClient(hWnd, &_ptSecond); if (!(gi.dwFlags & (GF_END/*|GF_INERTIA*/))) { // We apply move operation of the object if (ProcessMove(hWnd, _ptSecond.x-_ptFirst.x, _ptSecond.y-_ptFirst.y)) { // We have to copy second point into first one to prepare // for the next step of this gesture. _ptFirst = _ptSecond; } } } break; case GID_ROTATE: DUMPGEST(L"GID_ROTATE"); if (gi.dwFlags & GF_BEGIN) { _inRotate = false; _dwArguments = LODWORD(gi.ullArguments); // Запомним начальный угол } else { _ptFirst.x = gi.ptsLocation.x; _ptFirst.y = gi.ptsLocation.y; ScreenToClient(hWnd, &_ptFirst); // Пока угол не станет достаточным для смены таба - игнорируем if (ProcessRotate(hWnd, LODWORD(gi.ullArguments) - _dwArguments, _ptFirst.x,_ptFirst.y, ((gi.dwFlags & GF_END) == GF_END))) { _dwArguments = LODWORD(gi.ullArguments); } } break; case GID_TWOFINGERTAP: DUMPGEST(L"GID_TWOFINGERTAP"); _ptFirst.x = gi.ptsLocation.x; _ptFirst.y = gi.ptsLocation.y; ScreenToClient(hWnd,&_ptFirst); ProcessTwoFingerTap(hWnd, _ptFirst.x, _ptFirst.y, LODWORD(gi.ullArguments)); break; case GID_PRESSANDTAP: DUMPGEST(L"GID_PRESSANDTAP"); if (gi.dwFlags & GF_BEGIN) { _ptFirst.x = gi.ptsLocation.x; _ptFirst.y = gi.ptsLocation.y; ScreenToClient(hWnd,&_ptFirst); DWORD nDelta = LODWORD(gi.ullArguments); short nDeltaX = (short)LOWORD(nDelta); short nDeltaY = (short)HIWORD(nDelta); ProcessPressAndTap(hWnd, _ptFirst.x, _ptFirst.y, nDeltaX, nDeltaY); } break; default: DUMPGEST(L"GID_<UNKNOWN>"); } _CloseGestureInfoHandle((HGESTUREINFO)lParam); return TRUE; }
BOOL SendConsoleEvent(INPUT_RECORD* pr, UINT nCount) { if (!nCount || !pr) { _ASSERTE(nCount>0 && pr!=NULL); return FALSE; } BOOL fSuccess = FALSE; //// Если сейчас идет ресайз - нежелательно помещение в буфер событий //if (gpSrv->bInSyncResize) // WaitForSingleObject(gpSrv->hAllowInputEvent, MAX_SYNCSETSIZE_WAIT); //DWORD nCurInputCount = 0, cbWritten = 0; //INPUT_RECORD irDummy[2] = {{0},{0}}; //HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); // тут был ghConIn // 02.04.2010 Maks - перенесено в WaitConsoleReady //// 27.06.2009 Maks - If input queue is not empty - wait for a while, to avoid conflicts with FAR reading queue //// 19.02.2010 Maks - замена на GetNumberOfConsoleInputEvents ////if (PeekConsoleInput(hIn, irDummy, 1, &(nCurInputCount = 0)) && nCurInputCount > 0) { //if (GetNumberOfConsoleInputEvents(hIn, &(nCurInputCount = 0)) && nCurInputCount > 0) { // DWORD dwStartTick = GetTickCount(); // WARNING("Do NOT wait, but place event in Cyclic queue"); // do { // Sleep(5); // //if (!PeekConsoleInput(hIn, irDummy, 1, &(nCurInputCount = 0))) // if (!GetNumberOfConsoleInputEvents(hIn, &(nCurInputCount = 0))) // nCurInputCount = 0; // } while ((nCurInputCount > 0) && ((GetTickCount() - dwStartTick) < MAX_INPUT_QUEUE_EMPTY_WAIT)); //} INPUT_RECORD* prNew = NULL; int nAllCount = 0; BOOL lbReqEmpty = FALSE; for (UINT n = 0; n < nCount; n++) { if (pr[n].EventType != KEY_EVENT) { nAllCount++; if (!lbReqEmpty && (pr[n].EventType == MOUSE_EVENT)) { // По всей видимости дурит консоль Windows. // Если в буфере сейчас еще есть мышиные события, то запись // в буфер возвращает ОК, но считывающее приложение получает 0-событий. // В итоге, получаем пропуск некоторых событий, что очень неприятно // при выделении кучи файлов правой кнопкой мыши (проводкой с зажатой кнопкой) if (pr[n].Event.MouseEvent.dwButtonState /*== RIGHTMOST_BUTTON_PRESSED*/) lbReqEmpty = TRUE; } } else { if (!pr[n].Event.KeyEvent.wRepeatCount) { _ASSERTE(pr[n].Event.KeyEvent.wRepeatCount!=0); pr[n].Event.KeyEvent.wRepeatCount = 1; } nAllCount += pr[n].Event.KeyEvent.wRepeatCount; } } if (nAllCount > (int)nCount) { prNew = (INPUT_RECORD*)malloc(sizeof(INPUT_RECORD)*nAllCount); if (prNew) { INPUT_RECORD* ppr = prNew; INPUT_RECORD* pprMod = NULL; for (UINT n = 0; n < nCount; n++) { *(ppr++) = pr[n]; if (pr[n].EventType == KEY_EVENT) { UINT nCurCount = pr[n].Event.KeyEvent.wRepeatCount; if (nCurCount > 1) { pprMod = (ppr-1); pprMod->Event.KeyEvent.wRepeatCount = 1; for (UINT i = 1; i < nCurCount; i++) { *(ppr++) = *pprMod; } } } else if (!lbReqEmpty && (pr[n].EventType == MOUSE_EVENT)) { // По всей видимости дурит консоль Windows. // Если в буфере сейчас еще есть мышиные события, то запись // в буфер возвращает ОК, но считывающее приложение получает 0-событий. // В итоге, получаем пропуск некоторых событий, что очень неприятно // при выделении кучи файлов правой кнопкой мыши (проводкой с зажатой кнопкой) if (pr[n].Event.MouseEvent.dwButtonState == RIGHTMOST_BUTTON_PRESSED) lbReqEmpty = TRUE; } } pr = prNew; _ASSERTE(nAllCount == (ppr-prNew)); nCount = (UINT)(ppr-prNew); } } // Если не готов - все равно запишем DEBUGTEST(BOOL bConReady = ) WaitConsoleReady(lbReqEmpty); DWORD cbWritten = 0; #ifdef _DEBUG wchar_t* pszDbgCurChars = NULL; wchar_t szDbg[255]; for (UINT i = 0; i < nCount; i++) { switch (pr[i].EventType) { case MOUSE_EVENT: _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"*** ConEmuC.MouseEvent(X=%i,Y=%i,Btns=0x%04x,Moved=%i)\n", pr[i].Event.MouseEvent.dwMousePosition.X, pr[i].Event.MouseEvent.dwMousePosition.Y, pr[i].Event.MouseEvent.dwButtonState, (pr[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED)); DEBUGSTRINPUTWRITE(szDbg); #ifdef _DEBUG { static int LastMsButton; if ((LastMsButton & 1) && (pr[i].Event.MouseEvent.dwButtonState == 0)) { // LButton was Down, now - Up LastMsButton = pr[i].Event.MouseEvent.dwButtonState; } else if (!LastMsButton && (pr[i].Event.MouseEvent.dwButtonState & 1)) { // LButton was Up, now - Down LastMsButton = pr[i].Event.MouseEvent.dwButtonState; } else { //-V523 LastMsButton = pr[i].Event.MouseEvent.dwButtonState; } } #endif break; case KEY_EVENT: { wchar_t szCh[3] = {pr[i].Event.KeyEvent.uChar.UnicodeChar}; switch (szCh[0]) { case 8: szCh[0] = L'\\'; szCh[1] = L'b'; break; case 9: szCh[0] = L'\\'; szCh[1] = L't'; break; case 10: szCh[0] = L'\\'; szCh[1] = L'r'; break; case 13: szCh[0] = L'\\'; szCh[1] = L'n'; break; case 27: szCh[0] = L'\\'; szCh[1] = L'e'; break; } _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"*** ConEmuC.KeybdEvent(%s, VK=%u, CH=%s)\n", pr[i].Event.KeyEvent.bKeyDown ? L"Dn" : L"Up", pr[i].Event.KeyEvent.wVirtualKeyCode, szCh); DEBUGSTRINPUTWRITE(szDbg); } break; } // Only for input_bug search purposes in Debug builds LONG idx = (InterlockedIncrement(&gn_LogWrittenChars) & (gn_LogWrittenCharsMax-1))*2; if (!pszDbgCurChars) pszDbgCurChars = gs_LogWrittenChars+idx; if (pr[i].EventType == KEY_EVENT) { gs_LogWrittenChars[idx++] = pr[i].Event.KeyEvent.bKeyDown ? L'\\' : L'/'; gs_LogWrittenChars[idx] = pr[i].Event.KeyEvent.uChar.UnicodeChar ? pr[i].Event.KeyEvent.uChar.UnicodeChar : L'.'; } else { gs_LogWrittenChars[idx++] = L'='; switch (pr[i].EventType) { case MOUSE_EVENT: gs_LogWrittenChars[idx] = L'm'; break; case WINDOW_BUFFER_SIZE_EVENT: gs_LogWrittenChars[idx] = L'w'; break; case MENU_EVENT: gs_LogWrittenChars[idx] = L'e'; break; case FOCUS_EVENT: gs_LogWrittenChars[idx] = L'f'; break; default: gs_LogWrittenChars[idx] = L'x'; break; } } gs_LogWrittenChars[++idx] = 0; } int nDbgSendLen = pszDbgCurChars ? lstrlen(pszDbgCurChars) : -1; SetLastError(0); #endif HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); // тут был ghConIn // Strange VIM reaction on xterm-keypresses if ((nCount > 2) && (nCount <= 32) && (pr->EventType == KEY_EVENT) && (pr->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) { DWORD nWritten = 0; cbWritten = 0; for (UINT n = 0; n < nCount; n++) { if ((n + 1) == nCount) { DEBUGTEST(bConReady = ) WaitConsoleReady(TRUE); } fSuccess = WriteConsoleInput(hIn, pr+n, 1, &nWritten); if (fSuccess) cbWritten += nWritten; }