// anConEmuOnly // 0 - если в ConEmu - вернуть окно отрисовки, иначе - вернуть окно консоли // 1 - вернуть окно отрисовки // 2 - вернуть главное окно ConEmu // 3 - вернуть окно консоли HWND WINAPI GetFarHWND2(int anConEmuOnly) { // Если просили реальное окно консоли - вернем сразу if (anConEmuOnly == 3) { return FarHwnd; } if (ghConEmuWndDC) { if (IsWindow(ghConEmuWndDC)) { if (anConEmuOnly == 2) return GetConEmuHWND(1); return ghConEmuWndDC; } // ghConEmuWndDC = NULL; // SetConEmuEnvVar(NULL); SetConEmuEnvVarChild(NULL,NULL); } if (anConEmuOnly) return NULL; return FarHwnd; }
// 0 -- All OK (ConEmu found, Version OK) // 1 -- NO ConEmu (simple console mode) // (obsolete) 2 -- ConEmu found, but old version int ConEmuCheck(HWND* ahConEmuWnd) { //int nChk = -1; HWND ConEmuWnd = NULL; ConEmuWnd = GetConEmuHWND(FALSE/*abRoot*/ /*, &nChk*/); // Если хотели узнать хэндл - возвращаем его if (ahConEmuWnd) *ahConEmuWnd = ConEmuWnd; if (ConEmuWnd == NULL) { return 1; // NO ConEmu (simple console mode) } else { //if (nChk>=3) // return 2; // ConEmu found, but old version return 0; } }
int RunDebugger() { if (!gpSrv->DbgInfo.pDebugTreeProcesses) { gpSrv->DbgInfo.pDebugTreeProcesses = (MMap<DWORD,CEDebugProcessInfo>*)calloc(1,sizeof(*gpSrv->DbgInfo.pDebugTreeProcesses)); gpSrv->DbgInfo.pDebugTreeProcesses->Init(1024); } UpdateDebuggerTitle(); // Если это новая консоль - увеличить ее размер, для удобства if (IsWindowVisible(ghConWnd)) { HANDLE hCon = ghConOut; CONSOLE_SCREEN_BUFFER_INFO csbi = {}; GetConsoleScreenBufferInfo(hCon, &csbi); if (csbi.dwSize.X < 260) { COORD crNewSize = {260, 9999}; SetConsoleScreenBufferSize(ghConOut, crNewSize); } //if ((csbi.srWindow.Right - csbi.srWindow.Left + 1) < 120) //{ // COORD crMax = GetLargestConsoleWindowSize(hCon); // if ((crMax.X - 10) > (csbi.srWindow.Right - csbi.srWindow.Left + 1)) // { // COORD crSize = {((int)((crMax.X - 15)/10))*10, min(crMax.Y, (csbi.srWindow.Bottom - csbi.srWindow.Top + 1))}; // SMALL_RECT srWnd = {0, csbi.srWindow.Top, crSize.X - 1, csbi.srWindow.Bottom}; // MONITORINFO mi = {sizeof(mi)}; // GetMonitorInfo(MonitorFromWindow(ghConWnd, MONITOR_DEFAULTTONEAREST), &mi); // RECT rcWnd = {}; GetWindowRect(ghConWnd, &rcWnd); // SetWindowPos(ghConWnd, NULL, min(rcWnd.left,(mi.rcWork.left+50)), rcWnd.top, 0,0, SWP_NOSIZE|SWP_NOZORDER); // SetConsoleSize(9999, crSize, srWnd, "StartDebugger"); // } //} } // Вывести в консоль информацию о версии. PrintVersion(); #ifdef SHOW_DEBUG_STARTED_MSGBOX wchar_t szInfo[128]; StringCchPrintf(szInfo, countof(szInfo), L"Attaching debugger...\nConEmuC PID = %u\nDebug PID = %u", GetCurrentProcessId(), gpSrv->dwRootProcess); MessageBox(GetConEmuHWND(2), szInfo, L"ConEmuC.Debugger", 0); #endif //if (!DebugActiveProcess(gpSrv->dwRootProcess)) //{ // DWORD dwErr = GetLastError(); // _printf("Can't start debugger! ErrCode=0x%08X\n", dwErr); // 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(); if (gpSrv->DbgInfo.pszDebuggingCmdLine == NULL) { int iAttachRc = AttachRootProcessHandle(); if (iAttachRc != 0) return iAttachRc; } else { _ASSERTE(!gpSrv->DbgInfo.bDebuggerActive); } _ASSERTE(((gpSrv->hRootProcess!=NULL) || (gpSrv->DbgInfo.pszDebuggingCmdLine!=NULL)) && "Process handle must be opened"); gpSrv->DbgInfo.hDebugReady = CreateEvent(NULL, FALSE, FALSE, NULL); // Перенес обработку отладочных событий в отдельную нить, чтобы случайно не заблокироваться с главной gpSrv->DbgInfo.hDebugThread = CreateThread(NULL, 0, DebugThread, NULL, 0, &gpSrv->DbgInfo.dwDebugThreadId); HANDLE hEvents[2] = {gpSrv->DbgInfo.hDebugReady, gpSrv->DbgInfo.hDebugThread}; DWORD nReady = WaitForMultipleObjects(countof(hEvents), hEvents, FALSE, INFINITE); if (nReady != WAIT_OBJECT_0) { DWORD nExit = 0; GetExitCodeThread(gpSrv->DbgInfo.hDebugThread, &nExit); return nExit; } gpszRunCmd = (wchar_t*)calloc(1,2); if (!gpszRunCmd) { _printf("Can't allocate 1 wchar!\n"); return CERR_NOTENOUGHMEM1; } gpszRunCmd[0] = 0; gpSrv->DbgInfo.bDebuggerActive = TRUE; // And wait for debugger thread completion _ASSERTE(gnRunMode == RM_UNDEFINED); DWORD nDebugThread = WaitForSingleObject(gpSrv->DbgInfo.hDebugThread, INFINITE); _ASSERTE(nDebugThread == WAIT_OBJECT_0); UNREFERENCED_PARAMETER(nDebugThread); gbInShutdown = TRUE; return 0; }
int MyAssertProc(const wchar_t* pszFile, int nLine, const wchar_t* pszTest, bool abNoPipe) { #ifdef _DEBUG bool lbSkip = false; if (lbSkip) return 1; #endif HANDLE hHeap = GetProcessHeap(); MyAssertInfo* pa = (MyAssertInfo*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(MyAssertInfo)); wchar_t *szExeName = (wchar_t*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, (MAX_PATH+1)*sizeof(wchar_t)); if (!GetModuleFileNameW(NULL, szExeName, MAX_PATH+1)) szExeName[0] = 0; pa->bNoPipe = abNoPipe; msprintf(pa->szTitle, countof(pa->szTitle), L"CEAssert PID=%u TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); msprintf(pa->szDebugInfo, countof(pa->szDebugInfo), L"Assertion in %s\n%s\n\n%s: %i\n\nPress 'Retry' to trap.", szExeName, pszTest ? pszTest : L"", pszFile, nLine); DWORD dwCode = 0; if (gAllowAssertThread == am_Thread) { DWORD dwTID; HANDLE hThread = CreateThread(NULL, 0, MyAssertThread, pa, 0, &dwTID); if (hThread == NULL) { dwCode = IDRETRY; goto wrap; } WaitForSingleObject(hThread, INFINITE); GetExitCodeThread(hThread, &dwCode); CloseHandle(hThread); goto wrap; } #ifdef ASSERT_PIPE_ALLOWED #ifdef _DEBUG if (!abNoPipe && (gAllowAssertThread == am_Pipe)) { HWND hConWnd = GetConEmuHWND(2); HWND hGuiWnd = ghConEmuWnd; // -- искать - нельзя. Если мы НЕ в ConEmu - нельзя стучаться в другие копии!!! //#ifndef CONEMU_MINIMAL //if (hGuiWnd == NULL) //{ // hGuiWnd = FindWindowEx(NULL, NULL, VirtualConsoleClassMain, NULL); //} //#endif if (hGuiWnd && !gbInMyAssertTrap) { gbInMyAssertTrap = true; gbInMyAssertPipe = true; gnInMyAssertThread = GetCurrentThreadId(); ResetEvent(ghInMyAssertTrap); dwCode = GuiMessageBox(abNoPipe ? NULL : hGuiWnd, pa->szDebugInfo, pa->szTitle, MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_RETRYCANCEL); gbInMyAssertTrap = false; gbInMyAssertPipe = false; SetEvent(ghInMyAssertTrap); gnInMyAssertThread = 0; goto wrap; } } while (gbInMyAssertPipe && (gnInMyAssertThread != GetCurrentThreadId())) { Sleep(250); } #endif #endif // В консольных приложениях попытка запустить CreateThread(MyAssertThread) может зависать dwCode = MyAssertThread(pa); wrap: if (pa) HeapFree(hHeap, 0, pa); if (szExeName) HeapFree(hHeap, 0, szExeName); return (dwCode == IDRETRY) ? -1 : 1; }
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); }
int RunDebugger() { if (!gpSrv->DbgInfo.pDebugTreeProcesses) { gpSrv->DbgInfo.pDebugTreeProcesses = (MMap<DWORD,CEDebugProcessInfo>*)calloc(1,sizeof(*gpSrv->DbgInfo.pDebugTreeProcesses)); gpSrv->DbgInfo.pDebugTreeProcesses->Init(1024); } UpdateDebuggerTitle(); // Если это новая консоль - увеличить ее размер, для удобства if (IsWindowVisible(ghConWnd)) { HANDLE hCon = ghConOut; CONSOLE_SCREEN_BUFFER_INFO csbi = {}; GetConsoleScreenBufferInfo(hCon, &csbi); if (csbi.dwSize.X < 260) { COORD crNewSize = {260, 9999}; SetConsoleScreenBufferSize(ghConOut, crNewSize); } //if ((csbi.srWindow.Right - csbi.srWindow.Left + 1) < 120) //{ // COORD crMax = GetLargestConsoleWindowSize(hCon); // if ((crMax.X - 10) > (csbi.srWindow.Right - csbi.srWindow.Left + 1)) // { // COORD crSize = {((int)((crMax.X - 15)/10))*10, min(crMax.Y, (csbi.srWindow.Bottom - csbi.srWindow.Top + 1))}; // SMALL_RECT srWnd = {0, csbi.srWindow.Top, crSize.X - 1, csbi.srWindow.Bottom}; // MONITORINFO mi = {sizeof(mi)}; // GetMonitorInfo(MonitorFromWindow(ghConWnd, MONITOR_DEFAULTTONEAREST), &mi); // RECT rcWnd = {}; GetWindowRect(ghConWnd, &rcWnd); // SetWindowPos(ghConWnd, NULL, min(rcWnd.left,(mi.rcWork.left+50)), rcWnd.top, 0,0, SWP_NOSIZE|SWP_NOZORDER); // SetConsoleSize(9999, crSize, srWnd, "StartDebugger"); // } //} } // Вывести в консоль информацию о версии. PrintVersion(); #ifdef SHOW_DEBUG_STARTED_MSGBOX wchar_t szInfo[128]; StringCchPrintf(szInfo, countof(szInfo), L"Attaching debugger...\n" CE_CONEMUC_NAME_W " PID = %u\nDebug PID = %u", GetCurrentProcessId(), gpSrv->dwRootProcess); MessageBox(GetConEmuHWND(2), szInfo, CE_CONEMUC_NAME_W L".Debugger", 0); #endif if (gpSrv->DbgInfo.pszDebuggingCmdLine == NULL) { int iAttachRc = AttachRootProcessHandle(); if (iAttachRc != 0) return iAttachRc; } else { _ASSERTE(!gpSrv->DbgInfo.bDebuggerActive); } gpszRunCmd = (wchar_t*)calloc(1,sizeof(*gpszRunCmd)); if (!gpszRunCmd) { _printf("Can't allocate 1 wchar!\n"); return CERR_NOTENOUGHMEM1; } _ASSERTE(((gpSrv->hRootProcess!=NULL) || (gpSrv->DbgInfo.pszDebuggingCmdLine!=NULL)) && "Process handle must be opened"); // Если просили сделать дамп нескольких процессов - нужно сразу уточнить его тип if (gpSrv->DbgInfo.bDebugMultiProcess && (gpSrv->DbgInfo.nDebugDumpProcess == 1)) { // 2 - minidump, 3 - fulldump int nConfirmDumpType = ConfirmDumpType(gpSrv->dwRootProcess, NULL); if (nConfirmDumpType < 2) { // Отмена return CERR_CANTSTARTDEBUGGER; } gpSrv->DbgInfo.nDebugDumpProcess = nConfirmDumpType; } // gpSrv->DbgInfo.bDebuggerActive must be set in DebugThread // Run DebugThread gpSrv->DbgInfo.hDebugReady = CreateEvent(NULL, FALSE, FALSE, NULL); // Перенес обработку отладочных событий в отдельную нить, чтобы случайно не заблокироваться с главной gpSrv->DbgInfo.hDebugThread = CreateThread(NULL, 0, DebugThread, NULL, 0, &gpSrv->DbgInfo.dwDebugThreadId); HANDLE hEvents[2] = {gpSrv->DbgInfo.hDebugReady, gpSrv->DbgInfo.hDebugThread}; DWORD nReady = WaitForMultipleObjects(countof(hEvents), hEvents, FALSE, INFINITE); if (nReady != WAIT_OBJECT_0) { DWORD nExit = 0; GetExitCodeThread(gpSrv->DbgInfo.hDebugThread, &nExit); return nExit; } // gpSrv->DbgInfo.bDebuggerActive was set in DebugThread // And wait for debugger thread completion _ASSERTE(gnRunMode == RM_UNDEFINED); DWORD nDebugThread = WaitForSingleObject(gpSrv->DbgInfo.hDebugThread, INFINITE); _ASSERTE(nDebugThread == WAIT_OBJECT_0); UNREFERENCED_PARAMETER(nDebugThread); gbInShutdown = TRUE; return 0; }