bool CSetDlgFonts::StartEnumFontsThread() { _ASSERTE(mh_EnumThread == NULL); mb_EnumThreadFinished = false; mh_EnumThread = apiCreateThread(EnumFontsThread, NULL, &mn_EnumThreadId, "EnumFontsThread"); // хэндл закроет сама нить return (mh_EnumThread != NULL); }
void WindowHandler::Check() { if(!m_Thread || WaitForSingleObject(m_Thread, 0)!=WAIT_TIMEOUT) { m_Thread = apiCreateThread(nullptr, 0, this, &WindowHandler::WindowThreadRoutine, nullptr, 0, nullptr); } }
void Close() { if (bTokenInitialized) { GdiplusShutdown(gdiplusToken); bTokenInitialized = false; } if (hGDIPlus) { //FreeLibrary(hGDIPlus); DWORD nFreeTID = 0, nWait = 0, nErr = 0; HANDLE hFree = apiCreateThread(FreeThreadProc, this, &nFreeTID, "gdip::FreeThreadProc"); if (!hFree) { nErr = GetLastError(); FreeLibrary(hGDIPlus); } else { nWait = WaitForSingleObject(hFree, 5000); if (nWait != WAIT_OBJECT_0) apiTerminateThread(hFree, 100); CloseHandle(hFree); } hGDIPlus = NULL; } if (bCoInitialized) { bCoInitialized = FALSE; CoUninitialize(); } FREE(this); };
CAttachDlg::AttachMacroRet CAttachDlg::AttachFromMacro(DWORD anPID, bool abAlternative) { MArray<AttachParm> Parms; HWND hFind = NULL; CProcessData ProcessData; while ((hFind = FindWindowEx(NULL, hFind, NULL, NULL)) != NULL) { if (!IsWindowVisible(hFind)) continue; AttachWndInfo Info = {}; if (!GetWindowThreadProcessId(hFind, &Info.nPID) || (Info.nPID != anPID)) continue; if (!CanAttachWindow(hFind, 0, &ProcessData, Info)) continue; AttachParm p = {}; p.hAttachWnd = hFind; p.nPID = Info.nPID; p.nBits = Info.nImageBits; if (lstrcmp(Info.szType, szTypeCon) == 0) p.nType = apt_Console; else if (lstrcmp(Info.szType, szTypeGui) == 0) p.nType = apt_Gui; else continue; p.bAlternativeMode = abAlternative; Parms.push_back(p); } if (Parms.empty()) return amr_WindowNotFound; if (Parms.size() > 1) return amr_Ambiguous; AttachParm Null = {}; Parms.push_back(Null); // Работу делаем в фоновом потоке, чтобы не блокировать главный // (к окну ConEmu должна подцепиться новая вкладка) AttachParm* pParm = Parms.detach(); if (!pParm) return amr_Unexpected; DWORD nTID = 0; HANDLE hThread = apiCreateThread((LPTHREAD_START_ROUTINE)StartAttachThread, pParm, &nTID, "CAttachDlg::StartAttachThread#2"); if (!hThread) { //DWORD dwErr = GetLastError(); //_wsprintf(szItem, SKIPLEN(countof(szItem)) L"ConEmu Attach, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); //DisplayLastError(L"Can't start attach thread", dwErr, 0, szItem); return amr_Unexpected; } // We don't need this handle CloseHandle(hThread); return amr_Success; }
bool CAttachDlg::OnStartAttach() { bool lbRc = false; // Тут нужно получить инфу из списка и дернуть собственно аттач wchar_t szItem[128] = {}; //DWORD nPID = 0, nBits = WIN3264TEST(32,64); //AttachProcessType nType = apt_Unknown; wchar_t *psz; int iSel, iCur; DWORD nTID; HANDLE hThread = NULL; AttachParm *pParm = NULL; MArray<AttachParm> Parms; //HWND hAttachWnd = NULL; ShowWindow(mh_Dlg, SW_HIDE); BOOL bAlternativeMode = (IsDlgButtonChecked(mh_Dlg, IDC_ATTACH_ALT) != 0); iSel = ListView_GetNextItem(mh_List, -1, LVNI_SELECTED); while (iSel >= 0) { iCur = iSel; iSel = ListView_GetNextItem(mh_List, iCur, LVNI_SELECTED); AttachParm L = {NULL, 0, WIN3264TEST(32,64), apt_Unknown, bAlternativeMode}; ListView_GetItemText(mh_List, iCur, alc_PID, szItem, countof(szItem)-1); L.nPID = wcstoul(szItem, &psz, 10); if (L.nPID) { psz = wcschr(szItem, L'['); if (!psz) { _ASSERTE(FALSE && "Process bitness was not detected?"); } else { L.nBits = wcstoul(psz+1, &psz, 10); } } ListView_GetItemText(mh_List, iCur, alc_Type, szItem, countof(szItem)); if (lstrcmp(szItem, szTypeCon) == 0) L.nType = apt_Console; else if (lstrcmp(szItem, szTypeGui) == 0) L.nType = apt_Gui; ListView_GetItemText(mh_List, iCur, alc_HWND, szItem, countof(szItem)); L.hAttachWnd = (szItem[0]==L'0' && szItem[1]==L'x') ? (HWND)(DWORD_PTR)wcstoul(szItem+2, &psz, 16) : NULL; if (!L.nPID || !L.nBits || !L.nType || !L.hAttachWnd) { MBoxAssert(L.nPID && L.nBits && L.nType && L.hAttachWnd); goto wrap; } Parms.push_back(L); } if (Parms.empty()) { goto wrap; } else { AttachParm N = {NULL}; Parms.push_back(N); } //// Чтобы клик от мышки в консоль не провалился //WARNING("Клик от мышки в консоль проваливается"); //gpConEmu->mouse.nSkipEvents[0] = WM_LBUTTONUP; //gpConEmu->mouse.nSkipEvents[1] = 0; //gpConEmu->mouse.nReplaceDblClk = 0; // Все, диалог закрываем, чтобы не мешался Close(); // Работу делаем в фоновом потоке, чтобы не блокировать главный // (к окну ConEmu должна подцепиться новая вкладка) pParm = Parms.detach(); if (!pParm) { _wsprintf(szItem, SKIPLEN(countof(szItem)) L"ConEmu Attach, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); DisplayLastError(L"Parms.detach() failed", -1, 0, szItem); goto wrap; } else { hThread = apiCreateThread((LPTHREAD_START_ROUTINE)StartAttachThread, pParm, &nTID, "CAttachDlg::StartAttachThread#1"); if (!hThread) { DWORD dwErr = GetLastError(); _wsprintf(szItem, SKIPLEN(countof(szItem)) L"ConEmu Attach, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); DisplayLastError(L"Can't start attach thread", dwErr, 0, szItem); } else lbRc = true; } wrap: // We don't need this handle if (hThread) CloseHandle(hThread); return lbRc; }
// 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 = apiCreateThread(BackgroundMacroError, pszErrText, &nTID, "BackgroundMacroError"); SafeCloseHandle(h); } } } else { //gFarVersion.dwBuild InfoW2800->MacroControl(&guid_ConEmu, MCTL_SENDSTRING, 0, &mcr); } }
BOOL WINAPI OnSetConsoleOutputCP(UINT wCodePageID) { //typedef BOOL (WINAPI* OnSetConsoleOutputCP_t)(UINT wCodePageID); ORIGINALFAST(SetConsoleOutputCP); _ASSERTE(OnSetConsoleOutputCP!=SetConsoleOutputCP); BOOL lbRc = FALSE; SCOCP sco = {wCodePageID, (OnSetConsoleCP_t)F(SetConsoleOutputCP), CreateEvent(NULL,FALSE,FALSE,NULL)}; DWORD nTID = 0, nWait = -1, nErr; /* wchar_t szErrText[255], szTitle[64]; msprintf(szTitle, SKIPLEN(countof(szTitle)) L"PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); */ #ifdef _DEBUG DWORD nPrevCP = GetConsoleOutputCP(); #endif DWORD nCurCP = 0; HANDLE hThread = apiCreateThread(SetConsoleCPThread, &sco, &nTID, "OnSetConsoleOutputCP(%u)", wCodePageID); if (!hThread) { nErr = GetLastError(); _ASSERTE(hThread!=NULL); /* msprintf(szErrText, SKIPLEN(countof(szErrText)) L"chcp(out) failed, ErrCode=0x%08X\nConEmuHooks.cpp:OnSetConsoleOutputCP", nErr); Message BoxW(NULL, szErrText, szTitle, MB_ICONSTOP|MB_SYSTEMMODAL); lbRc = FALSE; */ } else { HANDLE hEvents[2] = {hThread, sco.hReady}; nWait = WaitForMultipleObjects(2, hEvents, FALSE, SETCONCP_READYTIMEOUT); if (nWait != WAIT_OBJECT_0) nWait = WaitForSingleObject(hThread, SETCONCP_TIMEOUT); if (nWait == WAIT_OBJECT_0) { lbRc = sco.lbRc; } else { //BUGBUG: На некоторых системых (Win2k3, WinXP) SetConsoleCP (и иже с ними) просто зависают apiTerminateThread(hThread,100); nCurCP = GetConsoleOutputCP(); if (nCurCP == wCodePageID) { lbRc = TRUE; // таки получилось } else { _ASSERTE(nCurCP == wCodePageID); /* msprintf(szErrText, SKIPLEN(countof(szErrText)) L"chcp(out) hung detected\n" L"ConEmuHooks.cpp:OnSetConsoleOutputCP\n" L"ReqOutCP=%u, PrevOutCP=%u, CurOutCP=%u\n" //L"\nPress <OK> to stop waiting" ,wCodePageID, nPrevCP, nCurCP); Message BoxW(NULL, szErrText, szTitle, MB_ICONSTOP|MB_SYSTEMMODAL); */ } //nWait = WaitForSingleObject(hThread, 0); //if (nWait == WAIT_TIMEOUT) // apiTerminateThread(hThread,100); //if (GetConsoleOutputCP() == wCodePageID) // lbRc = TRUE; } CloseHandle(hThread); } if (sco.hReady) CloseHandle(sco.hReady); return lbRc; }
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; };
int MyAssertProc(const wchar_t* pszFile, int nLine, const wchar_t* pszTest, bool abNoPipe) { HooksUnlocker; #ifdef _DEBUG if (MyAssertSkip(pszFile, nLine, pszTest, abNoPipe)) return 1; #endif MyAssertDumpToFile(pszFile, nLine, pszTest); HANDLE hHeap = GetProcessHeap(); MyAssertInfo* pa = (MyAssertInfo*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(MyAssertInfo)); if (!pa) return -1; wchar_t *szExeName = (wchar_t*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, (MAX_PATH+1)*sizeof(wchar_t)); if (szExeName && !GetModuleFileNameW(NULL, szExeName, MAX_PATH+1)) szExeName[0] = 0; pa->bNoPipe = abNoPipe; msprintf(pa->szTitle, countof(pa->szTitle), L"CEAssert PID=%u TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); wchar_t szVer4[2] = WSTRING(MVV_4a); msprintf(pa->szDebugInfo, countof(pa->szDebugInfo), L"Assertion in %s [%02u%02u%02u%s]\n%s\n\n%s: %i\n\nPress 'Retry' to trap.", szExeName ? szExeName : L"<HeapAllocFailed>", MVV_1, MVV_2, MVV_3, szVer4, pszTest ? pszTest : L"", pszFile, nLine); DWORD dwCode = 0; if (gAllowAssertThread == am_Thread) { DWORD dwTID; HANDLE hThread = apiCreateThread(MyAssertThread, pa, &dwTID, "MyAssertThread"); if (hThread == NULL) { dwCode = IDRETRY; goto wrap; } WaitForSingleObject(hThread, INFINITE); GetExitCodeThread(hThread, &dwCode); CloseHandle(hThread); goto wrap; } #ifdef ASSERT_PIPE_ALLOWED #ifdef _DEBUG if (!abNoPipe && (gAllowAssertThread == am_Pipe)) { HWND hConWnd = GetConEmuHWND(2); HWND hGuiWnd = ghConEmuWnd; // -- искать - нельзя. Если мы НЕ в ConEmu - нельзя стучаться в другие копии!!! //#ifndef CONEMU_MINIMAL //if (hGuiWnd == NULL) //{ // hGuiWnd = FindWindowEx(NULL, NULL, VirtualConsoleClassMain, NULL); //} //#endif if (hGuiWnd && gnInMyAssertTrap <= 0) { InterlockedIncrement(&gnInMyAssertTrap); InterlockedIncrement(&gnInMyAssertPipe); gnInMyAssertThread = GetCurrentThreadId(); ResetEvent(ghInMyAssertTrap); dwCode = GuiMessageBox(abNoPipe ? NULL : hGuiWnd, pa->szDebugInfo, pa->szTitle, MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_RETRYCANCEL); InterlockedDecrement(&gnInMyAssertTrap); InterlockedDecrement(&gnInMyAssertPipe); SetEvent(ghInMyAssertTrap); gnInMyAssertThread = 0; goto wrap; } } while (gnInMyAssertPipe>0 && (gnInMyAssertThread != GetCurrentThreadId())) { Sleep(250); } #endif #endif // В консольных приложениях попытка запустить CreateThread(MyAssertThread) может зависать dwCode = MyAssertThread(pa); wrap: if (pa) HeapFree(hHeap, 0, pa); if (szExeName) HeapFree(hHeap, 0, szExeName); return (dwCode == IDRETRY) ? -1 : 1; }
// 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); }