bool MSection::MyEnterCriticalSection(DWORD anTimeout) { DWORD nCurTID = GetCurrentThreadId(), nExclWait = -1; //EnterCriticalSection(&m_cs); // дождаться пока секцию отпустят // НАДА. Т.к. может быть задан nTimeout (для DC) DWORD dwTryLockSectionStart = GetTickCount(), dwCurrentTick; if (!m_cs.TryEnter()) { Sleep(10); while (!m_cs.TryEnter()) { if ((mn_TID != nCurTID) && mh_ExclusiveThread) { BOOL lbLocked = FALSE; if (mh_ExclusiveThread) { HANDLE h = mh_ExclusiveThread; nExclWait = WaitForSingleObject(h, 0); if (nExclWait != WAIT_TIMEOUT) { // Все, m_cs протух. Его нужно пересоздать Process_Lock(); // Первым выполнить Process_Lock мог другой поток. // Нужно проверить хэндл на соответствие, если он другой // то на этом шаге уже не дергаться if (h == mh_ExclusiveThread) { _ASSERTEX(FALSE && "Exclusively locked thread was abnormally terminated?"); SafeCloseHandle(mh_ExclusiveThread); lbLocked = m_cs.RecreateAndLock(); _ASSERTEX(mn_LockedTID[0] = mn_TID); mn_LockedTID[0] = 0; if (mn_LockedCount[0] > 0) { mn_LockedCount[0] --; // на [0] mn_Locked не распространяется } mn_TID = nCurTID; } Process_Unlock(); } } if (lbLocked) { break; } } Sleep(10); DEBUGSTR(L"TryEnterCriticalSection failed!!!\n"); dwCurrentTick = GetTickCount(); if (anTimeout != (DWORD)-1) { if (((dwCurrentTick - dwTryLockSectionStart) > anTimeout)) { #ifndef CSECTION_NON_RAISE _ASSERTEX((dwCurrentTick - dwTryLockSectionStart) <= anTimeout); #endif return false; } } #ifdef _DEBUG else if ((dwCurrentTick - dwTryLockSectionStart) > 3000) { #ifndef CSECTION_NON_RAISE _ASSERTEX((dwCurrentTick - dwTryLockSectionStart) <= 3000); #endif dwTryLockSectionStart = GetTickCount(); } #endif } } return true; }
BOOL MSection::Lock(BOOL abExclusive, DWORD anTimeout/*=-1*/) { DWORD dwTID = GetCurrentThreadId(); // Может эта нить уже полностью заблокирована? if (mb_Exclusive && dwTID == mn_TID) { //111126 возвращался FALSE _ASSERTEX(!mb_Exclusive || dwTID != mn_TID); return TRUE; // Уже, но Unlock делать не нужно! } if (!abExclusive) { if (!mb_Exclusive) { // Быстрая блокировка, не запрещающая чтение другим нитям. // Запрещено только изменение (пересоздание буфера например) AddRef(dwTID); } // Если другая нить уже захватила exclusive else //if (mb_Exclusive) { _ASSERTEX(mb_Exclusive); //int nLeft = ReleaseRef(dwTID); // Иначе можем попасть на взаимную блокировку //if (nLeft > 0) //{ // // Нужно избегать этого. Значит выше по стеку в этой нити // // более одного раза был выполнен non exclusive lock // _ASSERTEX(nLeft == 0); //} #ifdef _DEBUG int nInThreadLeft = 0; for (int i=1; i<countof(mn_LockedTID); i++) { if (mn_LockedTID[i] == dwTID) { _ASSERTEX(mn_LockedCount[i]>=0); nInThreadLeft = mn_LockedCount[i]; break; } } if (nInThreadLeft > 0) { // Нужно избегать этого. Значит выше по стеку в этой нити // более одного раза был выполнен non exclusive lock _ASSERTEX(nInThreadLeft == 0); } #endif DEBUGSTR(L"!!! Failed non exclusive lock, trying to use CriticalSection\n"); bool lbEntered = MyEnterCriticalSection(anTimeout); // дождаться пока секцию отпустят // mb_Exclusive может быть выставлен, если сейчас другая нить пытается выполнить exclusive lock _ASSERTEX(!mb_Exclusive); // После LeaveCriticalSection mb_Exclusive УЖЕ должен быть сброшен AddRef(dwTID); // накрутить счетчик // Но поскольку нам нужен только nonexclusive lock if (lbEntered) m_cs.Leave(); } } else // abExclusive { // Требуется Exclusive Lock #ifdef _DEBUG if (mb_Exclusive) { // Этого надо стараться избегать DEBUGSTR(L"!!! Exclusive lock found in other thread\n"); } #endif // Если есть ExclusiveLock (в другой нити) - дождется сама EnterCriticalSection #ifdef _DEBUG BOOL lbPrev = mb_Exclusive; DWORD nPrevTID = mn_TID; #endif // Сразу установим mb_Exclusive, чтобы в других нитях случайно не прошел nonexclusive lock // иначе может получиться, что nonexclusive lock мешает выполнить exclusive lock (ждут друг друга) mb_Exclusive = TRUE; TODO("Need to check, if MyEnterCriticalSection failed on timeout!\n"); if (!MyEnterCriticalSection(anTimeout)) { // Пока поставил _ASSERTE, чтобы посмотреть, возникают ли Timeout-ы при блокировке _ASSERTEX(FALSE); if (mn_TID == 0) // поскольку заблокировать не удалось - сбросим флажок mb_Exclusive = FALSE; return FALSE; } // 120710 - добавил "|| (mn_TID==dwTID)". Это в том случае, если предыдущая ExclusiveThread была прибита. _ASSERTEX(!(lbPrev && mb_Exclusive) || (mn_TID==dwTID)); // После LeaveCriticalSection mb_Exclusive УЖЕ должен быть сброшен mn_TID = dwTID; // И запомним, в какой нити это произошло HANDLE h = mh_ExclusiveThread; mh_ExclusiveThread = OpenThread(SYNCHRONIZE, FALSE, dwTID); SafeCloseHandle(h); mb_Exclusive = TRUE; // Флаг могла сбросить другая нить, выполнившая Leave _ASSERTEX(mn_LockedTID[0] == 0 && mn_LockedCount[0] == 0); mn_LockedTID[0] = dwTID; mn_LockedCount[0] ++; // на [0] mn_Locked не распространяется /*if (abRelockExclusive) { ReleaseRef(dwTID); // Если до этого был nonexclusive lock }*/ // B если есть nonexclusive locks - дождаться их завершения if (mn_Locked) { //WARNING: Тут есть шанс наколоться, если сначала был NonExclusive, а потом в этой же нити - Exclusive // В таких случаях нужно вызывать с параметром abRelockExclusive WaitUnlocked(dwTID, anTimeout); } } return TRUE; }
// Warning, напрямую НЕ вызывать. Пользоваться "общей" PostMacro void CPluginW2800::PostMacroApi(const wchar_t* asMacro, INPUT_RECORD* apRec, bool abShowParseErrors) { if (!InfoW2800 || !InfoW2800->AdvControl) return; MacroSendMacroText mcr = {sizeof(MacroSendMacroText)}; //mcr.Flags = 0; // По умолчанию - вывод на экран разрешен bool bEnableOutput = true; while ((asMacro[0] == L'@' || asMacro[0] == L'^') && asMacro[1] && asMacro[1] != L' ') { switch (*asMacro) { case L'@': bEnableOutput = false; break; case L'^': mcr.Flags |= KMFLAGS_NOSENDKEYSTOPLUGINS; break; } asMacro++; } if (bEnableOutput) mcr.Flags |= KMFLAGS_ENABLEOUTPUT; // This macro was not adopted to Lua? _ASSERTE(*asMacro && *asMacro != L'$'); // Вообще говоря, если тут попадается макрос в старом формате - то мы уже ничего не сделаем... // Начиная с Far 3 build 2851 - все макросы переведены на Lua mcr.SequenceText = asMacro; if (apRec) mcr.AKey = *apRec; mcr.Flags |= KMFLAGS_SILENTCHECK; if (!InfoW2800->MacroControl(&guid_ConEmu, MCTL_SENDSTRING, MSSC_CHECK, &mcr)) { if (abShowParseErrors) { wchar_t* pszErrText = NULL; size_t iRcSize = InfoW2800->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"); InfoW2800->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] {2800}\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] {2800}\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 = CreateThread(NULL, 0, BackgroundMacroError, pszErrText, 0, &nTID); SafeCloseHandle(h); } } } else { //gFarVersion.dwBuild InfoW2800->MacroControl(&guid_ConEmu, MCTL_SENDSTRING, 0, &mcr); } }
// accept処理を非同期で行う unsigned __stdcall I4C3DReceiveThreadProc(void* pParam) { LoggingMessage(Log_Debug, _T(MESSAGE_DEBUG_PROCESSING), GetLastError(), g_FILE, __LINE__); I4C3DContext* pContext = (I4C3DContext*)pParam; SOCKET newClient = NULL; SOCKADDR_IN address = {0}; int nLen = 0; HANDLE hChildThread = NULL; UINT uThreadID = 0; I4C3DChildContext* pChildContext = NULL; char cTermination = 0; DWORD dwResult = 0; WSAEVENT hEvent = NULL; WSAEVENT hEventArray[2] = {0}; WSANETWORKEVENTS events = {0}; hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (hEvent == NULL) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); I4C3DExit(EXIT_SYSTEM_ERROR); return EXIT_SYSTEM_ERROR; } I4C3DAccessor accessor; if (!accessor.SetListeningSocket(pContext->receiver, &pContext->address, g_backlog, hEvent, FD_ACCEPT | FD_CLOSE)) { SafeCloseHandle(hEvent); I4C3DExit(EXIT_SOCKET_ERROR); return EXIT_SOCKET_ERROR; } hEventArray[0] = hEvent; hEventArray[1] = pContext->hStopEvent; for (;;) { dwResult = WSAWaitForMultipleEvents(2, hEventArray, FALSE, WSA_INFINITE, FALSE); if (dwResult == WSA_WAIT_FAILED) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); break; } if (dwResult - WSA_WAIT_EVENT_0 == 0) { WSAEnumNetworkEvents(pContext->receiver, hEvent, &events); if (events.lNetworkEvents & FD_CLOSE) { break; } else if (events.lNetworkEvents & FD_ACCEPT) { // accept if ( !CheckChildThreadCount() ) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); continue; } nLen = sizeof(address); newClient = accept(pContext->receiver, (SOCKADDR*)&address, &nLen); if (newClient == INVALID_SOCKET) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_SOCKET_INVALID), GetLastError(), g_FILE, __LINE__); break; } // Create child thread. pChildContext = (I4C3DChildContext*)calloc(1, sizeof(I4C3DChildContext)); if (pChildContext == NULL) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); break; } // 設定ファイルから終端文字を取得 if (cTermination == 0) { GetTerminationFromFile(pContext, &cTermination); } pChildContext->cTermination = cTermination; pChildContext->pContext = pContext; pChildContext->clientSocket = newClient; hChildThread = (HANDLE)_beginthreadex(NULL, 0, I4C3DAcceptedThreadProc, pChildContext, CREATE_SUSPENDED, &uThreadID); if (hChildThread == INVALID_HANDLE_VALUE) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); break; } else { pChildContext->hChildThread = hChildThread; AddChildThread( hChildThread ); ResumeThread(hChildThread); } } } else if (dwResult - WSA_WAIT_EVENT_0 == 1) { RemoveAllChildThread(); pContext->pController->UnInitialize(); break; } } SafeCloseHandle(hEvent); shutdown(pContext->receiver, SD_BOTH); closesocket(pContext->receiver); LoggingMessage(Log_Debug, _T(MESSAGE_DEBUG_PROCESSING), GetLastError(), g_FILE, __LINE__); return EXIT_SUCCESS; }
// // Invoke() // // invoke the GIB program and return the recommended play // int CGIB::Invoke(CPlayer* pPlayer, CHandHoldings* pHand, CHandHoldings* pDummyHand, CPlayerStatusDialog* pStatusDlg) { SECURITY_ATTRIBUTES saAttr; // // create the GIB monitor dialog // CGIBDialog gibDialog(pMAINFRAME); int nProcessingTime = theApp.GetValue(tnGIBAnalysisTime); gibDialog.m_nProcessTime = nProcessingTime; // gibDialog.m_hEventCancel = m_hEventCancel; // Set the bInheritHandle flag so pipe handles are inherited. saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // // create input and output pipes for the child process // // Create a pipe for the child process's STDOUT. if (!CreatePipe(&m_hChildStdoutRd, // returns the pipe's input handle &m_hChildStdoutWr, // returns the pipe's output handle &saAttr, 0)) { CString strError = "Stdout pipe creation failed\n"; TRACE(strError); pMAINFRAME->SetGIBMonitorText(strError); return ExitGracefully(-5); } // then create a pipe for the child process's STDIN. if (!CreatePipe(&m_hChildStdinRd, &m_hChildStdinWr, &saAttr, 0)) { CString strError = "Stdin pipe creation failed\n"; TRACE(strError); pMAINFRAME->SetGIBMonitorText(strError); return ExitGracefully(-5); } // // Now create the child process (GIB) // PROCESS_INFORMATION piProcInfo; if (!LaunchProgram(piProcInfo)) { TRACE("Create process failed"); return ExitGracefully(-1); } HANDLE hGIBProcess = piProcInfo.hProcess; DWORD nGIBProcessID = piProcInfo.dwProcessId; // now close the readable handle to the child's stdin SafeCloseHandle(m_hChildStdinRd); // and the writable handle to the child's stdout SafeCloseHandle(m_hChildStdoutWr); // //------------------------------------------------------------------ // // create the GIB input file // CFile file; CFileException fileException; CString strTempFile, strTempPath; GetTempPath(1024, strTempPath.GetBuffer(1024)); strTempPath.ReleaseBuffer(); GetTempFileName(strTempPath, "ezb", 0, strTempFile.GetBuffer(2048)); strTempFile.ReleaseBuffer(); // strTempFile.Format("%s\\%s", theApp.GetValueString(tszProgramDirectory), tszGIBTempFilename); /* LPTSTR szBuffer = strTempFile.GetBuffer(MAX_PATH); GetTempFileName(theApp.GetValueString(tszProgramDirectory), "ezb", 0, szBuffer); strTempFile.ReleaseBuffer(); */ // CString strInput; // strInput.Format("-T %d %s\n",theApp.GetValue(tnGIBAnalysisTime),strTempFile); int nCode = file.Open(strTempFile, CFile::modeWrite | CFile::modeCreate | CFile::shareDenyWrite, &fileException); if (nCode == 0) { CString strError = "Error opening temporary input file for GIB"; TRACE(strError); pMAINFRAME->SetGIBMonitorText(strError); return ExitGracefully(-2); } // CString strFileContents; CreateGIBInputFile(file, pPlayer, pHand, pDummyHand, strFileContents); file.Close(); // then send the parameters line CString strParameters, strShortParameters; strParameters.Format("-T %d %s\n",nProcessingTime,strTempFile); strShortParameters.Format("-T %d",nProcessingTime); DWORD dwWritten; int nErrCode; if (!WriteFile(m_hChildStdinWr, (LPCTSTR)strParameters, strParameters.GetLength(), &dwWritten, NULL)) { CString strError = "Error providing parameters to GIB"; TRACE(strError); pMAINFRAME->SetGIBMonitorText(strError); nErrCode = GetLastError(); return ExitGracefully(-3); } // // update the GIB monitor window // CString strGIBText = "========================================\n"; strGIBText += FormString("Launching %s %s\n", theApp.GetValueString(tszGIBPath), strShortParameters); // strGIBText += FormString("Input file contents:\n%s", strFileContents); strGIBText += "Awaiting Responses...\n"; strGIBText += "----------------------------------------\n"; // pMAINFRAME->SetGIBMonitorText(strGIBText); pMAINFRAME->AppendGIBMonitorText(strGIBText); // //------------------------------------------------------------ // // now set up the wait loop and the cancel dialog, // then sit and wait for the process to run or for a cancel message // /* // // create the "Cancel GIB" dialog thread // (this is a user interface thread) // CGIBMonitorThread* pMonitorThread = new CGIBMonitorThread(m_hEventFinished, m_hEventCancel, nProcessingTime); pMonitorThread->CreateThread(CREATE_SUSPENDED); pMonitorThread->SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL); pMonitorThread->ResumeThread(); // wait for the monitor thread to initialize DWORD nCode0 = WaitForSingleObject(m_hEventFinished, INFINITE); */ // // create the wait thread // (this is a worker thread) // GIBStruct gibData; gibData.hReadHandle = m_hChildStdoutRd; gibData.pGIBDialog = &gibDialog; CWinThread* pWaitThread = AfxBeginThread(CGIB::ReadGIBOutput, &gibData, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); // copy its handle se that we can check its exit code later HANDLE hWaitThread; BOOL bCode = ::DuplicateHandle(GetCurrentProcess(), pWaitThread->m_hThread, GetCurrentProcess(), &hWaitThread, 0, FALSE, DUPLICATE_SAME_ACCESS); // and launch the threads // MonitorThread->ResumeThread(); pWaitThread->ResumeThread(); // // Show the Wait/Cancel dialog // m_bGIBPending = TRUE; // mark dialog as active bCode = gibDialog.DoModal(); // see if the user cancelled if (!bCode) { /* // lock out the wait thread and cancel operations if (ClearGIBPending()) { */ // pMAINFRAME->SetStatusText("GIB cancelled."); // TerminateProcess(hGIBProcess, 0); TerminateThread(hWaitThread, 0); // wait for the read thread to end WaitForSingleObject(hWaitThread, INFINITE); // close the wait thread handle CloseHandle(hWaitThread); CloseHandle(hGIBProcess); // and delete the thread object delete pWaitThread; // close pipe handles SafeCloseHandle(m_hChildStdinWr); SafeCloseHandle(m_hChildStdoutRd); // and throw an exception throw CGIBException(); // } } /* // set up events HANDLE eventArray[2]; eventArray[0] = m_hEventCancel; eventArray[1] = pWaitThread->m_hThread; // // then sit back and wait for the thread(s) // for(;;) { // wait for the cancelled or finished messages DWORD nCode = WaitForMultipleObjects(2, // 2 events to wait for eventArray, // events array FALSE, // not all at once INFINITE); // wait 4-ever // if (nCode == WAIT_FAILED) { ASSERT(FALSE); break; } else if (nCode == WAIT_OBJECT_0) { // got the cancel message, so kill GIB & the wait thread // the following is very dangersous -- // so kids, don't try this at home TerminateThread(pWaitThread, 0); TerminateProcess(hGIBProcess, 0); return GIB_CANCEL; } else if (nCode == WAIT_OBJECT_0 + 1) { // GIB finished message // signal the GIB monitor that GIB has finished SetEvent(m_hEventFinished); break; } } */ // //------------------------------------------------------------ // // presumably, GIB has finished running // // wait for the GIB thread to exit, then get the card code DWORD nCardPlayed, nErrorCode; bCode = WaitForSingleObject(hWaitThread, INFINITE); bCode = GetExitCodeThread(hWaitThread, &nCardPlayed); if (!bCode) nErrorCode = GetLastError(); // close the wait thread handle CloseHandle(hWaitThread); // delete the temporary file DeleteFile(strTempFile); // and kill the child process // first send a Ctrl-C to the app // (this doesn't seem to do anything) CString strInput = "\03"; // Ctrl-C if (!WriteFile(m_hChildStdinWr, (LPCTSTR)strInput, strInput.GetLength(), &dwWritten, NULL)) { CString strError = "Error stopping GIB"; TRACE(strError); pMAINFRAME->SetGIBMonitorText(strError); nErrCode = GetLastError(); return ExitGracefully(-4); } // close the writable handle to the child's stdin SafeCloseHandle(m_hChildStdinWr); // then call terminateProcess TerminateProcess(hGIBProcess, 0); CloseHandle(hGIBProcess); // then close the readable handle to the child's stdout SafeCloseHandle(m_hChildStdoutRd); // // done // return nCardPlayed; }
/***************************************************************************** * CKsIrpTarget::Close() ***************************************************************************** *//*! * @brief * Close the Irp Target. */ BOOL CKsIrpTarget::Close() { BOOL Success = SafeCloseHandle(m_Handle); return Success; }
BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { BOOL lbAllow = TRUE; switch(ul_reason_for_call) { case DLL_PROCESS_ATTACH: { gnDllState = ds_DllProcessAttach; #ifdef _DEBUG HANDLE hProcHeap = GetProcessHeap(); #endif HeapInitialize(); ghOurModule = (HMODULE)hModule; ghConWnd = GetConsoleWindow(); if (ghConWnd) GetConsoleTitle(gsInitConTitle, countof(gsInitConTitle)); gnSelfPID = GetCurrentProcessId(); ghWorkingModule = (u64)hModule; gfGetRealConsoleWindow = GetConsoleWindow; user = (UserImp*)calloc(1, sizeof(*user)); GetMainThreadId(); // Инициализировать gnHookMainThreadId gcchLastWriteConsoleMax = 4096; gpszLastWriteConsole = (wchar_t*)calloc(gcchLastWriteConsoleMax,sizeof(*gpszLastWriteConsole)); gInQueue.Initialize(512, NULL); #ifdef _DEBUG gAllowAssertThread = am_Pipe; #endif #ifdef _DEBUG #ifdef UseDebugExceptionFilter gfnPrevFilter = SetUnhandledExceptionFilter(HkExceptionFilter); #endif #endif #ifdef SHOW_STARTED_MSGBOX if (!IsDebuggerPresent()) { ::MessageBox(ghConEmuWnd, L"ConEmuHk*.dll loaded", L"ConEmu hooks", MB_SYSTEMMODAL); } #endif #ifdef _DEBUG DWORD dwConMode = -1; GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConMode); #endif //_ASSERTE(ghHeap == NULL); //ghHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 200000, 0); wchar_t szEvtName[64]; msprintf(szEvtName, countof(szEvtName), CECONEMUROOTPROCESS, gnSelfPID); HANDLE hRootProcessFlag = OpenEvent(SYNCHRONIZE|EVENT_MODIFY_STATE, FALSE, szEvtName); DWORD nWaitRoot = -1; if (hRootProcessFlag) { nWaitRoot = WaitForSingleObject(hRootProcessFlag, 0); gbSelfIsRootConsoleProcess = (nWaitRoot == WAIT_OBJECT_0); } SafeCloseHandle(hRootProcessFlag); #ifdef HOOK_USE_DLLTHREAD _ASSERTEX(FALSE && "Hooks starting in background thread?"); //HANDLE hEvents[2]; //hEvents[0] = CreateEvent(NULL, FALSE, FALSE, NULL); //hEvents[1] = ghStartThread = CreateThread(NULL, 0, DllStart, NULL/*(LPVOID)(hEvents[0])*/, 0, &gnStartThreadID); if (ghStartThread == NULL) { //_ASSERTE(ghStartThread!=NULL); wchar_t szMsg[128]; DWORD nErrCode = GetLastError(); msprintf(szMsg, countof(szMsg), L"Failed to start DllStart thread!\nErrCode=0x%08X\nPID=%u", nErrCode, GetCurrentProcessId()); GuiMessageBox(ghConEmuWnd, szMsg, L"ConEmu hooks", 0); } else { DWORD nThreadWait = WaitForSingleObject(ghStartThread, 5000); DllThreadClose(); } //DWORD nThreadWait = WaitForMultipleObjects(hEvents, countof(hEvents), FALSE, INFINITE); //CloseHandle(hEvents[0]); #else DllStart(NULL); #endif user->setAllowLoadLibrary(); } break; case DLL_THREAD_ATTACH: { gnDllThreadCount++; if (gbHooksWasSet) InitHooksRegThread(); } break; case DLL_THREAD_DETACH: { #ifdef SHOW_SHUTDOWN_STEPS gnDbgPresent = 0; ShutdownStep(L"DLL_THREAD_DETACH"); #endif if (gbHooksWasSet) DoneHooksRegThread(); // DLL_PROCESS_DETACH зовется как выяснилось не всегда if (gnHookMainThreadId && (GetCurrentThreadId() == gnHookMainThreadId) && !gbDllDeinitialized) { gbDllDeinitialized = true; //WARNING!!! OutputDebugString must NOT be used from ConEmuHk::DllMain(DLL_PROCESS_DETACH). See Issue 465 DllStop(); } gnDllThreadCount--; ShutdownStep(L"DLL_THREAD_DETACH done, left=%i", gnDllThreadCount); } break; case DLL_PROCESS_DETACH: { ShutdownStep(L"DLL_PROCESS_DETACH"); gnDllState = ds_DllProcessDetach; if (gbHooksWasSet) lbAllow = FALSE; // Иначе свалимся, т.к. FreeLibrary перехвачена // Уже могли дернуть в DLL_THREAD_DETACH if (!gbDllDeinitialized) { gbDllDeinitialized = true; //WARNING!!! OutputDebugString must NOT be used from ConEmuHk::DllMain(DLL_PROCESS_DETACH). See Issue 465 DllStop(); } // -- free не нужен, т.к. уже вызван HeapDeinitialize() //free(user); ShutdownStep(L"DLL_PROCESS_DETACH done"); } break; } return lbAllow; }
UINT ExecuteDownloader(LPWSTR pszCommand, LPWSTR szCmdDirectory) { UINT iRc; DWORD nWait; DWORD nThreadWait = WAIT_TIMEOUT; PipeThreadParm threadParm = {this}; ZeroStruct(m_SI); m_SI.cb = sizeof(m_SI); ZeroStruct(m_PI); mb_Terminating = false; DWORD nCreateFlags = 0 //| CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS; m_SI.dwFlags |= STARTF_USESHOWWINDOW; m_SI.wShowWindow = RELEASEDEBUGTEST(SW_HIDE,SW_SHOWNA); if (!szCmdStringFormat || !*szCmdStringFormat) { // We need to redirect only StdError output SECURITY_ATTRIBUTES saAttr = {sizeof(saAttr), NULL, TRUE}; if (!CreatePipe(&mh_PipeErrRead, &mh_PipeErrWrite, &saAttr, 0)) { iRc = GetLastError(); _ASSERTE(FALSE && "CreatePipe was failed"); if (!iRc) iRc = E_UNEXPECTED; goto wrap; } // Ensure the read handle to the pipe for STDOUT is not inherited. SetHandleInformation(mh_PipeErrRead, HANDLE_FLAG_INHERIT, 0); mh_PipeErrThread = apiCreateThread(StdErrReaderThread, (LPVOID)&threadParm, &mn_PipeErrThreadId, "Downloader::ReaderThread"); if (mh_PipeErrThread != NULL) { m_SI.dwFlags |= STARTF_USESTDHANDLES; // Let's try to change only Error pipe? m_SI.hStdError = mh_PipeErrWrite; } } // Now we can run the downloader if (!CreateProcess(NULL, pszCommand, NULL, NULL, TRUE/*!Inherit!*/, nCreateFlags, NULL, szCmdDirectory, &m_SI, &m_PI)) { iRc = GetLastError(); _ASSERTE(FALSE && "Create downloader process was failed"); if (!iRc) iRc = E_UNEXPECTED; goto wrap; } nWait = WaitForSingleObject(m_PI.hProcess, INFINITE); if (GetExitCodeProcess(m_PI.hProcess, &nWait) && (nWait == 0)) // CERR_DOWNLOAD_SUCCEEDED is not returned for compatibility purposes { iRc = 0; // OK } else { _ASSERTE(nWait == 0 && "Downloader has returned an error"); iRc = nWait; } wrap: // Finalize reading routine mb_Terminating = true; if (mh_PipeErrThread) { nThreadWait = WaitForSingleObject(mh_PipeErrThread, 0); if (nThreadWait == WAIT_TIMEOUT) { apiCancelSynchronousIo(mh_PipeErrThread); } } SafeCloseHandle(mh_PipeErrRead); SafeCloseHandle(mh_PipeErrWrite); if (mh_PipeErrThread) { if (nThreadWait == WAIT_TIMEOUT) { nThreadWait = WaitForSingleObject(mh_PipeErrThread, 5000); } if (nThreadWait == WAIT_TIMEOUT) { _ASSERTE(FALSE && "StdErr reading thread hangs, terminating"); apiTerminateThread(mh_PipeErrThread, 999); } SafeCloseHandle(mh_PipeErrThread); } // Exit return iRc; };
// 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); }
// Проверка окна переднего плана. Если оно принадлежит к хукаемым процесса - вставить хук. // ДИАЛОГИ НЕ ПРОВЕРЯЮТСЯ bool CDefaultTerminal::CheckForeground(HWND hFore, DWORD nForePID, bool bRunInThread /*= true*/) { if (!isDefaultTerminalAllowed()) return false; bool lbRc = false; bool lbLocked = false; DWORD nResult = 0; wchar_t szClass[MAX_PATH]; szClass[0] = 0; PROCESSENTRY32 prc; bool bMonitored = false; const wchar_t* pszMonitored = NULL; HANDLE hProcess = NULL; int nBits = 0; wchar_t szCmdLine[MAX_PATH*3]; wchar_t szName[64]; PROCESS_INFORMATION pi = {}; STARTUPINFO si = {sizeof(si)}; BOOL bStarted = FALSE; // Если главное окно еще не создано if (!mb_ReadyToHook) { // Сразу выходим goto wrap; } //_ASSERTE(gpConEmu->isMainThread()); if (!hFore || !nForePID) { _ASSERTE(hFore && nForePID); goto wrap; } if (hFore == mh_LastWnd || hFore == mh_LastIgnoredWnd) { // Это окно уже проверялось lbRc = (hFore == mh_LastWnd); goto wrap; } if (bRunInThread && (hFore == mh_LastCall)) { // Просто выйти. Это проверка на частые фоновые вызовы. goto wrap; } mh_LastCall = hFore; if (bRunInThread) { if (gpConEmu->isMainThread()) { // Clear finished threads ClearThreads(false); } HANDLE hPostThread = NULL; DWORD nThreadId = 0; ThreadArg* pArg = (ThreadArg*)malloc(sizeof(ThreadArg)); if (!pArg) { _ASSERTE(pArg); goto wrap; } pArg->pTerm = this; pArg->hFore = hFore; pArg->nForePID = nForePID; hPostThread = CreateThread(NULL, 0, PostCheckThread, pArg, 0, &nThreadId); _ASSERTE(hPostThread!=NULL); if (hPostThread) { m_Threads.push_back(hPostThread); } lbRc = (hPostThread != NULL); // вернуть OK? goto wrap; } EnterCriticalSection(&mcs); lbLocked = true; // Clear dead processes and windows ClearProcessed(false); // Check window class if (GetClassName(hFore, szClass, countof(szClass))) { if ((lstrcmp(szClass, VirtualConsoleClass) == 0) //|| (lstrcmp(szClass, L"#32770") == 0) // Ignore dialogs // -- Process dialogs too (Application may be dialog-based) || isConsoleClass(szClass)) { mh_LastIgnoredWnd = hFore; goto wrap; } } // Go and check if (!GetProcessInfo(nForePID, &prc)) { mh_LastIgnoredWnd = hFore; goto wrap; } CharLowerBuff(prc.szExeFile, lstrlen(prc.szExeFile)); if (lstrcmp(prc.szExeFile, L"csrss.exe") == 0) { // This is "System" process and may not be hooked mh_LastIgnoredWnd = hFore; goto wrap; } // Is it in monitored applications? pszMonitored = gpSet->GetDefaultTerminalAppsMSZ(); if (pszMonitored) { // All strings are lower case const wchar_t* psz = pszMonitored; while (*psz) { if (_tcscmp(psz, prc.szExeFile) == 0) { bMonitored = true; break; } psz += _tcslen(psz)+1; } } // And how it is? if (!bMonitored) { mh_LastIgnoredWnd = hFore; goto wrap; } // Need to process for (INT_PTR i = m_Processed.size(); i--;) { if (m_Processed[i].nPID == nForePID) { bMonitored = false; break; // already hooked } } // May be hooked already? if (!bMonitored) { mh_LastWnd = hFore; lbRc = true; goto wrap; } _ASSERTE(isDefaultTerminalAllowed()); hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|SYNCHRONIZE, FALSE, nForePID); if (!hProcess) { // Failed to hook mh_LastIgnoredWnd = hFore; goto wrap; } // Need to be hooked nBits = GetProcessBits(nForePID, hProcess); switch (nBits) { case 32: _wsprintf(szCmdLine, SKIPLEN(countof(szCmdLine)) L"\"%s\\%s\" /DEFTRM=%u", gpConEmu->ms_ConEmuBaseDir, L"ConEmuC.exe", nForePID); break; case 64: _wsprintf(szCmdLine, SKIPLEN(countof(szCmdLine)) L"\"%s\\%s\" /DEFTRM=%u", gpConEmu->ms_ConEmuBaseDir, L"ConEmuC64.exe", nForePID); break; } if (!*szCmdLine) { // Unsupported bitness? CloseHandle(hProcess); mh_LastIgnoredWnd = hFore; goto wrap; } // Prepare event _wsprintf(szName, SKIPLEN(countof(szName)) CEDEFAULTTERMHOOK, nForePID); SafeCloseHandle(mh_SignEvent); mh_SignEvent = CreateEvent(LocalSecurity(), FALSE, FALSE, szName); if (mh_SignEvent) SetEvent(mh_SignEvent); // May be excess, but if event already exists... // Run hooker si.dwFlags = STARTF_USESHOWWINDOW; bStarted = CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if (!bStarted) { DisplayLastError(L"Failed to start hooking application!\nDefault terminal feature will not be available!"); CloseHandle(hProcess); mh_LastIgnoredWnd = hFore; goto wrap; } CloseHandle(pi.hThread); // Waiting for result TODO("Show status in status line?"); WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &nResult); CloseHandle(pi.hProcess); // And what? if (nResult == (UINT)CERR_HOOKS_WAS_SET) { mh_LastWnd = hFore; ProcessInfo inf = {}; inf.hProcess = hProcess; hProcess = NULL; // его закрывать НЕ нужно, сохранен в массиве inf.nPID = nForePID; inf.nHookTick = GetTickCount(); m_Processed.push_back(inf); lbRc = true; goto wrap; } // Failed, remember this CloseHandle(hProcess); mh_LastIgnoredWnd = hFore; _ASSERTE(lbRc == false); wrap: if (lbLocked) { LeaveCriticalSection(&mcs); } return lbRc; }
// Shutdown Method void cIocpServer::Shutdown(DWORD maxWait) { mEndServer = true; mRunServer = false; // Backend Thread if ( mIocpBackendThread != NULL ) { WaitForSingleObjectEx( mIocpBackendThread, maxWait, TRUE ); CloseHandle( mIocpBackendThread ); mIocpBackendThread = NULL; } SOCKET sockTemp = mSocket; mSocket = INVALID_SOCKET; if ( sockTemp != INVALID_SOCKET ) { closesocket( sockTemp ); } // Accept Thread if ( mIocpAcceptThread != NULL ) { WaitForSingleObjectEx( mIocpAcceptThread, maxWait, TRUE ); CloseHandle( mIocpAcceptThread ); mIocpAcceptThread = NULL; } // Cause worker threads to exit if ( mIocp != NULL ) { for ( int i = 0; i < mIocpWorkerThreadNumber; i++ ) { PostQueuedCompletionStatus( mIocp, 0, 0, IOCP_SHUTDOWN ); } } // Make sure worker threads exits. for ( int i = 0; i < mIocpWorkerThreadNumber; i++ ) { if ( WaitForSingleObject( mIocpWorkerThread[i], 60000 ) != WAIT_OBJECT_0 ) { DWORD exitCode; GetExitCodeThread( mIocpWorkerThread[i], &exitCode); if ( exitCode == STILL_ACTIVE ) { TerminateThread( mIocpWorkerThread[i], 0 ); } } CloseHandle( mIocpWorkerThread[i] ); mIocpWorkerThread[i] = NULL; } // Overlapped I/O Model Pool Socket Context Pool. if ( mIoContextFrontBuffer ) { GlobalFree( mIoContextFrontBuffer ); mIoContextFrontBuffer = NULL; } if ( mIoContextBackBuffer ) { GlobalFree( mIoContextBackBuffer ); mIoContextBackBuffer = NULL; } SafeDelete( mIoContextPool ); SafeDelete( mSocketContextPool ); // completion port SafeCloseHandle( mIocp ); }
void AbstractBTGenerator::Run(HANDLE hThread, bool bFaultingThread) { assert(m_process.IsValid()); assert(hThread); if (!Init()) { assert(false); return; } if (bFaultingThread) { const QString threadInfo = QString("Faulting thread (%1)").arg( reinterpret_cast<quintptr>(hThread) ); emit DebugLine(threadInfo); } else { const QString threadInfo = QString("Thread %1").arg( reinterpret_cast<quintptr>(hThread) ); emit DebugLine(threadInfo); } //HANDLE hFile = CreateFile(L"C:\\test\\test.dmp", FILE_ALL_ACCESS, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); //if (!MiniDumpWriteDump(m_process.GetHandle(), m_process.GetId(), hFile, // MiniDumpNormal, NULL, NULL, NULL)) //{ // HRESULT hres = (HRESULT) GetLastError(); // printf("%08X\n\n", hres); //} //SafeCloseHandle(hFile); DWORD dw = SuspendThread(hThread); assert(dw != DWORD(-1)); if (dw == DWORD(-1)) { qCritical() << "SuspendThread() failed: " << GetLastError(); return; } CONTEXT context; ZeroMemory(&context, sizeof(context)); if (!bFaultingThread) { // if it's not the faulting thread, get its context context.ContextFlags = CONTEXT_FULL; if (!GetThreadContext(hThread, &context)) { ResumeThread(hThread); assert(false); qCritical() << "GetThreadContext() failed: " << GetLastError(); return; } } else { // if it is, get it from KCrash HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, sharedMemoryName); if (hMapFile == NULL) { qCritical() << "OpenFileMapping() failed: " << GetLastError(); return; } CONTEXT *othercontext = (CONTEXT*) MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(CONTEXT)); if (othercontext == NULL) { qCritical() << "MapViewOfFile() failed: " << GetLastError(); SafeCloseHandle(hMapFile); return; } CopyMemory(&context, othercontext, sizeof(CONTEXT)); UnmapViewOfFile(othercontext); // continue even if it fails SafeCloseHandle(hMapFile); } // some of this stuff is taken from StackWalker ZeroMemory(&m_currentFrame, sizeof(m_currentFrame)); DWORD machineType = IMAGE_FILE_MACHINE_UNKNOWN; #if defined(_M_IX86) machineType = IMAGE_FILE_MACHINE_I386; m_currentFrame.AddrPC.Offset = context.Eip; m_currentFrame.AddrFrame.Offset = context.Ebp; m_currentFrame.AddrStack.Offset = context.Esp; #elif defined(_M_X64) machineType = IMAGE_FILE_MACHINE_AMD64; m_currentFrame.AddrPC.Offset = context.Rip; m_currentFrame.AddrFrame.Offset = context.Rbp; m_currentFrame.AddrStack.Offset = context.Rsp; #else # error This architecture is not supported. #endif m_currentFrame.AddrPC.Mode = AddrModeFlat; m_currentFrame.AddrFrame.Mode = AddrModeFlat; m_currentFrame.AddrStack.Mode = AddrModeFlat; SymSetOptions(SymGetOptions() | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); SymInitialize(m_process.GetHandle(), NULL, FALSE); LoadSymbols(); for (int i = 0; /*nothing*/; i++) { SetLastError(0); if (!StackWalk64( machineType, m_process.GetHandle(), hThread, &m_currentFrame, &context, &Callbacks::ReadProcessMemory, &Callbacks::SymFunctionTableAccess64, &Callbacks::SymGetModuleBase64, NULL)) { emit Finished(); qDebug() << "Stackwalk finished; GetLastError=" << GetLastError(); break; } FrameChanged(); QString modulename = GetModuleName(); QString functionname = GetFunctionName(); QString file = GetFile(); int line = GetLine(); QString address = QString::number(m_currentFrame.AddrPC.Offset, 16); QString debugLine = QString::fromLatin1(BACKTRACE_FORMAT). arg(modulename).arg(functionname).arg(file).arg(line).arg(address); emit DebugLine(debugLine); } // Resume the target thread now, or else the crashing process will not // be terminated ResumeThread(hThread); SymCleanup(m_process.GetHandle()); emit DebugLine(QString()); }
unsigned __stdcall I4C3DAcceptedThreadProc(void* pParam) { LoggingMessage(Log_Debug, _T(MESSAGE_DEBUG_PROCESSING), GetLastError(), g_FILE, __LINE__); I4C3DChildContext* pChildContext = (I4C3DChildContext*)pParam; I4C3DUDPPacket packet = {0}; const SIZE_T packetBufferSize = sizeof(packet.szCommand); SIZE_T totalRecvBytes = 0; int nBytes = 0; BOOL bBreak = FALSE; DWORD dwResult = 0; WSAEVENT hEvent = NULL; WSAEVENT hEventArray[2] = {0}; WSANETWORKEVENTS events = {0}; hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (hEvent == NULL) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); shutdown(pChildContext->clientSocket, SD_SEND); recv(pChildContext->clientSocket, packet.szCommand, packetBufferSize, 0); shutdown(pChildContext->clientSocket, SD_BOTH); closesocket(pChildContext->clientSocket); RemoveChildThread( pChildContext->hChildThread ); free(pChildContext); return EXIT_FAILURE; } WSAEventSelect(pChildContext->clientSocket, hEvent, FD_READ | FD_CLOSE); hEventArray[0] = hEvent; hEventArray[1] = pChildContext->pContext->hStopEvent; FillMemory(packet.szCommand, packetBufferSize, 0xFF); while (!bBreak) { if (!CheckNetworkEventError(events)) { break; } dwResult = WSAWaitForMultipleEvents(2, hEventArray, FALSE, WSA_INFINITE, FALSE); DEBUG_PROFILE_MONITOR; if (dwResult == WSA_WAIT_FAILED) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); break; } if (dwResult - WSA_WAIT_EVENT_0 == 0) { if (WSAEnumNetworkEvents(pChildContext->clientSocket, hEvent, &events) != 0) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); break; } if (events.lNetworkEvents & FD_CLOSE) { break; } else if (events.lNetworkEvents & FD_READ) { nBytes = recv(pChildContext->clientSocket, packet.szCommand + totalRecvBytes, packetBufferSize - totalRecvBytes, 0); if (nBytes == SOCKET_ERROR) { if (WSAGetLastError() == WSAEWOULDBLOCK) { continue; } else { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_SOCKET_RECV), WSAGetLastError(), g_FILE, __LINE__); } break; } else if (nBytes > 0) { totalRecvBytes += nBytes; PCSTR pTermination = (PCSTR)memchr(packet.szCommand, pChildContext->cTermination, totalRecvBytes); // 終端文字が見つからない場合、バッファをクリア if (pTermination == NULL) { if (totalRecvBytes >= packetBufferSize) { FillMemory(packet.szCommand, packetBufferSize, 0xFF); totalRecvBytes = 0; } continue; } do { DEBUG_PROFILE_MONITOR; // プラグインへ電文転送 pChildContext->pContext->pController->Execute(&packet, pTermination-packet.szCommand+1); volatile int i; for (i = 0; i < g_sleepCount; ++i) { Sleep(1); } //} else { // // Hotkey // MoveMemory(szCommand, recvBuffer, pTermination-recvBuffer); // szCommand[pTermination-recvBuffer] = '\0'; // EnterCriticalSection(&g_Lock); // pChildContext->pContext->pController->Execute(pChildContext->pContext, &delta, szCommand); // LeaveCriticalSection(&g_Lock); //} if (pTermination == (packet.szCommand + totalRecvBytes - 1)) { FillMemory(packet.szCommand, packetBufferSize, 0xFF); totalRecvBytes = 0; } else if (pTermination < (packet.szCommand + totalRecvBytes - 1)) { int nCopySize = packetBufferSize - (pTermination - packet.szCommand + 1); totalRecvBytes -= (pTermination - packet.szCommand + 1); MoveMemory(packet.szCommand, pTermination+1, nCopySize); FillMemory(packet.szCommand + nCopySize, packetBufferSize - nCopySize, 0xFF); } else { bBreak = TRUE; LoggingMessage(Log_Error, _T(MESSAGE_ERROR_MESSAGE_INVALID), GetLastError(), g_FILE, __LINE__); break; } DEBUG_PROFILE_MONITOR; } while ((pTermination = (LPCSTR)memchr(packet.szCommand, pChildContext->cTermination, totalRecvBytes)) != NULL); DEBUG_PROFILE_MONITOR; } } } else if (dwResult - WSA_WAIT_EVENT_0 == 1) { // pChildContext->pContext->hStopEvent に終了イベントがセットされた break; } } SafeCloseHandle(hEvent); // closesocket shutdown(pChildContext->clientSocket, SD_SEND); recv(pChildContext->clientSocket, packet.szCommand, packetBufferSize, 0); shutdown(pChildContext->clientSocket, SD_BOTH); closesocket(pChildContext->clientSocket); RemoveChildThread( pChildContext->hChildThread ); free(pChildContext); LoggingMessage(Log_Debug, _T(MESSAGE_DEBUG_PROCESSING), GetLastError(), g_FILE, __LINE__); return EXIT_SUCCESS; }
HRESULT CKsIrpTarget::SyncIoctl( IN HANDLE handle, IN ULONG ulIoctl, IN PVOID pvInBuffer, IN ULONG cbInBuffer, OUT PVOID pvOutBuffer, OUT ULONG cbOutBuffer, OUT PULONG pulBytesReturned) { TRACE_ENTER(); HRESULT hr = S_OK; OVERLAPPED overlapped; BOOL fRes = TRUE; ULONG ulBytesReturned; if (!IsValidHandle(handle)) { hr = E_FAIL; DebugPrintf(TRACE_ERROR,TEXT("CKsIrpTarget::SyncIoctl Invalid Handle")); } if (!pulBytesReturned) { pulBytesReturned = &ulBytesReturned; } if (SUCCEEDED(hr)) { ZeroMemory(&overlapped,sizeof(overlapped)); overlapped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL); if (!overlapped.hEvent) { hr = E_OUTOFMEMORY; DebugPrintf(TRACE_ERROR,TEXT("CKsIrpTarget::SyncIoctl CreateEvent failed")); } else { // Flag the event by setting the low-order bit so we // don't get completion port notifications. // Really! - see the description of the lpOverlapped parameter in // the docs for GetQueuedCompletionStatus overlapped.hEvent = (HANDLE)((DWORD_PTR)overlapped.hEvent | 0x1); } } if (SUCCEEDED(hr)) { fRes = DeviceIoControl(handle, ulIoctl, pvInBuffer, cbInBuffer, pvOutBuffer, cbOutBuffer, pulBytesReturned, &overlapped); if (!fRes) { DWORD dwError; dwError = GetLastError(); if (ERROR_IO_PENDING == dwError) { DWORD dwWait; // Wait for completion dwWait = ::WaitForSingleObject(overlapped.hEvent,INFINITE); assert(WAIT_OBJECT_0 == dwWait); if (dwWait != WAIT_OBJECT_0) { hr = E_FAIL; DebugPrintf(TRACE_ERROR,TEXT("CKsIrpTarget::SyncIoctl WaitForSingleObject failed dwWait:0x%08x"),dwWait); } } else if (((ERROR_INSUFFICIENT_BUFFER == dwError) || (ERROR_MORE_DATA == dwError)) && (IOCTL_KS_PROPERTY == ulIoctl) && (cbOutBuffer == 0)) { hr = S_OK; fRes = TRUE; } else { hr = E_FAIL; } } if (!fRes) *pulBytesReturned = 0; SafeCloseHandle(overlapped.hEvent); } TRACE_LEAVE_HRESULT(hr); return hr; }
DWORD CSetDlgFonts::EnumFontsThread(LPVOID apArg) { HDC hdc = GetDC(NULL); int aFontCount[] = { 0, 0, 0 }; wchar_t szName[MAX_PATH]; // Сначала загрузить имена шрифтов, установленных в систему (или зарегистрированных нами) EnumFontFamilies(hdc, (LPCTSTR) NULL, (FONTENUMPROC) EnumFamCallBack, (LPARAM) aFontCount); // Теперь - загрузить размеры установленных терминальных шрифтов (aka Raster fonts) LOGFONT term = {0}; term.lfCharSet = OEM_CHARSET; wcscpy_c(term.lfFaceName, L"Terminal"); //CFontMgr::szRasterSizes[0].cx = CFontMgr::szRasterSizes[0].cy = 0; memset(CFontMgr::szRasterSizes, 0, sizeof(CFontMgr::szRasterSizes)); EnumFontFamiliesEx(hdc, &term, (FONTENUMPROCW) EnumFontCallBackEx, 0/*LPARAM*/, 0); UINT nMaxCount = countof(CFontMgr::szRasterSizes); for(UINT i = 0; i<(nMaxCount-1) && CFontMgr::szRasterSizes[i].cy; i++) { UINT k = i; for(UINT j = i+1; j<nMaxCount && CFontMgr::szRasterSizes[j].cy; j++) { if (CFontMgr::szRasterSizes[j].cy < CFontMgr::szRasterSizes[k].cy) k = j; else if (CFontMgr::szRasterSizes[j].cy == CFontMgr::szRasterSizes[k].cy && CFontMgr::szRasterSizes[j].cx < CFontMgr::szRasterSizes[k].cx) k = j; } if (k != i) { SIZE sz = CFontMgr::szRasterSizes[k]; CFontMgr::szRasterSizes[k] = CFontMgr::szRasterSizes[i]; CFontMgr::szRasterSizes[i] = sz; } } DeleteDC(hdc); HWND hFontsPg = gpSetCls->GetPage(thi_Fonts); if (hFontsPg) { for (size_t sz=0; sz<countof(CFontMgr::szRasterSizes) && CFontMgr::szRasterSizes[sz].cy; sz++) { swprintf_c(szName, L"[%s %ix%i]", CFontMgr::RASTER_FONTS_NAME, CFontMgr::szRasterSizes[sz].cx, CFontMgr::szRasterSizes[sz].cy); int nIdx = SendDlgItemMessage(hFontsPg, tFontFace, CB_INSERTSTRING, sz, (LPARAM)szName); SendDlgItemMessage(hFontsPg, tFontFace, CB_SETITEMDATA, nIdx, 1); } GetDlgItemText(hFontsPg, tFontFace, szName, countof(szName)); CSetDlgLists::SelectString(hFontsPg, tFontFace, szName); GetDlgItemText(hFontsPg, tFontFace2, szName, countof(szName)); CSetDlgLists::SelectString(hFontsPg, tFontFace2, szName); } SafeCloseHandle(mh_EnumThread); _ASSERTE(mh_EnumThread == NULL); mb_EnumThreadFinished = true; // Если шустрый юзер успел переключиться на вкладку "Views" до окончания // загрузки шрифтов - послать в диалог сообщение "Считать список из [thi_Fonts]" HWND hViewsPg = gpSetCls->GetPage(thi_Views); if (hViewsPg) PostMessage(hViewsPg, gpSetCls->mn_MsgLoadFontFromMain, 0, 0); HWND hTabsPg = gpSetCls->GetPage(thi_Tabs); if (hTabsPg) PostMessage(hTabsPg, gpSetCls->mn_MsgLoadFontFromMain, 0, 0); HWND hStatusPg = gpSetCls->GetPage(thi_Status); if (hStatusPg) PostMessage(hStatusPg, gpSetCls->mn_MsgLoadFontFromMain, 0, 0); return 0; }
void CloseHandles() { SafeCloseHandle(m_PI.hProcess); SafeCloseHandle(m_PI.hThread); };
static void DeleteWatchedDir(WatchedDir *wd) { free((void*)wd->dirPath); SafeCloseHandle(wd->hDir); free(wd); }
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; }
// Не интересуется результатом команды! 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; }
// CIR_OK=0 - OK, CIR_AlreadyInjected=1 - Already injected, иначе - ошибка // Здесь вызывается CreateRemoteThread CINFILTRATE_EXIT_CODES InjectRemote(DWORD nRemotePID, bool abDefTermOnly /*= false */) { CINFILTRATE_EXIT_CODES iRc = CIR_GeneralError/*-1*/; bool lbWin64 = WIN3264TEST((IsWindows64()!=0),true); bool is32bit; int nBits; DWORD nWrapperWait = (DWORD)-1, nWrapperResult = (DWORD)-1; HANDLE hProc = NULL; wchar_t szSelf[MAX_PATH+16], szHooks[MAX_PATH+16]; wchar_t *pszNamePtr, szArgs[32]; wchar_t szName[64]; HANDLE hEvent = NULL; HANDLE hDefTermReady = NULL; bool bAlreadyHooked = false; HANDLE hSnap = NULL; MODULEENTRY32 mi = {sizeof(mi)}; HMODULE ptrOuterKernel = NULL; if (!GetModuleFileName(NULL, szSelf, MAX_PATH)) { iRc = CIR_GetModuleFileName/*-200*/; goto wrap; } wcscpy_c(szHooks, szSelf); pszNamePtr = (wchar_t*)PointToName(szHooks); if (!pszNamePtr) { iRc = CIR_GetModuleFileName/*-200*/; goto wrap; } // Hey, may be ConEmuHk.dll is already loaded? hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, nRemotePID); if (!hSnap || (hSnap == INVALID_HANDLE_VALUE)) { iRc = CIR_SnapshotCantBeOpened/*-113*/; goto wrap; } else if (hSnap && Module32First(hSnap, &mi)) { // 130829 - Let load newer(!) ConEmuHk.dll into target process. // 141201 - Also we need to be sure in kernel32.dll address LPCWSTR pszConEmuHk = WIN3264TEST(L"conemuhk.", L"conemuhk64."); size_t nDllNameLen = lstrlen(pszConEmuHk); // Out preferred module name wchar_t szOurName[40] = {}; wchar_t szMinor[8] = L""; lstrcpyn(szMinor, _CRT_WIDE(MVV_4a), countof(szMinor)); _wsprintf(szOurName, SKIPLEN(countof(szOurName)) CEDEFTERMDLLFORMAT /*L"ConEmuHk%s.%02u%02u%02u%s.dll"*/, WIN3264TEST(L"",L"64"), MVV_1, MVV_2, MVV_3, szMinor); CharLowerBuff(szOurName, lstrlen(szOurName)); // Go to enumeration wchar_t szName[64]; do { LPCWSTR pszName = PointToName(mi.szModule); // Name of ConEmuHk*.*.dll module may be changed (copied to %APPDATA%) if (!pszName || !*pszName) continue; lstrcpyn(szName, pszName, countof(szName)); CharLowerBuff(szName, lstrlen(szName)); if (!ptrOuterKernel && (lstrcmp(szName, L"kernel32.dll") == 0)) { ptrOuterKernel = mi.hModule; } // ConEmuHk*.*.dll? if (!bAlreadyHooked && (wmemcmp(szName, pszConEmuHk, nDllNameLen) == 0) && (wmemcmp(szName+lstrlen(szName)-4, L".dll", 4) == 0)) { // Yes! ConEmuHk.dll already loaded into nRemotePID! // But what is the version? Let don't downgrade loaded version! if (lstrcmp(szName, szOurName) >= 0) { // OK, szName is newer or equal to our build bAlreadyHooked = true; } } // Stop enumeration? if (bAlreadyHooked && ptrOuterKernel) break; } while (Module32Next(hSnap, &mi)); // Check done } SafeCloseHandle(hSnap); // Already hooked? if (bAlreadyHooked) { iRc = CIR_AlreadyInjected/*1*/; goto wrap; } if (!ptrOuterKernel) { iRc = CIR_OuterKernelAddr/*-112*/; goto wrap; } // Check, if we can access that process hProc = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, nRemotePID); if (hProc == NULL) { iRc = CIR_OpenProcess/*-201*/; goto wrap; } // Go to hook // Preparing Events _wsprintf(szName, SKIPLEN(countof(szName)) CEDEFAULTTERMHOOK, nRemotePID); if (!abDefTermOnly) { // When running in normal mode (NOT set up as default terminal) // we need full initialization procedure, not a light one when hooking explorer.exe hEvent = OpenEvent(EVENT_MODIFY_STATE|SYNCHRONIZE, FALSE, szName); if (hEvent) { ResetEvent(hEvent); CloseHandle(hEvent); } } else { hEvent = CreateEvent(LocalSecurity(), FALSE, FALSE, szName); SetEvent(hEvent); _wsprintf(szName, SKIPLEN(countof(szName)) CEDEFAULTTERMHOOKOK, nRemotePID); hDefTermReady = CreateEvent(LocalSecurity(), FALSE, FALSE, szName); ResetEvent(hDefTermReady); } // Creating as remote thread. // Resetting this event notify ConEmuHk about // 1) need to determine MainThreadId // 2) need to start pipe server _wsprintf(szName, SKIPLEN(countof(szName)) CECONEMUROOTTHREAD, nRemotePID); hEvent = OpenEvent(EVENT_MODIFY_STATE|SYNCHRONIZE, FALSE, szName); if (hEvent) { ResetEvent(hEvent); CloseHandle(hEvent); } // Определить битность процесса, Если он 32битный, а текущий - ConEmuC64.exe // Перезапустить 32битную версию ConEmuC.exe nBits = GetProcessBits(nRemotePID, hProc); if (nBits == 0) { // Do not even expected, ConEmu GUI must run ConEmuC elevated if required. iRc = CIR_GetProcessBits/*-204*/; goto wrap; } is32bit = (nBits == 32); if (is32bit != WIN3264TEST(true,false)) { // По идее, такого быть не должно. ConEmu должен был запустить соответствующий conemuC*.exe _ASSERTE(is32bit == WIN3264TEST(true,false)); PROCESS_INFORMATION pi = {}; STARTUPINFO si = {sizeof(si)}; _wcscpy_c(pszNamePtr, 16, is32bit ? L"ConEmuC.exe" : L"ConEmuC64.exe"); _wsprintf(szArgs, SKIPLEN(countof(szArgs)) L" /INJECT=%u", nRemotePID); if (!CreateProcess(szHooks, szArgs, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi)) { iRc = CIR_CreateProcess/*-202*/; goto wrap; } nWrapperWait = WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &nWrapperResult); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if ((nWrapperResult != CERR_HOOKS_WAS_SET) && (nWrapperResult != CERR_HOOKS_WAS_ALREADY_SET)) { iRc = CIR_WrapperResult/*-203*/; SetLastError(nWrapperResult); goto wrap; } // Значит всю работу сделал враппер iRc = CIR_OK/*0*/; goto wrap; } // Поехали _wcscpy_c(pszNamePtr, 16, is32bit ? L"ConEmuHk.dll" : L"ConEmuHk64.dll"); if (!FileExists(szHooks)) { iRc = CIR_ConEmuHkNotFound/*-250*/; goto wrap; } if (abDefTermOnly) { CINFILTRATE_EXIT_CODES iFRc = PrepareHookModule(szHooks); if (iFRc != 0) { iRc = iFRc; goto wrap; } } iRc = InfiltrateDll(hProc, ptrOuterKernel, szHooks); // Если создавали временную копию - запланировать ее удаление if (abDefTermOnly && (lstrcmpi(szHooks, szSelf) != 0)) { MoveFileEx(szHooks, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); } wrap: if (hProc != NULL) CloseHandle(hProc); // But check the result of the operation //_ASSERTE(FALSE && "WaitForSingleObject(hDefTermReady)"); if ((iRc == 0) && hDefTermReady) { _ASSERTE(abDefTermOnly); DWORD nWaitReady = WaitForSingleObject(hDefTermReady, CEDEFAULTTERMHOOKWAIT/*==0*/); if (nWaitReady == WAIT_TIMEOUT) { iRc = CIR_DefTermWaitingFailed/*-300*/; // Failed to start hooking thread in remote process } } return iRc; }
//------------------------------------------------------------------------ ///| Parsing the command line |/////////////////////////////////////////// //------------------------------------------------------------------------ // Returns: // true - continue normal startup // false - exit process with iResult code bool CConEmuStart::ParseCommandLine(LPCWSTR pszCmdLine, int& iResult) { bool bRc = false; iResult = 100; _ASSERTE(pszCmdLine!=NULL); opt.cmdLine.Set(pszCmdLine ? pszCmdLine : L""); // pszCmdLine *may* or *may not* start with our executable or full path to our executable LPCWSTR pszTemp = opt.cmdLine; LPCWSTR cmdLineRest = SkipNonPrintable(opt.cmdLine); LPCWSTR pszName, pszArgStart; LPCWSTR psUnknown = NULL; CEStr szArg, szNext; CEStr szExeName, szExeNameOnly; // Set %ConEmuArgs% env var // It may be usefull if we need to restart ConEmu // from batch/script with the same arguments (selfupdate etc.) LPCWSTR pszCopyToEnvStart = NULL; // Have to get our exectuable name and name without extension szExeName.Set(PointToName(gpConEmu->ms_ConEmuExe)); szExeNameOnly.Set(szExeName); wchar_t* pszDot = (wchar_t*)PointToExt(szExeNameOnly.ms_Val); _ASSERTE(pszDot); if (pszDot) *pszDot = 0; // Check the first argument in the command line (most probably it will be our executable path/name) if (NextArg(&pszTemp, szArg) != 0) { _ASSERTE(FALSE && "GetCommandLine() is empty"); // Treat as empty command line, allow to start bRc = true; iResult = 0; goto wrap; } pszName = PointToName(szArg); if ((lstrcmpi(pszName, szExeName) == 0) || (lstrcmpi(pszName, szExeNameOnly) == 0)) { // OK, our executable was specified properly in the command line _ASSERTE(*pszTemp != L' '); cmdLineRest = SkipNonPrintable(pszTemp); } // Must be empty at the moment _ASSERTE(opt.runCommand.IsEmpty()); // Does the command line contain our switches? // Or we need to append all switches to starting shell? if (cmdLineRest && *cmdLineRest) { pszTemp = cmdLineRest; if (NextArg(&pszTemp, szArg) == 0) { if ((*szArg.ms_Val != L'/') && (*szArg.ms_Val != L'-') /*&& !wcschr(szArg.ms_Val, L'/')*/ ) { // Save it for further use opt.runCommand.Set(cmdLineRest); // And do not process it (no switches at all) cmdLineRest = NULL; opt.params = -1; } } } // Let parse the reset szArg.Empty(); szNext.Empty(); // Processing loop begin if (cmdLineRest && *cmdLineRest) { pszCopyToEnvStart = cmdLineRest; opt.cfgSwitches.Set(pszCopyToEnvStart); while (NextArg(&cmdLineRest, szArg, &pszArgStart) == 0) { bool lbNotFound = false; // ':' removed from checks because otherwise it will not warn // on invalid usage of "-new_console:a" for example if (szArg.ms_Val[0] == L'-' && szArg.ms_Val[1] && !wcspbrk(szArg.ms_Val+1, L"\\//|.&<>^")) { // Seems this is to be the "switch" too // Use both notations ('-' and '/') *szArg.ms_Val = L'/'; } LPCWSTR curCommand = szArg.ms_Val; #define NeedNextArg() \ if (NextArg(&cmdLineRest, szNext) != 0) { iResult = 101; goto wrap; } \ curCommand = szNext.ms_Val; if (*curCommand != L'/') { continue; // Try next switch? } else { opt.params++; if (!klstricmp(curCommand, _T("/autosetup"))) { BOOL lbTurnOn = TRUE; NeedNextArg(); if (*curCommand == _T('0')) { lbTurnOn = FALSE; } else { NeedNextArg(); DWORD dwAttr = GetFileAttributes(curCommand); if (dwAttr == (DWORD)-1 || (dwAttr & FILE_ATTRIBUTE_DIRECTORY)) { iResult = 102; goto wrap; } } HKEY hk = NULL; DWORD dw; int nSetupRc = 100; if (0 != RegCreateKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Command Processor"), 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hk, &dw)) { iResult = 103; goto wrap; } if (lbTurnOn) { size_t cchMax = _tcslen(curCommand); LPCWSTR pszArg1 = NULL; if (*cmdLineRest) { // May be ‘/GHWND=NEW’ or smth else pszArg1 = cmdLineRest; cchMax += _tcslen(pszArg1); } cchMax += 16; // + quotations, spaces and so on wchar_t* pszCmd = (wchar_t*)calloc(cchMax, sizeof(*pszCmd)); _wsprintf(pszCmd, SKIPLEN(cchMax) L"\"%s\"%s%s%s", curCommand, pszArg1 ? L" \"" : L"", pszArg1 ? pszArg1 : L"", pszArg1 ? L"\"" : L""); if (0 == RegSetValueEx(hk, _T("AutoRun"), 0, REG_SZ, (LPBYTE)pszCmd, (DWORD)sizeof(*pszCmd)*(_tcslen(pszCmd)+1))) nSetupRc = 1; free(pszCmd); } else { if (0==RegDeleteValue(hk, _T("AutoRun"))) nSetupRc = 1; } RegCloseKey(hk); // сбросить CreateInNewEnvironment для ConMan ResetConman(); iResult = nSetupRc; goto wrap; } else if (!klstricmp(curCommand, _T("/bypass")) || !klstricmp(curCommand, _T("/apparent")) || !klstricmp(curCommand, _T("/system")) || !klstricmp(curCommand, _T("/interactive")) || !klstricmp(curCommand, _T("/demote"))) { // -bypass // Этот ключик был придуман для прозрачного запуска консоли // в режиме администратора // (т.е. чтобы окно UAC нормально всплывало, но не мелькало консольное окно) // Но не получилось, пока требуются хэндлы процесса, а их не получается // передать в НЕ приподнятый процесс (исходный ConEmu GUI). // -apparent // Same as -bypass, but run the process as SW_SHOWNORMAL // -demote // Запуск процесса (ком.строка после "/demote") в режиме простого юзера, // когда текущий процесс уже запущен "под админом". "Понизить" текущие // привилегии просто так нельзя, поэтому запуск идет через TaskSheduler. // -system // Non-interactive process, started as System account // It's used when starting consoles, our server works fine as non-interactive // -interactive // Used when ConEmu.exe is started under System account, // but we need to give starting process interactive capabilities. _ASSERTE(opt.runCommand.IsEmpty()); pszTemp = cmdLineRest; if ((NextArg(&pszTemp, szNext) == 0) && (szNext.ms_Val[0] == L'-' || szNext.ms_Val[0] == L'/') && (lstrcmpi(szNext.ms_Val+1, L"cmd") == 0)) { opt.runCommand.Set(pszTemp); } else { opt.runCommand.Set(cmdLineRest); } if (opt.runCommand.IsEmpty()) { CEStr lsMsg(L"Invalid cmd line. '", curCommand, L"' exists, command line is empty"); DisplayLastError(lsMsg, -1); goto wrap; } // Information #ifdef _DEBUG STARTUPINFO siOur = {sizeof(siOur)}; GetStartupInfo(&siOur); #endif STARTUPINFO si = {sizeof(si)}; PROCESS_INFORMATION pi = {}; si.dwFlags = STARTF_USESHOWWINDOW; // Only `-demote` and `-apparent` switches were implemented to start application visible // All others are intended to run our server process, without blinking of course if ((0 == klstricmp(curCommand, _T("/demote"))) || (0 == klstricmp(curCommand, _T("/apparent")))) si.wShowWindow = SW_SHOWNORMAL; else si.wShowWindow = SW_HIDE; wchar_t szCurDir[MAX_PATH+1] = L""; GetCurrentDirectory(countof(szCurDir), szCurDir); BOOL b; DWORD nErr = 0; // if we were started from TaskScheduler, it would be nice to wait a little // to let parent (creator of the scheduler task) know we were started successfully bool bFromScheduler = false; // Log the command to be started { CEStr lsLog( L"Starting process", L": ", curCommand, L" `", opt.runCommand.ms_Val, L"`"); LogString(lsLog); } if (!klstricmp(curCommand, _T("/demote"))) { b = CreateProcessDemoted(opt.runCommand.ms_Val, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, szCurDir, &si, &pi, &nErr); } else if (!klstricmp(curCommand, _T("/system"))) { b = CreateProcessSystem(opt.runCommand.ms_Val, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, szCurDir, &si, &pi); } else if (!klstricmp(curCommand, _T("/interactive"))) { b = CreateProcessInteractive((DWORD)-1, NULL, opt.runCommand.ms_Val, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, szCurDir, &si, &pi, &nErr); bFromScheduler = true; } else // -bypass, -apparent { b = CreateProcess(NULL, opt.runCommand.ms_Val, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); nErr = b ? 0 : GetLastError(); bFromScheduler = true; } // Log the result { CEStr lsLog; wchar_t szExtra[32] = L""; if (b) { if (pi.dwProcessId) _wsprintf(szExtra, SKIPCOUNT(szExtra) L", PID=%u", pi.dwProcessId); lsLog = lstrmerge( L"Process was created successfully", szExtra); } else { _wsprintf(szExtra, SKIPCOUNT(szExtra) L", ErrorCode=%u", nErr); lsLog = lstrmerge( L"Failed to start process", szExtra); } LogString(lsLog); } // If the error was not shown yet if (nErr) DisplayLastError(opt.runCommand, nErr); // if we were started from TaskScheduler, it would be nice to wait a little // to let parent (creator of the scheduler task) know we were started successfully if (bFromScheduler) { LogString(L"Sleeping for 5 seconds"); Sleep(5*1000); } // Success? if (b) { iResult = 0; } // Done, close handles, if they were opened SafeCloseHandle(pi.hProcess); SafeCloseHandle(pi.hThread); goto wrap; } else if (!klstricmp(curCommand, _T("/multi"))) { gpConEmu->AppendExtraArgs(curCommand); gpConEmu->opt.MultiConValue = true; } else if (!klstricmp(curCommand, _T("/nomulti"))) { gpConEmu->AppendExtraArgs(curCommand); gpConEmu->opt.MultiConValue = false; } else if (!klstricmp(curCommand, _T("/visible"))) { gpConEmu->opt.VisValue = true; } else if (!klstricmp(curCommand, _T("/ct")) || !klstricmp(curCommand, _T("/cleartype")) || !klstricmp(curCommand, _T("/ct0")) || !klstricmp(curCommand, _T("/ct1")) || !klstricmp(curCommand, _T("/ct2"))) { switch (curCommand[3]) { case L'0': gpConEmu->opt.ClearTypeVal = NONANTIALIASED_QUALITY; break; case L'1': gpConEmu->opt.ClearTypeVal = ANTIALIASED_QUALITY; break; default: gpConEmu->opt.ClearTypeVal = CLEARTYPE_NATURAL_QUALITY; } } // Interface language else if (!klstricmp(curCommand, _T("/lng"))) { NeedNextArg(); if (!gpConEmu->opt.Language.Exists) { gpConEmu->opt.Language = curCommand; gpConEmu->AppendExtraArgs(L"/lng", curCommand); } } // Optional specific "ConEmu.l10n" else if (!klstricmp(curCommand, _T("/lngfile"))) { NeedNextArg(); if (!gpConEmu->opt.LanguageFile.Exists) { gpConEmu->opt.LanguageFile = curCommand; gpConEmu->AppendExtraArgs(L"/lngfile", curCommand); } } // имя шрифта else if (!klstricmp(curCommand, _T("/font"))) { NeedNextArg(); if (!gpConEmu->opt.FontVal.Exists) { gpConEmu->opt.FontVal = curCommand; gpConEmu->AppendExtraArgs(L"/font", curCommand); } } // Высота шрифта else if (!klstricmp(curCommand, _T("/size"))) { NeedNextArg(); if (!gpConEmu->opt.SizeVal.Exists) { gpConEmu->opt.SizeVal.SetInt(curCommand); } } // ADD fontname; by Mors else if (!klstricmp(curCommand, _T("/fontfile"))) { CESwitch szFile(sw_Str); if (!GetCfgParm(cmdLineRest, szFile, MAX_PATH)) { goto wrap; } gpConEmu->AppendExtraArgs(L"/fontfile", szFile.GetStr()); gpFontMgr->RegisterFont(szFile.GetStr(), TRUE); } // Register all fonts from specified directory else if (!klstricmp(curCommand, _T("/fontdir"))) { CESwitch szDir(sw_Str); if (!GetCfgParm(cmdLineRest, szDir, MAX_PATH)) { goto wrap; } gpConEmu->AppendExtraArgs(L"/fontdir", szDir.GetStr()); gpFontMgr->RegisterFontsDir(szDir.GetStr()); } else if (!klstricmp(curCommand, _T("/fs"))) { gpConEmu->opt.WindowModeVal = wmFullScreen; } else if (!klstricmp(curCommand, _T("/max"))) { gpConEmu->opt.WindowModeVal = wmMaximized; } else if (!klstricmp(curCommand, _T("/min")) || !klstricmp(curCommand, _T("/mintsa")) || !klstricmp(curCommand, _T("/starttsa"))) { gpConEmu->WindowStartMinimized = true; if (klstricmp(curCommand, _T("/min")) != 0) { gpConEmu->WindowStartTsa = true; gpConEmu->WindowStartNoClose = (klstricmp(curCommand, _T("/mintsa")) == 0); } } else if (!klstricmp(curCommand, _T("/tsa")) || !klstricmp(curCommand, _T("/tray"))) { gpConEmu->ForceMinimizeToTray = true; } else if (!klstricmp(curCommand, _T("/detached"))) { gpConEmu->m_StartDetached = crb_On; } else if (!klstricmp(curCommand, _T("/here"))) { gpConEmu->mb_ConEmuHere = true; gpConEmu->StoreWorkDir(); } else if (!klstricmp(curCommand, _T("/update"))) { gpConEmu->opt.AutoUpdateOnStart = true; } else if (!klstricmp(curCommand, _T("/noupdate"))) { // This one has more weight than AutoUpdateOnStart gpConEmu->opt.DisableAutoUpdate = true; } else if (!klstricmp(curCommand, _T("/nokeyhook")) || !klstricmp(curCommand, _T("/nokeyhooks")) || !klstricmp(curCommand, _T("/nokeybhook")) || !klstricmp(curCommand, _T("/nokeybhooks"))) { gpConEmu->DisableKeybHooks = true; } else if (!klstricmp(curCommand, _T("/nocloseconfirm"))) { gpConEmu->DisableCloseConfirm = true; } else if (!klstricmp(curCommand, _T("/nomacro"))) { gpConEmu->DisableAllMacro = true; } else if (!klstricmp(curCommand, _T("/nohotkey")) || !klstricmp(curCommand, _T("/nohotkeys"))) { gpConEmu->DisableAllHotkeys = true; } else if (!klstricmp(curCommand, _T("/nodeftrm")) || !klstricmp(curCommand, _T("/nodefterm"))) { gpConEmu->DisableSetDefTerm = true; } else if (!klstricmp(curCommand, _T("/noregfont")) || !klstricmp(curCommand, _T("/noregfonts"))) { gpConEmu->DisableRegisterFonts = true; } else if (!klstricmp(curCommand, _T("/inside")) || !lstrcmpni(curCommand, _T("/inside="), 8)) { bool bRunAsAdmin = isPressed(VK_SHIFT); bool bSyncDir = false; LPCWSTR pszSyncFmt = NULL; gpConEmu->mb_ConEmuHere = true; gpConEmu->StoreWorkDir(); if (curCommand[7] == _T('=')) { bSyncDir = true; pszSyncFmt = curCommand+8; // \eCD /d %1 - \e - ESC, \b - BS, \n - ENTER, %1 - "dir", %2 - "bash dir" } CConEmuInside::InitInside(bRunAsAdmin, bSyncDir, pszSyncFmt, 0, NULL); } else if (!klstricmp(curCommand, _T("/insidepid"))) { NeedNextArg(); bool bRunAsAdmin = isPressed(VK_SHIFT); wchar_t* pszEnd; // Здесь указывается PID, в который нужно внедриться. DWORD nInsideParentPID = wcstol(curCommand, &pszEnd, 10); if (nInsideParentPID) { CConEmuInside::InitInside(bRunAsAdmin, false, NULL, nInsideParentPID, NULL); } } else if (!klstricmp(curCommand, _T("/insidewnd"))) { NeedNextArg(); if (curCommand[0] == L'0' && (curCommand[1] == L'x' || curCommand[1] == L'X')) curCommand += 2; else if (curCommand[0] == L'x' || curCommand[0] == L'X') curCommand ++; bool bRunAsAdmin = isPressed(VK_SHIFT); wchar_t* pszEnd; // Здесь указывается HWND, в котором нужно создаваться. HWND hParent = (HWND)(DWORD_PTR)wcstoul(curCommand, &pszEnd, 16); if (hParent && IsWindow(hParent)) { CConEmuInside::InitInside(bRunAsAdmin, false, NULL, 0, hParent); } } else if (!klstricmp(curCommand, _T("/icon"))) { NeedNextArg(); if (!gpConEmu->opt.IconPrm.Exists && *curCommand) { gpConEmu->opt.IconPrm = true; gpConEmu->mps_IconPath = ExpandEnvStr(curCommand); } } else if (!klstricmp(curCommand, _T("/dir"))) { NeedNextArg(); if (*curCommand) { // Например, "%USERPROFILE%" wchar_t* pszExpand = NULL; if (wcschr(curCommand, L'%') && ((pszExpand = ExpandEnvStr(curCommand)) != NULL)) { gpConEmu->StoreWorkDir(pszExpand); SafeFree(pszExpand); } else { gpConEmu->StoreWorkDir(curCommand); } } } else if (!klstricmp(curCommand, _T("/updatejumplist"))) { // Copy current Task list to Win7 Jump list (Taskbar icon) gpConEmu->mb_UpdateJumpListOnStartup = true; } else if (!klstricmp(curCommand, L"/log") || !klstricmp(curCommand, L"/log0") || !klstricmp(curCommand, L"/log1") || !klstricmp(curCommand, L"/log2") || !klstricmp(curCommand, L"/log3") || !klstricmp(curCommand, L"/log4")) { if (!klstricmp(curCommand, L"/log") || !klstricmp(curCommand, L"/log0")) gpConEmu->opt.AdvLogging.SetInt(1); else gpConEmu->opt.AdvLogging.SetInt((BYTE)(curCommand[4] - L'0')); // 1..4 // Do create logging service DEBUGSTRSTARTUP(L"Creating log file"); gpConEmu->CreateLog(); } else if (!klstricmp(curCommand, _T("/single")) || !klstricmp(curCommand, _T("/reuse"))) { // "/reuse" switch to be remastered gpConEmu->AppendExtraArgs(curCommand); gpSetCls->SingleInstanceArg = sgl_Enabled; } else if (!klstricmp(curCommand, _T("/nosingle"))) { gpConEmu->AppendExtraArgs(curCommand); gpSetCls->SingleInstanceArg = sgl_Disabled; } else if (!klstricmp(curCommand, _T("/DesktopMode"))) { gpConEmu->opt.DesktopMode = true; } else if (!klstricmp(curCommand, _T("/quake")) || !klstricmp(curCommand, _T("/quakeauto")) || !klstricmp(curCommand, _T("/noquake"))) { if (!klstricmp(curCommand, _T("/quake"))) gpConEmu->opt.QuakeMode = 1; else if (!klstricmp(curCommand, _T("/quakeauto"))) gpConEmu->opt.QuakeMode = 2; else { gpConEmu->opt.QuakeMode = 0; if (gpSetCls->SingleInstanceArg == sgl_Default) gpSetCls->SingleInstanceArg = sgl_Disabled; } } else if (!klstricmp(curCommand, _T("/showhide")) || !klstricmp(curCommand, _T("/showhideTSA"))) { gpSetCls->SingleInstanceArg = sgl_Enabled; gpSetCls->SingleInstanceShowHide = !klstricmp(curCommand, _T("/showhide")) ? sih_ShowMinimize : sih_ShowHideTSA; } else if (!klstricmp(curCommand, _T("/reset")) || !klstricmp(curCommand, _T("/resetdefault")) || !klstricmp(curCommand, _T("/basic"))) { gpConEmu->opt.ResetSettings = true; if (!klstricmp(curCommand, _T("/resetdefault"))) { gpSetCls->isFastSetupDisabled = true; } else if (!klstricmp(curCommand, _T("/basic"))) { gpSetCls->isFastSetupDisabled = true; gpSetCls->isResetBasicSettings = true; } } else if (!klstricmp(curCommand, _T("/nocascade")) || !klstricmp(curCommand, _T("/dontcascade"))) { gpConEmu->AppendExtraArgs(curCommand); gpSetCls->isDontCascade = true; } else if (!klstricmp(curCommand, _T("/WndX")) || !klstricmp(curCommand, _T("/WndY")) || !klstricmp(curCommand, _T("/WndW")) || !klstricmp(curCommand, _T("/WndWidth")) || !klstricmp(curCommand, _T("/WndH")) || !klstricmp(curCommand, _T("/WndHeight"))) { TCHAR ch = curCommand[4]; CharUpperBuff(&ch, 1); CESwitch psz(sw_Str); bool bParm = false; if (!GetCfgParm(cmdLineRest, bParm, psz, 32)) { goto wrap; } gpConEmu->opt.SizePosPrm = true; // Direct X/Y implies /nocascade if (ch == _T('X') || ch == _T('Y')) { // TODO: isDontCascade must be in our opt struct !!! gpSetCls->isDontCascade = true; } switch (ch) { case _T('X'): gpConEmu->opt.sWndX.SetStr(psz.Str, sw_Str); break; case _T('Y'): gpConEmu->opt.sWndY.SetStr(psz.Str, sw_Str); break; case _T('W'): gpConEmu->opt.sWndW.SetStr(psz.Str, sw_Str); break; case _T('H'): gpConEmu->opt.sWndH.SetStr(psz.Str, sw_Str); break; } } else if (!klstricmp(curCommand, _T("/Monitor"))) { CESwitch psz(sw_Str); bool bParm = false; if (!GetCfgParm(cmdLineRest, bParm, psz, 64)) { goto wrap; } if ((gpConEmu->opt.Monitor.Mon = MonitorFromParam(psz.Str)) != NULL) { gpConEmu->opt.Monitor.Exists = true; gpConEmu->opt.Monitor.Type = sw_Int; gpStartEnv->hStartMon = gpConEmu->opt.Monitor.Mon; } } else if (!klstricmp(curCommand, _T("/Buffer")) || !klstricmp(curCommand, _T("/BufferHeight"))) { NeedNextArg(); if (!gpConEmu->opt.BufferHeightVal.Exists) { gpConEmu->opt.BufferHeightVal.SetInt(curCommand); if (gpConEmu->opt.BufferHeightVal.GetInt() < 0) { //setParent = true; -- Maximus5 - нефиг, все ручками gpConEmu->opt.BufferHeightVal = -gpConEmu->opt.BufferHeightVal.GetInt(); } if (gpConEmu->opt.BufferHeightVal.GetInt() < LONGOUTPUTHEIGHT_MIN) gpConEmu->opt.BufferHeightVal = LONGOUTPUTHEIGHT_MIN; else if (gpConEmu->opt.BufferHeightVal.GetInt() > LONGOUTPUTHEIGHT_MAX) gpConEmu->opt.BufferHeightVal = LONGOUTPUTHEIGHT_MAX; } } else if (!klstricmp(curCommand, _T("/Config"))) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.ConfigVal, 127)) { goto wrap; } } else if (!klstricmp(curCommand, _T("/Palette"))) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.PaletteVal, MAX_PATH)) { goto wrap; } } else if (!klstricmp(curCommand, _T("/LoadRegistry"))) { gpConEmu->AppendExtraArgs(curCommand); gpConEmu->opt.ForceUseRegistryPrm = true; } else if (!klstricmp(curCommand, _T("/LoadCfgFile")) || !klstricmp(curCommand, _T("/LoadXmlFile"))) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.LoadCfgFile, MAX_PATH, true)) { goto wrap; } } else if (!klstricmp(curCommand, _T("/SaveCfgFile")) || !klstricmp(curCommand, _T("/SaveXmlFile"))) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.SaveCfgFile, MAX_PATH, true)) { goto wrap; } } else if (!klstricmp(curCommand, _T("/GuiMacro"))) { // -- выполняется только последний if (!GetCfgParm(cmdLineRest, gpConEmu->opt.ExecGuiMacro, 0x8000, false)) { goto wrap; } } else if (!klstricmp(curCommand, _T("/UpdateSrcSet"))) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.UpdateSrcSet, MAX_PATH*4, false)) { goto wrap; } } else if (!klstricmp(curCommand, _T("/AnsiLog"))) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.AnsiLogPath, MAX_PATH-40, true)) { goto wrap; } } else if (!klstricmp(curCommand, _T("/SetDefTerm"))) { gpConEmu->opt.SetUpDefaultTerminal = true; } else if (!klstricmp(curCommand, _T("/ZoneId"))) { gpConEmu->opt.FixZoneId = true; } else if (!klstricmp(curCommand, _T("/Exit"))) { gpConEmu->opt.ExitAfterActionPrm = true; } else if (!klstricmp(curCommand, _T("/QuitOnClose"))) { gpConEmu->mb_ForceQuitOnClose = true; } else if (!klstricmp(curCommand, _T("/Title"))) { bool bOk = false; CESwitch pszTitle(sw_Str); if (!GetCfgParm(cmdLineRest, bOk, pszTitle, 127)) { goto wrap; } gpConEmu->SetTitleTemplate(pszTitle.GetStr()); } else if (!klstricmp(curCommand, _T("/FindBugMode"))) { gpConEmu->mb_FindBugMode = true; } else if (!klstricmp(curCommand, _T("/debug")) || !klstricmp(curCommand, _T("/debugw")) || !klstricmp(curCommand, _T("/debugi"))) { // These switches were already processed } else if (!klstricmp(curCommand, _T("/?")) || !klstricmp(curCommand, _T("/h")) || !klstricmp(curCommand, _T("/help"))) { if (gpLng) gpLng->Reload(); ConEmuAbout::OnInfo_About(); iResult = -1; goto wrap; } // Final `-cmd ...` or `-cmdlist ...` else if ( !klstricmp(curCommand, _T("/cmd")) || !klstricmp(curCommand, _T("/cmdlist")) ) { if (opt.cfgSwitches.ms_Val) { _ASSERTE(pszArgStart>pszCopyToEnvStart); _ASSERTE((INT_PTR)(pszArgStart - pszCopyToEnvStart) <= opt.cfgSwitches.GetLen()); opt.cfgSwitches.ms_Val[pszArgStart - pszCopyToEnvStart] = 0; } opt.runCommand.Set(SkipNonPrintable(cmdLineRest)); opt.isScript = (klstricmp(curCommand, L"/cmdlist") == 0); break; } else { // Show error on unknown switch psUnknown = pszArgStart; break; } } // (*curCommand == L'/') // Avoid assertions in NextArg szArg.Empty(); szNext.Empty(); } // while (NextArg(&cmdLineRest, szArg, &pszArgStart) == 0) } // Processing loop end if (psUnknown) { DEBUGSTRSTARTUP(L"Unknown switch, exiting!"); if (gpSet->isLogging()) { // For direct logging we do not use lng resources CEStr lsLog(L"\r\n", L"Unknown switch specified: ", psUnknown, L"\r\n\r\n"); gpConEmu->LogString(lsLog, false, false); } CEStr szNewConWarn; LPCWSTR pszTestSwitch = (psUnknown[0] == L'-' || psUnknown[0] == L'/') ? ((psUnknown[1] == L'-' || psUnknown[1] == L'/') ? (psUnknown+2) : (psUnknown+1)) : psUnknown; if ((lstrcmpni(pszTestSwitch, L"new_console", 11) == 0) || (lstrcmpni(pszTestSwitch, L"cur_console", 11) == 0)) { szNewConWarn = lstrmerge(L"\r\n\r\n", CLngRc::getRsrc(lng_UnknownSwitch4/*"Switch -new_console must be specified *after* /cmd or /cmdlist"*/) ); } CEStr lsMsg( CLngRc::getRsrc(lng_UnknownSwitch1/*"Unknown switch specified:"*/), L"\r\n\r\n", psUnknown, szNewConWarn, L"\r\n\r\n", CLngRc::getRsrc(lng_UnknownSwitch2/*"Visit website to get thorough switches description:"*/), L"\r\n" CEGUIARGSPAGE L"\r\n\r\n", CLngRc::getRsrc(lng_UnknownSwitch3/*"Or run ‘ConEmu.exe -?’ to get the brief."*/) ); MBoxA(lsMsg); goto wrap; } // Set "ConEmuArgs" and "ConEmuArgs2" ProcessConEmuArgsVar(); // Continue normal startup bRc = true; wrap: return bRc; }
/***************************************************************************** * CKsIrpTarget::SynchronizedIoctl() ***************************************************************************** *//*! * @brief * Synchronized I/O control. * @param * Handle The file handle to send the I/O control to. * @param * CtlCode The I/O control code to send. * @param * InputBuffer Pointer to the input buffer. * @param * InputBufferSize Size in bytes of the input buffer. * @param * OutputBuffer Pointer to the output buffer. * @param * OutputBufferSize Size in bytes of the output buffer. * @param * OutBytesReturned The number of bytes written to the output buffer. * @return * Returns S_OK on success, otherwise appropriate error code. */ HRESULT CKsIrpTarget:: SynchronizedIoctl ( IN HANDLE Handle, IN ULONG CtlCode, IN PVOID InputBuffer, IN ULONG InputBufferSize, OUT PVOID OutputBuffer, OUT ULONG OutputBufferSize, OUT ULONG * OutBytesReturned ) { HRESULT hr = S_OK; ULONG BytesReturned; if (!OutBytesReturned) { OutBytesReturned = &BytesReturned; } if (!IsValidHandle(Handle)) { hr = E_FAIL; _DbgPrintF(DEBUGLVL_ERROR,("[CKsIrpTarget::SynchronizedIoctl] - Invalid Handle")); } OVERLAPPED Overlapped; if (SUCCEEDED(hr)) { ZeroMemory(&Overlapped, sizeof(OVERLAPPED)); Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (Overlapped.hEvent) { // Flag the event by setting the low-order bit so we // don't get completion port notifications. // Really! - see the description of the lpOverlapped parameter in // the docs for GetQueuedCompletionStatus Overlapped.hEvent = (HANDLE)((DWORD_PTR)Overlapped.hEvent | 0x1); } else { hr = E_OUTOFMEMORY; _DbgPrintF(DEBUGLVL_ERROR,("[CKsIrpTarget::SynchronizedIoctl] - CreateEvent failed")); } } if (SUCCEEDED(hr)) { BOOL Result = DeviceIoControl(Handle, CtlCode, InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize, OutBytesReturned, &Overlapped); if (!Result) { DWORD w32Error = GetLastError(); if (ERROR_IO_PENDING == w32Error) { // Wait for completion DWORD Wait = ::WaitForSingleObject(Overlapped.hEvent, INFINITE); ASSERT(WAIT_OBJECT_0 == Wait); if (Wait != WAIT_OBJECT_0) { hr = E_FAIL; _DbgPrintF(DEBUGLVL_ERROR,("[CKsIrpTarget::SynchronizedIoctl] - WaitForSingleObject failed Wait: 0x%08x", Wait)); } } else if (((ERROR_INSUFFICIENT_BUFFER == w32Error) || (ERROR_MORE_DATA == w32Error)) && (IOCTL_KS_PROPERTY == CtlCode) && (OutputBufferSize == 0)) { hr = S_OK; Result = TRUE; } else { hr = E_FAIL; } } if (!Result) { *OutBytesReturned = 0; } SafeCloseHandle(Overlapped.hEvent); } return hr; }
static void FreeWatchedDir(WatchedDir *wd) { free(wd->dirPath); SafeCloseHandle(wd->hDir); free(wd); }
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int retCode = 1; // by default it's error #ifdef DEBUG // Memory leak detection (only enable _CRTDBG_LEAK_CHECK_DF for // regular termination so that leaks aren't checked on exceptions, // aborts, etc. where some clean-up might not take place) _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF); //_CrtSetBreakAlloc(421); TryLoadMemTrace(); #endif DisableDataExecution(); // ensure that C functions behave consistently under all OS locales // (use Win32 functions where localized input or output is desired) setlocale(LC_ALL, "C"); // don't show system-provided dialog boxes when accessing files on drives // that are not mounted (e.g. a: drive without floppy or cd rom drive // without a cd). SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); #if defined(DEBUG) || defined(SVN_PRE_RELEASE_VER) if (str::StartsWith(lpCmdLine, "/tester")) { extern int TesterMain(); // in Tester.cpp return TesterMain(); } if (str::StartsWith(lpCmdLine, "/regress")) { extern int RegressMain(); // in Regress.cpp return RegressMain(); } #endif #ifdef SUPPORTS_AUTO_UPDATE if (str::StartsWith(lpCmdLine, "-autoupdate")) { bool quit = AutoUpdateMain(); if (quit) return 0; } #endif srand((unsigned int)time(NULL)); // load uiautomationcore.dll before installing crash handler (i.e. initializing // dbghelp.dll), so that we get function names/offsets in GetCallstack() uia::Initialize(); #ifdef DEBUG dbghelp::RememberCallstackLogs(); #endif SetupCrashHandler(); ScopedOle ole; InitAllCommonControls(); ScopedGdiPlus gdiPlus(true); mui::Initialize(); uitask::Initialize(); prefs::Load(); CommandLineInfo i(GetCommandLine()); SetCurrentLang(i.lang ? i.lang : gGlobalPrefs->uiLanguage); // This allows ad-hoc comparison of gdi, gdi+ and gdi+ quick when used // in layout #if 0 RedirectIOToConsole(); BenchEbookLayout(L"C:\\kjk\\downloads\\pg12.mobi"); system("pause"); goto Exit; #endif if (i.showConsole) { RedirectIOToConsole(); RedirectDllIOToConsole(); } if (i.makeDefault) AssociateExeWithPdfExtension(); if (i.pathsToBenchmark.Count() > 0) { BenchFileOrDir(i.pathsToBenchmark); if (i.showConsole) system("pause"); } if (i.exitImmediately) goto Exit; gCrashOnOpen = i.crashOnOpen; gPolicyRestrictions = GetPolicies(i.restrictedUse); GetFixedPageUiColors(gRenderCache.textColor, gRenderCache.backgroundColor); DebugGdiPlusDevice(gUseGdiRenderer); if (!RegisterWinClass()) goto Exit; CrashIf(hInstance != GetModuleHandle(NULL)); if (!InstanceInit(nCmdShow)) goto Exit; if (i.hwndPluginParent) { if (!SetupPluginMode(i)) goto Exit; } if (i.printerName) { // note: this prints all PDF files. Another option would be to // print only the first one for (size_t n = 0; n < i.fileNames.Count(); n++) { bool ok = PrintFile(i.fileNames.At(n), i.printerName, !i.silent, i.printSettings); if (!ok) retCode++; } --retCode; // was 1 if no print failures, turn 1 into 0 goto Exit; } bool showStartPage = i.fileNames.Count() == 0 && gGlobalPrefs->rememberOpenedFiles && gGlobalPrefs->showStartPage; if (showStartPage) { // make the shell prepare the image list, so that it's ready when the first window's loaded SHFILEINFO sfi; SHGetFileInfo(L".pdf", 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES); } if (gGlobalPrefs->reopenOnce) { WStrVec moreFileNames; ParseCmdLine(gGlobalPrefs->reopenOnce, moreFileNames); moreFileNames.Reverse(); for (WCHAR **fileName = moreFileNames.IterStart(); fileName; fileName = moreFileNames.IterNext()) { i.fileNames.Append(*fileName); } moreFileNames.RemoveAt(0, moreFileNames.Count()); str::ReplacePtr(&gGlobalPrefs->reopenOnce, NULL); } HANDLE hMutex = NULL; HWND hPrevWnd = NULL; if (i.printDialog || i.stressTestPath || gPluginMode) { // TODO: pass print request through to previous instance? } else if (i.reuseDdeInstance) { hPrevWnd = FindWindow(FRAME_CLASS_NAME, NULL); } else if (gGlobalPrefs->reuseInstance || gGlobalPrefs->useTabs) { hPrevWnd = FindPrevInstWindow(&hMutex); } if (hPrevWnd) { for (size_t n = 0; n < i.fileNames.Count(); n++) { OpenUsingDde(hPrevWnd, i.fileNames.At(n), i, 0 == n); } goto Exit; } WindowInfo *win = NULL; for (size_t n = 0; n < i.fileNames.Count(); n++) { win = LoadOnStartup(i.fileNames.At(n), i, !win); if (!win) { retCode++; continue; } if (i.printDialog) OnMenuPrint(win, i.exitWhenDone); } if (i.fileNames.Count() > 0 && !win) { // failed to create any window, even though there // were files to load (or show a failure message for) goto Exit; } if (i.printDialog && i.exitWhenDone) goto Exit; if (!win) { win = CreateAndShowWindowInfo(); if (!win) goto Exit; } UpdateUITextForLanguage(); // needed for RTL languages if (win->IsAboutWindow()) { // TODO: shouldn't CreateAndShowWindowInfo take care of this? UpdateToolbarAndScrollbarState(*win); } // Make sure that we're still registered as default, // if the user has explicitly told us to be if (gGlobalPrefs->associatedExtensions) RegisterForPdfExtentions(win->hwndFrame); if (i.stressTestPath) { // don't save file history and preference changes gPolicyRestrictions = (gPolicyRestrictions | Perm_RestrictedUse) & ~Perm_SavePreferences; RebuildMenuBarForWindow(win); StartStressTest(&i, win, &gRenderCache); } if (gGlobalPrefs->checkForUpdates) UpdateCheckAsync(win, true); // only hide newly missing files when showing the start page on startup if (showStartPage && gFileHistory.Get(0)) { gFileExistenceChecker = new FileExistenceChecker(); gFileExistenceChecker->Start(); } // call this once it's clear whether Perm_SavePreferences has been granted prefs::RegisterForFileChanges(); retCode = RunMessageLoop(); SafeCloseHandle(&hMutex); CleanUpThumbnailCache(gFileHistory); Exit: prefs::UnregisterForFileChanges(); while (gWindows.Count() > 0) { DeleteWindowInfo(gWindows.At(0)); } #ifndef DEBUG // leave all the remaining clean-up to the OS // (as recommended for a quick exit) ExitProcess(retCode); #else DeleteObject(GetDefaultGuiFont()); DeleteBitmap(gBitmapReloadingCue); DeleteSplitterBrush(); // wait for FileExistenceChecker to terminate // (which should be necessary only very rarely) while (gFileExistenceChecker) { Sleep(10); uitask::DrainQueue(); } mui::Destroy(); uitask::Destroy(); trans::Destroy(); SaveCallstackLogs(); dbghelp::FreeCallstackLogs(); // must be after uitask::Destroy() because we might have queued prefs::Reload() // which crashes if gGlobalPrefs is freed gFileHistory.UpdateStatesSource(NULL); DeleteGlobalPrefs(gGlobalPrefs); // it's still possible to crash after this (destructors of static classes, // atexit() code etc.) point, but it's very unlikely UninstallCrashHandler(); // output leaks after all destructors of static objects have run _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); return retCode; #endif }
/** * @brief * 主要処理系のスレッドの初期化を行います。 * * @param pContext * I4C3Dモジュールのコンテキストのポインタ。 * * @returns * 初期化が成功しスレッドが実行できた場合にTRUE、失敗した場合にはFALSEを返します。 * * 各種設定の読み込みや、主要処理系のスレッドの初期化を行います。 * 失敗した場合はInitialize()でリソース解放処理が行われます。 * * @see * Initialize() */ BOOL I4C3DCore::InitializeMainContext(I4C3DContext* pContext) { USHORT uBridgePort = 0; // 設定ファイルよりSleepカウントを取得 PCTSTR szSleepCount = pContext->pAnalyzer->GetGlobalValue(TAG_SLEEPCOUNT); if (szSleepCount == NULL || _stscanf_s(szSleepCount, _T("%d"), &g_sleepCount) != 1) { g_sleepCount = 1; } // 設定ファイルよりBridge Portを取得 PCTSTR szPort = pContext->pAnalyzer->GetGlobalValue(TAG_PORT); if (szPort == NULL) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_CFG_PORT), GetLastError(), g_FILE, __LINE__); I4C3DExit(EXIT_INVALID_FILE_CONFIGURATION); return FALSE; } if (_stscanf_s(szPort, _T("%hu"), &uBridgePort) != 1) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_CFG_PORT), GetLastError(), g_FILE, __LINE__); I4C3DExit(EXIT_INVALID_FILE_CONFIGURATION); return FALSE; } // 設定ファイルより接続クライアント数を取得 PCTSTR szBacklog = pContext->pAnalyzer->GetGlobalValue(TAG_BACKLOG); if (szBacklog == NULL || _stscanf_s(szBacklog, _T("%d"), &g_backlog) != 1) { g_backlog = 8; } g_ChildThreadInfoLimit = min(_countof(g_ChildThreadInfo), g_backlog); g_backlog *= 3; // 全端末SYN2回まで失敗できるだけのバックログ // iPhone待ち受けソケット生成 I4C3DAccessor accessor; pContext->receiver = accessor.InitializeTCPSocket(&pContext->address, NULL, FALSE, uBridgePort); if (pContext->receiver == INVALID_SOCKET) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_SOCKET_INVALID), GetLastError(), g_FILE, __LINE__); I4C3DExit(EXIT_SOCKET_ERROR); return FALSE; } // 待ちうけ終了イベント作成 pContext->hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (pContext->hStopEvent == NULL) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); closesocket(pContext->receiver); I4C3DExit(EXIT_SYSTEM_ERROR); return FALSE; } pContext->hThread = (HANDLE)_beginthreadex(NULL, 0, &I4C3DReceiveThreadProc, (void*)pContext, CREATE_SUSPENDED, NULL/*&pContext->uThreadID*/); if (pContext->hThread == INVALID_HANDLE_VALUE) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); SafeCloseHandle(pContext->hStopEvent); closesocket(pContext->receiver); I4C3DExit(EXIT_SYSTEM_ERROR); return FALSE; } ResumeThread(pContext->hThread); return TRUE; }