void Help() { PrintVersion(); // See definition in "ConEmuCD/ConsoleHelp.h" _wprintf(pConsoleHelp); _wprintf(pNewConsoleHelp); }
// ConEmuC -OsVerInfo int OsVerInfo() { OSVERSIONINFOEX osv = {sizeof(osv)}; GetOsVersionInformational((OSVERSIONINFO*)&osv); UINT DBCS = IsDbcs(); UINT HWFS = IsHwFullScreenAvailable(); UINT W5fam = IsWin5family(); UINT WXPSP1 = IsWinXPSP1(); UINT W6 = IsWin6(); UINT W7 = IsWin7(); UINT W10 = IsWin10(); UINT Wx64 = IsWindows64(); UINT WINE = IsWine(); UINT WPE = IsWinPE(); UINT TELNET = isTerminalMode(); wchar_t szInfo[200]; _wsprintf(szInfo, SKIPCOUNT(szInfo) L"OS version information\n" L"%u.%u build %u SP%u.%u suite=x%04X type=%u\n" L"W5fam=%u WXPSP1=%u W6=%u W7=%u W10=%u Wx64=%u\n" L"HWFS=%u DBCS=%u WINE=%u WPE=%u TELNET=%u\n", osv.dwMajorVersion, osv.dwMinorVersion, osv.dwBuildNumber, osv.wServicePackMajor, osv.wServicePackMinor, osv.wSuiteMask, osv.wProductType, W5fam, WXPSP1, W6, W7, W10, Wx64, HWFS, DBCS, WINE, WPE, TELNET); _wprintf(szInfo); return MAKEWORD(osv.dwMinorVersion, osv.dwMajorVersion); }
void PrintVersion() { wchar_t szProgInfo[255], szVer[32]; MultiByteToWideChar(CP_ACP, 0, CONEMUVERS, -1, szVer, countof(szVer)); _wsprintf(szProgInfo, SKIPLEN(countof(szProgInfo)) L"ConEmuC build %s %s. " CECOPYRIGHTSTRING_W L"\n", szVer, WIN3264TEST(L"x86",L"x64")); _wprintf(szProgInfo); }
// 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(); // } //} } }
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_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); 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; }
int main(int argc, char** argv) { gn_argc = argc; gp_argv = argv; int iRc = 0; HMODULE hConEmu = NULL; wchar_t szErrInfo[200]; DWORD dwErr; typedef int (__stdcall* ConsoleMain2_t)(BOOL abAlternative); ConsoleMain2_t lfConsoleMain2; #ifdef _DEBUG HMODULE hConEmuHk = GetModuleHandle(WIN3264TEST(L"ConEmuHk.dll",L"ConEmuHk64.dll")); _ASSERTE(hConEmuHk==NULL && "Hooks must not be loaded into ConEmuC[64].exe!"); #endif #if defined(SHOW_STARTED_MSGBOX) if (!IsDebuggerPresent()) { wchar_t szTitle[100]; _wsprintf(szTitle, SKIPLEN(countof(szTitle)) WIN3264TEST(L"ConEmuC",L"ConEmuC64") L" Loaded (PID=%i)", GetCurrentProcessId()); const wchar_t* pszCmdLine = GetCommandLineW(); MessageBox(NULL,pszCmdLine,szTitle,0); } #endif // Обязательно, иначе по CtrlC мы свалимся SetConsoleCtrlHandler((PHANDLER_ROUTINE)HandlerRoutine, true); #ifdef _DEBUG UnitTests(); #endif // Some command we can process internally if (ProcessCommandLine(iRc, hConEmu)) { // Done, exiting goto wrap; } // Otherwise - do the full cycle if (!hConEmu) hConEmu = LoadLibrary(WIN3264TEST(L"ConEmuCD.dll",L"ConEmuCD64.dll")); dwErr = GetLastError(); if (!hConEmu) { _wsprintf(szErrInfo, SKIPLEN(countof(szErrInfo)) L"Can't load library \"%s\", ErrorCode=0x%08X\n", WIN3264TEST(L"ConEmuCD.dll",L"ConEmuCD64.dll"), dwErr); _wprintf(szErrInfo); _ASSERTE(FALSE && "LoadLibrary failed"); iRc = CERR_CONEMUHK_NOTFOUND; goto wrap; } // Загрузить функи из ConEmuHk lfConsoleMain2 = (ConsoleMain2_t)GetProcAddress(hConEmu, "ConsoleMain2"); gfHandlerRoutine = (PHANDLER_ROUTINE)GetProcAddress(hConEmu, "HandlerRoutine"); if (!lfConsoleMain2 || !gfHandlerRoutine) { dwErr = GetLastError(); _wsprintf(szErrInfo, SKIPLEN(countof(szErrInfo)) L"Procedure \"%s\" not found in library \"%s\"", lfConsoleMain2 ? L"HandlerRoutine" : L"ConsoleMain2", WIN3264TEST(L"ConEmuCD.dll",L"ConEmuCD64.dll")); _wprintf(szErrInfo); _ASSERTE(FALSE && "GetProcAddress failed"); FreeLibrary(hConEmu); iRc = CERR_CONSOLEMAIN_NOTFOUND; goto wrap; } // Main dll entry point for Server & ComSpec iRc = lfConsoleMain2(0/*WorkMode*/); // Exiting gfHandlerRoutine = NULL; //FreeLibrary(hConEmu); -- Shutdown Server/Comspec уже выполнен wrap: //-- bottle neck: relatively long deinitialization ExitProcess(iRc); return iRc; }
// The function exists in both "ConEmuC/ConEmuC.cpp" and "ConEmuCD/Actions.cpp" // Version in "ConEmuC/ConEmuC.cpp" shows arguments from main(int argc, char** argv) // Version in "ConEmuCD/Actions.cpp" perhaps would not be ever called int DoParseArgs(LPCWSTR asCmdLine) { char szLine[80]; _wsprintfA(szLine, SKIPLEN(countof(szLine)) "main arguments (%i)\n", gn_argc); _printf(szLine); for (int j = 0; j < gn_argc; j++) { _wsprintfA(szLine, SKIPLEN(countof(szLine)) " %u: ", j); _printf(szLine); if (!gp_argv) { _printf("*NULL"); } else if (!gp_argv[j]) { _printf("<NULL>"); } else { _printf("`"); _printf(gp_argv[j]); _printf("`"); } _printf("\n"); } _printf("Parsing command\n `"); _wprintf(asCmdLine); _printf("`\n"); int iShellCount = 0; LPWSTR* ppszShl = CommandLineToArgvW(asCmdLine, &iShellCount); int i = 0; CEStr szArg; _printf("ConEmu `NextArg` splitter\n"); while (NextArg(&asCmdLine, szArg) == 0) { if (szArg.mb_Quoted) DemangleArg(szArg, true); _wsprintfA(szLine, SKIPLEN(countof(szLine)) " %u: `", ++i); _printf(szLine); _wprintf(szArg); _printf("`\n"); } _wsprintfA(szLine, SKIPLEN(countof(szLine)) " Total arguments parsed: %u\n", i); _printf(szLine); _printf("Standard shell splitter\n"); for (int j = 0; j < iShellCount; j++) { _wsprintfA(szLine, SKIPLEN(countof(szLine)) " %u: `", j); _printf(szLine); _wprintf(ppszShl[j]); _printf("`\n"); } _wsprintfA(szLine, SKIPLEN(countof(szLine)) " Total arguments parsed: %u\n", iShellCount); _printf(szLine); LocalFree(ppszShl); return i; }
// The function exists in both "ConEmuC/ConEmuC.cpp" and "ConEmuCD/Actions.cpp" // Version in "ConEmuC/ConEmuC.cpp" shows arguments from main(int argc, char** argv) // Version in "ConEmuCD/Actions.cpp" perhaps would not be ever called int DoParseArgs(LPCWSTR asCmdLine) { char szLine[80]; char szCLVer[32]; HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbi = {}; GetConsoleScreenBufferInfo(hOut, &csbi); struct Highlighter { HANDLE hOut; WORD defAttr; Highlighter(HANDLE ahOut, WORD adefAttr, WORD fore) : hOut(ahOut), defAttr(adefAttr) { SetConsoleTextAttribute(hOut, fore|(defAttr & 0xF0)); }; ~Highlighter() { SetConsoleTextAttribute(hOut, defAttr); }; }; #undef HL #define HL(fore) Highlighter hl(hOut, csbi.wAttributes, fore) #if defined(__GNUC__) lstrcpyn(szCLVer, "GNUC"); #elif defined(_MSC_VER) _wsprintfA(szCLVer, SKIPCOUNT(szCLVer) "VC %u.%u", (int)(_MSC_VER / 100), (int)(_MSC_VER % 100)); #else lstrcpyn(szCLVer, "<Unknown CL>"); #endif _wsprintfA(szLine, SKIPCOUNT(szLine) "main arguments (count %i) {%s}\n", gn_argc, szCLVer); { HL(10); _printf(szLine); } for (int j = 0; j < gn_argc; j++) { if (j >= 999) { HL(12); _printf("*** TOO MANY ARGUMENTS ***\n"); break; } _wsprintfA(szLine, SKIPCOUNT(szLine) " %u: ", j); { HL(2); _printf(szLine); } if (!gp_argv) { HL(12); _printf("*NULL"); } else if (!gp_argv[j]) { HL(12); _printf("<NULL>"); } else { { HL(8); _printf("`"); } { HL(15); _printf(gp_argv[j]); } { HL(8); _printf("`"); } } _printf("\n"); } { HL(10); _printf("Parsing command"); } { HL(8); _printf("\n `"); } { HL(15); _wprintf(asCmdLine); } { HL(8); _printf("`\n"); } int iShellCount = 0; LPWSTR* ppszShl = CommandLineToArgvW(asCmdLine, &iShellCount); int i = 0; CEStr szArg; { HL(10); _printf("ConEmu `NextArg` splitter\n"); } while (NextArg(&asCmdLine, szArg) == 0) { if (szArg.mb_Quoted) DemangleArg(szArg, true); _wsprintfA(szLine, SKIPCOUNT(szLine) " %u: ", ++i); { HL(2); _printf(szLine); } { HL(8); _printf("`"); } { HL(15); _wprintf(szArg); } { HL(8); _printf("`\n"); } } _wsprintfA(szLine, SKIPCOUNT(szLine) " Total arguments parsed: %u\n", i); { HL(8); _printf(szLine); } { HL(10); _printf("Standard shell splitter\n"); } for (int j = 0; j < iShellCount; j++) { _wsprintfA(szLine, SKIPCOUNT(szLine) " %u: ", j); { HL(2); _printf(szLine); } { HL(8); _printf("`"); } { HL(15); _wprintf(ppszShl[j]); } { HL(8); _printf("`\n"); } } _wsprintfA(szLine, SKIPCOUNT(szLine) " Total arguments parsed: %u\n", iShellCount); { HL(8); _printf(szLine); } LocalFree(ppszShl); return i; }
int ComspecInit() { TODO("Определить код родительского процесса, и если это FAR - запомнить его (для подключения к пайпу плагина)"); TODO("Размер получить из GUI, если оно есть, иначе - по умолчанию"); TODO("GUI может скорректировать размер с учетом полосы прокрутки"); WARNING("CreateFile(CONOUT$) по идее возвращает текущий ScreenBuffer. Можно его самим возвращать в ComspecDone"); // Правда нужно проверить, что там происходит с ghConOut.Close(),... // Размер должен менять сам GUI, через серверный ConEmuC! #ifdef SHOW_STARTED_MSGBOX MessageBox(GetConEmuHWND(2), L"ConEmuC (comspec mode) is about to START", L"ConEmuC.ComSpec", 0); #endif //int nNewBufferHeight = 0; //COORD crNewSize = {0,0}; //SMALL_RECT rNewWindow = gpSrv->sbi.srWindow; BOOL lbSbiRc = FALSE; gbRootWasFoundInCon = 2; // не добавлять к "Press Enter to close console" - "or wait" gbComspecInitCalled = TRUE; // Нельзя вызывать ComspecDone, если не было вызова ComspecInit // в режиме ComSpec - запрещено! gbAlwaysConfirmExit = FALSE; gbAutoDisableConfirmExit = FALSE; #ifdef _DEBUG xf_validate(); xf_dump_chk(); #endif // Это наверное и не нужно, просто для информации... lbSbiRc = GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &gpSrv->sbi); #ifdef _DEBUG DWORD nErrCode = lbSbiRc ? 0 : GetLastError(); // Процесс запущен с редиректом вывода? _ASSERTE(lbSbiRc || (nErrCode == ERROR_INVALID_HANDLE)); #endif #if 0 // 111211 - "-new_console" теперь передается в GUI и исполняется в нем // Сюда мы попадаем если был ключик -new_console // А этом случае нужно завершить ЭТОТ экземпляр и запустить в ConEmu новую вкладку if (gpSrv->bNewConsole) { #ifdef _DEBUG xf_validate(); xf_dump_chk(); #endif PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(pi)); STARTUPINFOW si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USECOUNTCHARS; si.dwXCountChars = gpSrv->sbi.dwSize.X; si.dwYCountChars = gpSrv->sbi.dwSize.Y; si.wShowWindow = SW_HIDE; PRINT_COMSPEC(L"Creating new console for:\n%s\n", gpszRunCmd); #ifdef _DEBUG xf_validate(); xf_dump_chk(); #endif // CREATE_NEW_PROCESS_GROUP - низя, перестает работать Ctrl-C // Запускается новый сервер (новая консоль), сюда хуки ставить не надо. BOOL lbRc = createProcess(TRUE, NULL, gpszRunCmd, NULL,NULL, TRUE, NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); DWORD dwErr = GetLastError(); if (!lbRc) { PrintExecuteError(gpszRunCmd, dwErr); return CERR_CREATEPROCESS; } #ifdef _DEBUG xf_validate(); xf_dump_chk(); #endif //delete psNewCmd; psNewCmd = NULL; AllowSetForegroundWindow(pi.dwProcessId); PRINT_COMSPEC(L"New console created. PID=%i. Exiting...\n", pi.dwProcessId); SafeCloseHandle(pi.hProcess); SafeCloseHandle(pi.hThread); DisableAutoConfirmExit(); //gpSrv->nProcessStartTick = GetTickCount() - 2*CHECK_ROOTSTART_TIMEOUT; // менять nProcessStartTick не нужно. проверка только по флажкам #ifdef _DEBUG xf_validate(); xf_dump_chk(); #endif return CERR_RUNNEWCONSOLE; } #endif // Если определена ComSpecC - значит ConEmuC переопределил стандартный ComSpec // Вернем его wchar_t szComSpec[MAX_PATH+1]; const wchar_t* pszComSpecName; //110202 - comspec более не переопределяется //if (GetEnvironmentVariable(L"ComSpecC", szComSpec, MAX_PATH) && szComSpec[0] != 0) WARNING("TCC/ComSpec"); if (GetEnvironmentVariable(L"ComSpec", szComSpec, MAX_PATH) && szComSpec[0] != 0) { //// Только если это (случайно) не conemuc.exe //wchar_t* pwszCopy = (wchar_t*)PointToName(szComSpec); //wcsrchr(szComSpec, L'\\'); ////if (!pwszCopy) pwszCopy = szComSpec; //#pragma warning( push ) //#pragma warning(disable : 6400) //if (lstrcmpiW(pwszCopy, L"ConEmuC")==0 || lstrcmpiW(pwszCopy, L"ConEmuC.exe")==0 // /*|| lstrcmpiW(pwszCopy, L"ConEmuC64")==0 || lstrcmpiW(pwszCopy, L"ConEmuC64.exe")==0*/) // szComSpec[0] = 0; //#pragma warning( pop ) //if (szComSpec[0]) //{ // SetEnvironmentVariable(L"ComSpec", szComSpec); // SetEnvironmentVariable(L"ComSpecC", NULL); //} pszComSpecName = (wchar_t*)PointToName(szComSpec); } else { WARNING("TCC/ComSpec"); pszComSpecName = L"cmd.exe"; } lstrcpyn(gpSrv->szComSpecName, pszComSpecName, countof(gpSrv->szComSpecName)); if (pszComSpecName) { wchar_t szSelf[MAX_PATH+1]; if (GetModuleFileName(NULL, szSelf, MAX_PATH)) { lstrcpyn(gpSrv->szSelfName, (wchar_t*)PointToName(szSelf), countof(gpSrv->szSelfName)); if (!GetAliases(gpSrv->szSelfName, &gpSrv->pszPreAliases, &gpSrv->nPreAliasSize)) { if (gpSrv->pszPreAliases) { _wprintf(gpSrv->pszPreAliases); free(gpSrv->pszPreAliases); gpSrv->pszPreAliases = NULL; } } } } SendStarted(); //ConOutCloseHandle() return 0; }
void ComspecDone(int aiRc) { #ifdef _DEBUG xf_dump_chk(); xf_validate(NULL); #endif //WARNING("Послать в GUI CONEMUCMDSTOPPED"); LogSize(NULL, 0, "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), FALSE, 0, TRUE); 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, 0, ":ComspecDone.RetSize.before"); SetConsoleSize(0, sbi2.dwSize, rc, "ComspecDone.Force"); if (gpLogSize) LogSize(NULL, 0, ":ComspecDone.RetSize.after"); } } } } if (gpSrv->pszPreAliases) { free(gpSrv->pszPreAliases); gpSrv->pszPreAliases = NULL; } //SafeCloseHandle(ghCtrlCEvent); //SafeCloseHandle(ghCtrlBreakEvent); }
// 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); } }
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; }