int apiGetFullPathName(LPCWSTR lpFileName, CEStr& rsPath) { bool bFound = false; wchar_t *pszFilePart, *pszBuffer = NULL; wchar_t szFind[MAX_PATH+1]; DWORD nLen = GetFullPathName(lpFileName, countof(szFind), szFind, &pszFilePart); if (nLen) { if (nLen < countof(szFind)) { bFound = true; rsPath.Set(szFind); } else { // Too long path, allocate more space pszBuffer = (wchar_t*)malloc((++nLen)*sizeof(*pszBuffer)); if (pszBuffer) { DWORD nLen2 = GetFullPathName(lpFileName, nLen, pszBuffer, &pszFilePart); if (nLen2 && (nLen2 < nLen)) { bFound = true; rsPath.Set(pszBuffer); } free(pszBuffer); } } } return bFound ? rsPath.GetLen() : 0; }
// Create the command to show on the Integration settings page LPCWSTR CreateCommand(CEStr& rsReady) { rsReady = L""; for (INT_PTR i = 0; i < ourSwitches.size(); i++) { Switch* ps = ourSwitches[i]; _ASSERTE(ps && !ps->szSwitch.IsEmpty()); bool bOpt = !ps->szOpt.IsEmpty(); bool bQuot = (bOpt && IsQuotationNeeded(ps->szOpt)); lstrmerge(&rsReady.ms_Val, ps->szSwitch, bOpt ? L" " : NULL, bQuot ? L"\"" : NULL, bOpt ? ps->szOpt.c_str() : NULL, bQuot ? L"\" " : L" "); } if (!rsReady.IsEmpty() || bCmdList) { lstrmerge(&rsReady.ms_Val, bCmdList ? L"-runlist " : L"-run ", szCmd); } else { rsReady.Set(szCmd); } return rsReady.c_str(L""); };
bool FileSearchInDir(LPCWSTR asFilePath, CEStr& rsFound) { // Possibilities // a) asFilePath does not contain path, only: "far" // b) asFilePath contains path, but without extension: "C:\\Program Files\\Far\\Far" LPCWSTR pszSearchFile = asFilePath; LPCWSTR pszSlash = wcsrchr(asFilePath, L'\\'); if (pszSlash) { if ((pszSlash - asFilePath) >= MAX_PATH) { // No need to continue, this is invalid path to executable return false; } // C:\Far\Far.exe /w /pC:\Far\Plugins\ConEmu;C:\Far\Plugins.My if (!IsFilePath(asFilePath, false)) { return false; } // Do not allow '/' here LPCWSTR pszFwd = wcschr(asFilePath, L'/'); if (pszFwd != NULL) { return false; } } wchar_t* pszSearchPath = NULL; if (pszSlash) { if ((pszSearchPath = lstrdup(asFilePath)) != NULL) { pszSearchFile = pszSlash + 1; pszSearchPath[pszSearchFile - asFilePath] = 0; } } // Попытаемся найти "по путям" (%PATH%) wchar_t *pszFilePart; wchar_t szFind[MAX_PATH+1]; LPCWSTR pszExt = PointToExt(asFilePath); DWORD nLen = SearchPath(pszSearchPath, pszSearchFile, pszExt ? NULL : L".exe", countof(szFind), szFind, &pszFilePart); SafeFree(pszSearchPath); if (nLen && (nLen < countof(szFind)) && FileExists(szFind)) { // asFilePath will be invalid after .Set rsFound.Set(szFind); return true; } return false; }
void SetFKey(CEStr& lsSubst, UINT fn) { if (!Mods) { msprintf(szSubst, countof(szSubst), L"\033[%u~", fn); } else { msprintf(szSubst, countof(szSubst), L"\033[%u;%c~", fn, Mods+L'1'); } lsSubst.Set(szSubst); }
void SetTilde(CEStr& lsSubst, wchar_t c) { if (!Mods) { msprintf(szSubst, countof(szSubst), L"\033[%c~", c); } else { msprintf(szSubst, countof(szSubst), L"\033[%c;%c~", c, Mods+L'1'); } lsSubst.Set(szSubst); }
void SetKey(CEStr& lsSubst, wchar_t c, wchar_t prefix=L'O') { if (!Mods) { //wcscpy_c(szSubst, L"\033O*A"); msprintf(szSubst, countof(szSubst), L"\033%c%c", prefix, c); } else { msprintf(szSubst, countof(szSubst), L"\033[1;%c%c", Mods+L'1', c); } lsSubst.Set(szSubst); }
// Returns 0 if succeeded, otherwise the error code int NextLine(const wchar_t** asLines, CEStr &rsLine, NEXTLINEFLAGS Flags /*= NLF_TRIM_SPACES|NLF_SKIP_EMPTY_LINES*/) { if (!asLines || !*asLines) return CERR_CMDLINEEMPTY; const wchar_t* psz = *asLines; //const wchar_t szSpaces[] = L" \t"; //const wchar_t szLines[] = L"\r\n"; //const wchar_t szSpacesLines[] = L" \t\r\n"; if ((Flags & (NLF_TRIM_SPACES|NLF_SKIP_EMPTY_LINES)) == (NLF_TRIM_SPACES|NLF_SKIP_EMPTY_LINES)) psz = SkipNonPrintable(psz); else if (Flags & NLF_TRIM_SPACES) while (*psz == L' ' || *psz == L'\t') psz++; else if (Flags & NLF_SKIP_EMPTY_LINES) while (*psz == L'\r' || *psz == L'\n') psz++; if (!*psz) { *asLines = psz; return CERR_CMDLINEEMPTY; } const wchar_t* pszEnd = wcspbrk(psz, L"\r\n"); if (!pszEnd) { pszEnd = psz + lstrlen(psz); } const wchar_t* pszTrim = pszEnd; if (*pszEnd == L'\r') pszEnd++; if (*pszEnd == L'\n') pszEnd++; if (Flags & NLF_TRIM_SPACES) { while ((pszTrim > psz) && ((*(pszTrim-1) == L' ') || (*(pszTrim-1) == L'\t'))) pszTrim--; } _ASSERTE(pszTrim >= psz); rsLine.Set(psz, pszTrim-psz); psz = pszEnd; *asLines = psz; return 0; }
bool CLngRc::GetResource(MArray<LngRcItem>& arr, int idx, CEStr& lsText) { bool bFound = false; if ((idx >= 0) && (idx < arr.size())) { const LngRcItem& item = arr[idx]; if (item.Processed && (item.Str && *item.Str)) { lsText.Set(item.Str); bFound = true; } } return bFound; }
bool IsNeedCmd(BOOL bRootCmd, LPCWSTR asCmdLine, CEStr &szExe, LPCWSTR* rsArguments /*= NULL*/, BOOL* rpbNeedCutStartEndQuot /*= NULL*/, BOOL* rpbRootIsCmdExe /*= NULL*/, BOOL* rpbAlwaysConfirmExit /*= NULL*/, BOOL* rpbAutoDisableConfirmExit /*= NULL*/) { bool rbNeedCutStartEndQuot = false; bool rbRootIsCmdExe = true; bool rbAlwaysConfirmExit = false; bool rbAutoDisableConfirmExit = false; wchar_t *pwszEndSpace; if (rsArguments) *rsArguments = NULL; bool lbRc = false; int iRc = 0; BOOL lbFirstWasGot = FALSE; LPCWSTR pwszCopy; int nLastChar; #ifdef _DEBUG CEStr szDbgFirst; #endif if (!asCmdLine || !*asCmdLine) { _ASSERTE(asCmdLine && *asCmdLine); goto wrap; } #ifdef _DEBUG // Это минимальные проверки, собственно к коду - не относятся bool bIsBatch = false; { LPCWSTR psz = asCmdLine; NextArg(&psz, szDbgFirst); psz = PointToExt(szDbgFirst); if (lstrcmpi(psz, L".cmd")==0 || lstrcmpi(psz, L".bat")==0) bIsBatch = true; } #endif if (!szExe.GetBuffer(MAX_PATH)) { _ASSERTE(FALSE && "Failed to allocate MAX_PATH"); lbRc = true; goto wrap; } szExe.Empty(); if (!asCmdLine || *asCmdLine == 0) { _ASSERTE(asCmdLine && *asCmdLine); lbRc = true; goto wrap; } pwszCopy = asCmdLine; // cmd /c ""c:\program files\arc\7z.exe" -?" // да еще и внутри могут быть двойными... // cmd /c "dir c:\" nLastChar = lstrlenW(pwszCopy) - 1; if (pwszCopy[0] == L'"' && pwszCopy[nLastChar] == L'"') { //if (pwszCopy[1] == L'"' && pwszCopy[2]) //{ // pwszCopy ++; // Отбросить первую кавычку в командах типа: ""c:\program files\arc\7z.exe" -?" // if (rbNeedCutStartEndQuot) *rbNeedCutStartEndQuot = TRUE; //} //else // глючила на ""F:\VCProject\FarPlugin\#FAR180\far.exe -new_console"" //if (wcschr(pwszCopy+1, L'"') == (pwszCopy+nLastChar)) { // LPCWSTR pwszTemp = pwszCopy; // // Получим первую команду (исполняемый файл?) // if ((iRc = NextArg(&pwszTemp, szArg)) != 0) { // //Parsing command line failed // lbRc = true; goto wrap; // } // pwszCopy ++; // Отбросить первую кавычку в командах типа: "c:\arc\7z.exe -?" // lbFirstWasGot = TRUE; // if (rbNeedCutStartEndQuot) *rbNeedCutStartEndQuot = TRUE; //} else { // Will be dequoted in 'NextArg' function. Examples // "C:\GCC\msys\bin\make.EXE -f "makefile" COMMON="../../../plugins/common"" // ""F:\VCProject\FarPlugin\#FAR180\far.exe -new_console"" // ""cmd"" // cmd /c ""c:\program files\arc\7z.exe" -?" // да еще и внутри могут быть двойными... // cmd /c "dir c:\" LPCWSTR pwszTemp = pwszCopy; // Получим первую команду (исполняемый файл?) if ((iRc = NextArg(&pwszTemp, szExe)) != 0) { //Parsing command line failed #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } if (lstrcmpiW(szExe, L"start") == 0) { // Команду start обрабатывает только процессор #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } LPCWSTR pwszQ = pwszCopy + 1 + lstrlen(szExe); wchar_t* pszExpand = NULL; if (*pwszQ != L'"' && IsExecutable(szExe, &pszExpand)) { pwszCopy ++; // отбрасываем lbFirstWasGot = TRUE; if (pszExpand) { szExe.Set(pszExpand); SafeFree(pszExpand); if (rsArguments) *rsArguments = pwszQ; } rbNeedCutStartEndQuot = true; } } } // Получим первую команду (исполняемый файл?) if (!lbFirstWasGot) { szExe.Empty(); // `start` command must be processed by processor itself if ((lstrcmpni(pwszCopy, L"start", 5) == 0) && (!pwszCopy[5] || isSpace(pwszCopy[5]))) { #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } // 17.10.2010 - support executable file path without parameters, but with spaces in its path // 22.11.2015 - or some weirdness, like `C:\Program Files\CB/cb_console_runner.exe "C:\sources\app.exe"` LPCWSTR pchEnd = wcschr(pwszCopy, L' '); if (!pchEnd) pchEnd = pwszCopy + lstrlenW(pwszCopy); CEStr szTemp; DWORD nTempSize; while (pchEnd) { szTemp.Set(pwszCopy, (pchEnd - pwszCopy)); _ASSERTE(szTemp[(pchEnd - pwszCopy)] == 0); // If this is a full path without environment variables if (((IsFilePath(szTemp, true) && !wcschr(szTemp, L'%')) // or file/dir may be found via env.var. substitution or searching in %PATH% || FileExistsSearch((LPCWSTR)szTemp, szTemp)) // Than check if it is a FILE (not a directory) && FileExists(szTemp, &nTempSize) && nTempSize) { // OK, it an our executable? if (rsArguments) *rsArguments = pchEnd; szExe.Set(szTemp); break; } _ASSERTE(*pchEnd == 0 || *pchEnd == L' '); if (!*pchEnd) break; // Find next space after nonspace while (*(pchEnd) == L' ') pchEnd++; // If quoted string starts from here - it's supposed to be an argument if (*pchEnd == L'"') { // And we must not get here, because the executable must be already processed above // _ASSERTE(*pchEnd != L'"'); break; } pchEnd = wcschr(pchEnd, L' '); if (!pchEnd) pchEnd = pwszCopy + lstrlenW(pwszCopy); } if (szExe[0] == 0) { if ((iRc = NextArg(&pwszCopy, szExe)) != 0) { //Parsing command line failed #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } _ASSERTE(lstrcmpiW(szExe, L"start") != 0); // Обработка переменных окружения и поиск в PATH if (FileExistsSearch((LPCWSTR)szExe, szExe)) { if (rsArguments) *rsArguments = pwszCopy; } } } if (!*szExe) { _ASSERTE(szExe[0] != 0); } else { // Если юзеру нужен редирект - то он должен явно указать ком.процессор // Иначе нереально (или достаточно сложно) определить, является ли символ // редиректом, или это просто один из аргументов команды... // "Левые" символы в имени файла (а вот в "первом аргументе" все однозначно) if (wcspbrk(szExe, L"?*<>|")) { rbRootIsCmdExe = TRUE; // запуск через "процессор" lbRc = true; goto wrap; // добавить "cmd.exe" } // если "путь" не указан if (wcschr(szExe, L'\\') == NULL) { bool bHasExt = (wcschr(szExe, L'.') != NULL); // Проверим, может это команда процессора (типа "DIR")? if (!bHasExt) { bool bIsCommand = false; wchar_t* pszUppr = lstrdup(szExe); if (pszUppr) { // избежать линковки на user32.dll //CharUpperBuff(pszUppr, lstrlen(pszUppr)); for (wchar_t* p = pszUppr; *p; p++) { if (*p >= L'a' && *p <= 'z') *p -= 0x20; } const wchar_t* pszFind = gsInternalCommands; while (*pszFind) { if (lstrcmp(pszUppr, pszFind) == 0) { bIsCommand = true; break; } pszFind += lstrlen(pszFind)+1; } free(pszUppr); } if (bIsCommand) { #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif rbRootIsCmdExe = TRUE; // запуск через "процессор" lbRc = true; goto wrap; // добавить "cmd.exe" } } // Try to find executable in %PATH% { #ifndef CONEMU_MINIMAL MWow64Disable wow; wow.Disable(); // Disable Wow64 file redirector #endif apiSearchPath(NULL, szExe, bHasExt ? NULL : L".exe", szExe); } } // end: if (wcschr(szExe, L'\\') == NULL) } // Если szExe не содержит путь к файлу - запускаем через cmd // "start "" C:\Utils\Files\Hiew32\hiew32.exe C:\00\Far.exe" if (!IsFilePath(szExe)) { #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif rbRootIsCmdExe = TRUE; // запуск через "процессор" lbRc = true; goto wrap; // добавить "cmd.exe" } //pwszCopy = wcsrchr(szArg, L'\\'); if (!pwszCopy) pwszCopy = szArg; else pwszCopy ++; pwszCopy = PointToName(szExe); //2009-08-27 pwszEndSpace = szExe.ms_Val + lstrlenW(szExe) - 1; while ((*pwszEndSpace == L' ') && (pwszEndSpace > szExe)) { *(pwszEndSpace--) = 0; } #ifndef __GNUC__ #pragma warning( push ) #pragma warning(disable : 6400) #endif if (lstrcmpiW(pwszCopy, L"cmd")==0 || lstrcmpiW(pwszCopy, L"cmd.exe")==0 || lstrcmpiW(pwszCopy, L"tcc")==0 || lstrcmpiW(pwszCopy, L"tcc.exe")==0) { rbRootIsCmdExe = TRUE; // уже должен быть выставлен, но проверим rbAlwaysConfirmExit = TRUE; rbAutoDisableConfirmExit = FALSE; _ASSERTE(!bIsBatch); lbRc = false; goto wrap; // уже указан командный процессор, cmd.exe в начало добавлять не нужно } // Issue 1211: Decide not to do weird heuristic. // If user REALLY needs redirection (root command, huh?) // - he must call "cmd /c ..." directly // Если есть одна из команд перенаправления, или слияния - нужен CMD.EXE if (!bRootCmd) { if (wcschr(asCmdLine, L'&') || wcschr(asCmdLine, L'>') || wcschr(asCmdLine, L'<') || wcschr(asCmdLine, L'|') || wcschr(asCmdLine, L'^') // или экранирования ) { #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } } //if (lstrcmpiW(pwszCopy, L"far")==0 || lstrcmpiW(pwszCopy, L"far.exe")==0) if (IsFarExe(pwszCopy)) { bool bFound = (wcschr(pwszCopy, L'.') != NULL); // Если указали при запуске просто "far" - это может быть батник, расположенный в %PATH% if (!bFound) { CEStr szSearch; if (apiSearchPath(NULL, pwszCopy, L".exe", szSearch)) { if (lstrcmpi(PointToExt(szSearch), L".exe") == 0) bFound = true; } } if (bFound) { rbAutoDisableConfirmExit = TRUE; rbRootIsCmdExe = FALSE; // FAR! _ASSERTE(!bIsBatch); lbRc = false; goto wrap; // уже указан исполняемый файл, cmd.exe в начало добавлять не нужно } } if (IsExecutable(szExe)) { rbRootIsCmdExe = FALSE; // Для других программ - буфер не включаем _ASSERTE(!bIsBatch); lbRc = false; goto wrap; // Запускается конкретная консольная программа. cmd.exe не требуется } //Можно еще Доделать поиски с: SearchPath, GetFullPathName, добавив расширения .exe & .com //хотя фар сам формирует полные пути к командам, так что можно не заморачиваться #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif rbRootIsCmdExe = TRUE; #ifndef __GNUC__ #pragma warning( pop ) #endif lbRc = true; wrap: if (rpbNeedCutStartEndQuot) *rpbNeedCutStartEndQuot = rbNeedCutStartEndQuot; if (rpbRootIsCmdExe) *rpbRootIsCmdExe = rbRootIsCmdExe; if (rpbAlwaysConfirmExit) *rpbAlwaysConfirmExit = rbAlwaysConfirmExit; if (rpbAutoDisableConfirmExit) *rpbAutoDisableConfirmExit = rbAutoDisableConfirmExit; return lbRc; }
// Returns 0 if succeeded, otherwise the error code int NextArg(const wchar_t** asCmdLine, CEStr &rsArg, const wchar_t** rsArgStart/*=NULL*/) { if (!asCmdLine || !*asCmdLine) return CERR_CMDLINEEMPTY; #ifdef _DEBUG if ((rsArg.mn_TokenNo==0) // first token || ((rsArg.mn_TokenNo>0) && (rsArg.ms_LastTokenEnd==*asCmdLine) && (wcsncmp(*asCmdLine,rsArg.ms_LastTokenSave,countof(rsArg.ms_LastTokenSave)-1))==0)) { // OK, параметры корректны } else { _ASSERTE(FALSE && "rsArgs was not resetted before new cycle!"); } #endif LPCWSTR psCmdLine = SkipNonPrintable(*asCmdLine), pch = NULL; if (!*psCmdLine) return CERR_CMDLINEEMPTY; // Remote surrounding quotes, in certain cases // Example: ""7z.exe" /?" // Example: "C:\Windows\system32\cmd.exe" /C ""C:\Python27\python.EXE"" if ((rsArg.mn_TokenNo == 0) || (rsArg.mn_CmdCall == CEStr::cc_CmdCK)) { if (IsNeedDequote(psCmdLine, (rsArg.mn_CmdCall == CEStr::cc_CmdCK), &rsArg.mpsz_Dequoted)) psCmdLine++; if (rsArg.mn_CmdCall == CEStr::cc_CmdCK) rsArg.mn_CmdCall = CEStr::cc_CmdCommand; } size_t nArgLen = 0; bool lbQMode = false; // аргумент начинается с " if (*psCmdLine == L'"') { lbQMode = true; psCmdLine++; // ... /d "\"C:\ConEmu\ConEmuPortable.exe\" /Dir ... bool bQuoteEscaped = (psCmdLine[0] == L'\\' && psCmdLine[1] == L'"'); pch = wcschr(psCmdLine, L'"'); if (pch && (pch > psCmdLine)) { // To be correctly parsed something like this: // reg.exe add "HKCU\MyCo" /ve /t REG_EXPAND_SZ /d "\"C:\ConEmu\ConEmuPortable.exe\" /Dir \"%V\" /cmd \"cmd.exe\" \"-new_console:nC:cmd.exe\" \"-cur_console:d:%V\"" /f // But must not fails with ‘simple’ command like (no escapes in "C:\"): // /dir "C:\" /icon "cmd.exe" /single // Prev version fails while getting strings for -GuiMacro, example: // ConEmu.exe -detached -GuiMacro "print(\" echo abc \"); Context;" pch = wcspbrk(psCmdLine, L"\\\""); while (pch) { // Escaped quotation? if ((*pch == L'\\') && (*(pch+1) == L'"')) { // It's allowed when: // a) at the beginning of the line (handled above, bQuoteEscaped); // b) after space, left bracket or colon (-GuiMacro) // c) when already was forced by bQuoteEscaped if (( ((((pch - 1) >= psCmdLine) && wcschr(L" (,", *(pch-1))) || (*(pch+2) && !isSpace(*(pch+2))) )) || bQuoteEscaped) { bQuoteEscaped = true; pch++; // Point to " } } else if (*pch == L'"') break; // Next entry AFTER pch pch = wcspbrk(pch+1, L"\\\""); } } if (!pch) return CERR_CMDLINE; while (pch[1] == L'"' && (!rsArg.mpsz_Dequoted || ((pch+1) < rsArg.mpsz_Dequoted))) { pch += 2; pch = wcschr(pch, L'"'); if (!pch) return CERR_CMDLINE; } // Теперь в pch ссылка на последнюю " } else { // До конца строки или до первого пробела //pch = wcschr(psCmdLine, L' '); // 09.06.2009 Maks - обломался на: cmd /c" echo Y " pch = psCmdLine; // General: Look for spacing of quote while (*pch && *pch!=L'"' && *pch!=L' ' && *pch!=L'\t' && *pch!=L'\r' && *pch!=L'\n') pch++; //if (!pch) pch = psCmdLine + lstrlenW(psCmdLine); // до конца строки } _ASSERTE(pch >= psCmdLine); nArgLen = pch - psCmdLine; // Set result arugment // Warning: Don't demangle quotes/escapes here, or we'll fail to // concatenate environment or smth, losing quotes and others if (!rsArg.Set(psCmdLine, nArgLen)) return CERR_CMDLINE; rsArg.mb_Quoted = lbQMode; rsArg.mn_TokenNo++; if (rsArgStart) *rsArgStart = psCmdLine; psCmdLine = pch; // Finalize if ((*psCmdLine == L'"') && (lbQMode || (rsArg.mpsz_Dequoted == psCmdLine))) psCmdLine++; // was pointed to closing quotation mark psCmdLine = SkipNonPrintable(psCmdLine); // When whole line was dequoted if ((*psCmdLine == L'"') && (rsArg.mpsz_Dequoted == psCmdLine)) psCmdLine++; #ifdef _DEBUG rsArg.ms_LastTokenEnd = psCmdLine; lstrcpyn(rsArg.ms_LastTokenSave, psCmdLine, countof(rsArg.ms_LastTokenSave)); #endif switch (rsArg.mn_CmdCall) { case CEStr::cc_Undefined: // Если это однозначно "ключ" - то на имя файла не проверяем if (*rsArg.ms_Val == L'/' || *rsArg.ms_Val == L'-') { // Это для парсинга (чтобы ассертов не было) параметров из ShellExecute (там cmd.exe указывается в другом аргументе) if ((rsArg.mn_TokenNo == 1) && (lstrcmpi(rsArg.ms_Val, L"/C") == 0 || lstrcmpi(rsArg.ms_Val, L"/K") == 0)) rsArg.mn_CmdCall = CEStr::cc_CmdCK; } else { pch = PointToName(rsArg.ms_Val); if (pch) { if ((lstrcmpi(pch, L"cmd") == 0 || lstrcmpi(pch, L"cmd.exe") == 0) || (lstrcmpi(pch, L"ConEmuC") == 0 || lstrcmpi(pch, L"ConEmuC.exe") == 0) || (lstrcmpi(pch, L"ConEmuC64") == 0 || lstrcmpi(pch, L"ConEmuC64.exe") == 0)) { rsArg.mn_CmdCall = CEStr::cc_CmdExeFound; } } } break; case CEStr::cc_CmdExeFound: if (lstrcmpi(rsArg.ms_Val, L"/C") == 0 || lstrcmpi(rsArg.ms_Val, L"/K") == 0) rsArg.mn_CmdCall = CEStr::cc_CmdCK; else if ((rsArg.ms_Val[0] != L'/') && (rsArg.ms_Val[0] != L'-')) rsArg.mn_CmdCall = CEStr::cc_Undefined; break; } *asCmdLine = psCmdLine; return 0; }
// Function checks, if we need drop first and last quotation marks // Example: ""7z.exe" /?" // Using cmd.exe rules bool IsNeedDequote(LPCWSTR asCmdLine, bool abFromCmdCK, LPCWSTR* rsEndQuote/*=NULL*/) { if (rsEndQuote) *rsEndQuote = NULL; if (!asCmdLine) return false; bool bDeQu = false; LPCWSTR pszQE, pszSP; if (asCmdLine[0] == L'"') { bDeQu = (asCmdLine[1] == L'"'); // Всегда - нельзя. Иначе парсинг строки запуска некорректно идет // L"\"C:\\ConEmu\\ConEmuC64.exe\" /PARENTFARPID=1 /C \"C:\\GIT\\cmdw\\ad.cmd CE12.sln & ci -m \"Solution debug build properties\"\"" if (!bDeQu) { size_t nLen = lstrlen(asCmdLine); if (abFromCmdCK) { bDeQu = ((asCmdLine[nLen-1] == L'"') && (asCmdLine[nLen-2] == L'"')); } if (!bDeQu && (asCmdLine[nLen-1] == L'"')) { pszSP = wcschr(asCmdLine+1, L' '); pszQE = wcschr(asCmdLine+1, L'"'); if (pszSP && pszQE && (pszSP < pszQE) && ((pszSP - asCmdLine) < MAX_PATH)) { CEStr lsTmp; lsTmp.Set(asCmdLine+1, pszSP-asCmdLine-1); bDeQu = (IsFilePath(lsTmp, true) && IsExecutable(lsTmp)); } } } } if (!bDeQu) return false; // Don't dequote? pszQE = wcsrchr(asCmdLine+2, L'"'); if (!pszQE) return false; #if 0 LPCWSTR pszQ1 = wcschr(asCmdLine+2, L'"'); if (!pszQ1) return false; LPCWSTR pszQE = wcsrchr(pszQ1, L'"'); // Only TWO quotes in asCmdLine? if (pszQE == pszQ1) { // Doesn't contains special symbols? if (!wcspbrk(asCmdLine+1, L"&<>()@^|")) { // Must contains spaces (doubt?) if (wcschr(asCmdLine+1, L' ')) { // Cmd also checks this for executable file name. Skip this check? return false; } } } #endif // Well, we get here _ASSERTE(asCmdLine[0]==L'"' && pszQE && *pszQE==L'"' && !wcschr(pszQE+1,L'"')); // Dequote it! if (rsEndQuote) *rsEndQuote = pszQE; return true; }
void CSetPgDebug::debugLogShell(DWORD nParentPID, CESERVER_REQ_ONCREATEPROCESS* pInfo) { CSetPgDebug* pDbgPg = (CSetPgDebug*)gpSetCls->GetPageObj(thi_Debug); if (!pDbgPg) return; if ((pDbgPg->GetActivityLoggingType() != glt_Processes) && (pDbgPg->GetActivityLoggingType() != glt_Shell)) return; LPCWSTR pszFile = pInfo->wsValue + pInfo->nActionLen; LPCWSTR pszParam = pInfo->wsValue + pInfo->nActionLen+pInfo->nFileLen; DebugLogShellActivity *shl = (DebugLogShellActivity*)calloc(sizeof(DebugLogShellActivity),1); shl->nParentPID = nParentPID; shl->nParentBits = pInfo->nSourceBits; wcscpy_c(shl->szFunction, pInfo->sFunction); shl->pszAction = lstrdup(pInfo->wsValue); shl->pszFile = lstrdup(pszFile); shl->pszParam = lstrdup(pszParam); shl->bDos = (pInfo->nImageBits == 16) && (pInfo->nImageSubsystem == IMAGE_SUBSYSTEM_DOS_EXECUTABLE); shl->nImageBits = pInfo->nImageBits; shl->nImageSubsystem = pInfo->nImageSubsystem; shl->nShellFlags = pInfo->nShellFlags; shl->nCreateFlags = pInfo->nCreateFlags; shl->nStartFlags = pInfo->nStartFlags; shl->nShowCmd = pInfo->nShowCmd; shl->hStdIn = (DWORD)pInfo->hStdIn; shl->hStdOut = (DWORD)pInfo->hStdOut; shl->hStdErr = (DWORD)pInfo->hStdErr; // Append directory and bat/tmp files contents to pszParam { LPCWSTR pszDir = (pInfo->wsValue+pInfo->nActionLen+pInfo->nFileLen+pInfo->nParamLen); LPCWSTR pszAppFile = NULL; wchar_t*& pszParamEx = shl->pszParam; if (pszDir && *pszDir) { CEStr lsDir((pszParamEx && *pszParamEx) ? L"\r\n\r\n" : NULL, L"CD: \"", pszDir, L"\""); lstrmerge(&pszParamEx, lsDir); } if (shl->pszFile) { LPCWSTR pszExt = PointToExt(shl->pszFile); if (pszExt && (!lstrcmpi(pszExt, L".bat") || !lstrcmpi(pszExt, L".cmd"))) debugLogShellText(pszParamEx, (pszAppFile = shl->pszFile)); } if (pszParam && *pszParam) { LPCWSTR pszNext = pszParam; CEStr szArg; while (0 == NextArg(&pszNext, szArg)) { if (!*szArg || (*szArg == L'-') || (*szArg == L'/')) continue; LPCWSTR pszExt = PointToExt(szArg); // Perhaps process *.tmp files too? (used with VC RC compilation?) if (pszExt && (!lstrcmpi(pszExt, L".bat") || !lstrcmpi(pszExt, L".cmd") /*|| !lstrcmpi(pszExt, L".tmp")*/) && (!pszAppFile || (lstrcmpi(szArg, pszAppFile) != 0))) { debugLogShellText(pszParamEx, szArg); } else if (szArg[0] == L'@') { CEStr lsPath; if (IsFilePath(szArg.Mid(1), true)) { // Full path to "arguments file" lsPath.Set(szArg.Mid(1)); } else if ((szArg[1] != L'\\' && szArg[1] != L'/') && (pszDir && *pszDir)) { // Relative path to "arguments file" lsPath = JoinPath(pszDir, szArg.Mid(1)); } if (!lsPath.IsEmpty()) { debugLogShellText(pszParamEx, lsPath); } } } } } // end of "Append directory and bat/tmp files contents to pszParam" PostMessage(pDbgPg->Dlg(), DBGMSG_LOG_ID, DBGMSG_LOG_SHELL_MAGIC, (LPARAM)shl); }
// pszFull comes from registry's [HKCR\Directory\shell\...\command] // Example: // "C:\Tools\ConEmu.exe" -inside -LoadCfgFile "C:\Tools\ConEmu.xml" -FontDir C:\Tools\ConEmu // -lngfile C:\Tools\ConEmu\ConEmu.l10n -lng ru -dir "%1" -run {cmd} -cur_console:n // Strip switches which match current instance startup arguments // No sense to show them (e.g. "-lng ru") in the Integration dialog page void StripDupSwitches(LPCWSTR pszFull) { bCmdList = false; szCmd = L""; szDirSync = L""; szConfig = L""; ReleaseVectors(); CEStr szArg, szNext; LPCWSTR psz; Switch* ps = NULL; // First, parse our extra args (passed to current ConEmu.exe) ParseStdSwitches(); // Now parse new switches (command from registry or from field on Integration page) // Drop `-dir "..."` (especially from registry) always! psz = pszFull; while (0 == NextArg(&psz, szArg)) { if (!szArg.IsPossibleSwitch()) continue; if (szArg.OneOfSwitches(L"-inside", L"-here")) { // Nop } else if (szArg.IsSwitch(L"-inside:")) // Both "-inside:" and "-inside=" notations are supported { szDirSync.Set(szArg.Mid(8)); // may be empty! } else if (szArg.IsSwitch(L"-config")) { if (0 != NextArg(&psz, szArg)) break; szConfig.Set(szArg); } else if (szArg.IsSwitch(L"-dir")) { if (0 != NextArg(&psz, szArg)) break; _ASSERTE(lstrcmpi(szArg, L"%1")==0); } else if (szArg.OneOfSwitches(L"-Single", L"-NoSingle", L"-ReUse")) { ps = new Switch(szArg.Detach(), NULL); ourSwitches.push_back(ps); } else if (szArg.OneOfSwitches(L"-run", L"-cmd", L"-runlist", L"-cmdlist")) { // FIN! LAST SWITCH! szCmd.Set(psz); bCmdList = szArg.OneOfSwitches(L"-runlist",L"-cmdlist"); break; } else if (NULL != (ps = GetNextSwitch(psz, szArg))) { if (IsIgnored(ps, GetSkipSwitches()) || IsIgnored(ps, stdSwitches)) { SafeDelete(ps); } else { ourSwitches.push_back(ps); } } } };
bool TermX::GetSubstitute(const KEY_EVENT_RECORD& k, CEStr& lsSubst) { _ASSERTE(lsSubst.IsEmpty()); // Bypass AltGr+keys to console intact if ((k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED)) == (LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED)) { if (k.uChar.UnicodeChar) { wchar_t szData[3] = {k.uChar.UnicodeChar}; if (LastDeadCharVK == k.wVirtualKeyCode) szData[1] = k.uChar.UnicodeChar; lsSubst.Set(szData); LastDeadCharVK = 0; } else { LastDeadCharVK = k.wVirtualKeyCode; lsSubst.Clear(); } return true; } wchar_t szSubst[16] = L""; static UINT F1Codes[24] = { 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 28, 29, 31, 32, 33, 34, 42, 43, 44, 45 }; static wchar_t F1F4Codes[] = {L'P', L'Q', L'R', L'S'}; static wchar_t ArrowCodes[] = {L'F', L'H', L'D', L'A', L'C', L'B'}; typedef DWORD XTermCtrls; const XTermCtrls xtc_Shift = 1, xtc_Alt = 2, xtc_Ctrl = 4, xtc_None = 0; struct processor { XTermCtrls Mods; wchar_t szSubst[16]; void SetKey(CEStr& lsSubst, wchar_t c, wchar_t prefix=L'O') { if (!Mods) { //wcscpy_c(szSubst, L"\033O*A"); msprintf(szSubst, countof(szSubst), L"\033%c%c", prefix, c); } else { msprintf(szSubst, countof(szSubst), L"\033[1;%c%c", Mods+L'1', c); } lsSubst.Set(szSubst); } void SetFKey(CEStr& lsSubst, UINT fn) { if (!Mods) { msprintf(szSubst, countof(szSubst), L"\033[%u~", fn); } else { msprintf(szSubst, countof(szSubst), L"\033[%u;%c~", fn, Mods+L'1'); } lsSubst.Set(szSubst); } void SetTilde(CEStr& lsSubst, wchar_t c) { if (!Mods) { msprintf(szSubst, countof(szSubst), L"\033[%c~", c); } else { msprintf(szSubst, countof(szSubst), L"\033[%c;%c~", c, Mods+L'1'); } lsSubst.Set(szSubst); } } Processor = {xtc_None}; if (k.dwControlKeyState & (SHIFT_PRESSED)) Processor.Mods |= xtc_Shift; if (k.dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) Processor.Mods |= xtc_Alt; if (k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) Processor.Mods |= xtc_Ctrl; switch (k.wVirtualKeyCode) { case VK_END: case VK_HOME: case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN: Processor.SetKey(lsSubst, ArrowCodes[(k.wVirtualKeyCode-VK_END)], AppCursorKeys ? L'O' : L'['); return true; case VK_F1: case VK_F2: case VK_F3: case VK_F4: Processor.SetKey(lsSubst, F1F4Codes[(k.wVirtualKeyCode-VK_F1)]); return true; case VK_F5: case VK_F6: case VK_F7: case VK_F8: case VK_F9: case VK_F10: case VK_F11: case VK_F12: case VK_F13: case VK_F14: case VK_F15: case VK_F16: case VK_F17: case VK_F18: case VK_F19: case VK_F20: case VK_F21: case VK_F22: case VK_F23: case VK_F24: // "\033[11;*~" .. L"\033[15;*~", and so on: F1Codes[] Processor.SetFKey(lsSubst, F1Codes[(k.wVirtualKeyCode-VK_F1)]); return true; case VK_INSERT: Processor.SetTilde(lsSubst, L'2'); return true; case VK_PRIOR: Processor.SetTilde(lsSubst, L'5'); return true; case VK_NEXT: Processor.SetTilde(lsSubst, L'6'); return true; case VK_DELETE: Processor.SetTilde(lsSubst, L'3'); return true; case VK_BACK: if ((Processor.Mods & xtc_Alt)) szSubst[0] = 0x1B; szSubst[(Processor.Mods == xtc_Alt) ? 1 : 0] = ((Processor.Mods & (xtc_Ctrl|xtc_Alt)) == (xtc_Ctrl|xtc_Alt)) ? 0x9F : (Processor.Mods & xtc_Ctrl) ? X_CTRL('_')/*0x1F*/ : X_CDEL/*0x7F*/; szSubst[(Processor.Mods == xtc_Alt) ? 2 : 1] = 0; lsSubst.Set(szSubst); return true; case VK_TAB: if (!(k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED|LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))) { wcscpy_c(szSubst, (k.dwControlKeyState & SHIFT_PRESSED) ? L"\033[Z" : L"\t"); } lsSubst.Set(szSubst); return true; /* NumPad with NumLock ON */ case VK_NUMPAD0: case VK_NUMPAD1: case VK_NUMPAD2: case VK_NUMPAD3: case VK_NUMPAD4: case VK_NUMPAD5: case VK_NUMPAD6: case VK_NUMPAD7: case VK_NUMPAD8: case VK_NUMPAD9: case VK_DECIMAL: // VK_OEM_PERIOD}, // Actually, this may be comma case VK_DIVIDE: case VK_MULTIPLY: case VK_SUBTRACT: case VK_ADD: if (k.uChar.UnicodeChar) { // Just a digits '0'..'9' and symbols +-/*. szSubst[0] = k.uChar.UnicodeChar; szSubst[1] = 0; } lsSubst.Set(szSubst); return true; } // Alt+Char if ((Processor.Mods & xtc_Alt) && k.uChar.UnicodeChar // connector/gh#4: AltGr+Char && (((k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED|LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) != (LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED)) // or just a Alt+Char || !(Processor.Mods & xtc_Ctrl)) ) { szSubst[0] = L'\033'; szSubst[1] = k.uChar.UnicodeChar; szSubst[2] = 0; lsSubst.Set(szSubst); return true; } // Ctrl+Char: A-->1, ..., J-->10, ... if (Processor.Mods & (xtc_Alt | xtc_Ctrl)) { wchar_t key_char = k.uChar.UnicodeChar; if (!key_char) { switch (k.wVirtualKeyCode) { case VK_OEM_2: key_char = L'?'; break; // Ctrl+/ -> \x1F case VK_OEM_3: key_char = L'~'; break; case VK_OEM_4: key_char = L'['; break; case VK_OEM_5: key_char = L'\\'; break; case VK_OEM_6: key_char = L']'; break; case VK_OEM_COMMA: key_char = L','; break; case VK_OEM_PERIOD: key_char = L'.'; break; case VK_OEM_MINUS: key_char = L'-'; break; case VK_OEM_PLUS: key_char = L'='; break; default: if (k.wVirtualKeyCode >= L'0' && k.wVirtualKeyCode <= L'9') key_char = k.wVirtualKeyCode; else if (k.wVirtualKeyCode >= L'A' && k.wVirtualKeyCode <= L'Z') key_char = k.wVirtualKeyCode; } } if (key_char) { szSubst[0] = szSubst[1] = szSubst[2] = szSubst[3] = 0; if ((Processor.Mods == xtc_Ctrl) && (key_char == L'2' || key_char == L' ')) { // Must send '\x00' but it's not a valid ASCIIZ string, have to be processed in connector return false; } else if (key_char >= L'A' && key_char <= L'Z') { if (Processor.Mods == xtc_Ctrl) { // In vt220: If XOFF support is enabled, then CTRL-S is a "hold screen" local function and CTRL-Q is an "unhold screen" local function. szSubst[0] = (wchar_t)(1 + (key_char - L'A')); } else if ((Processor.Mods == (xtc_Ctrl|xtc_Alt)) || (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift))) { szSubst[0] = 0x1B; szSubst[1] = (wchar_t)(1 + (key_char - L'A')); } // doesn't work, "showkey -a" receives "<x1B><xC3><x82><x01>" //else if (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift)) //{ // szSubst[0] = 0x1B; szSubst[1] = 0xC2; // szSubst[2] = (wchar_t)(1 + (key_char - L'A')); //} } else if ((Processor.Mods == xtc_Ctrl) && (key_char == L'1' || key_char == L'9' || key_char == L'0')) { // Strangely Ctrl+1, Ctrl+9, Ctrl+0 generate only 1, 9 and 0. szSubst[0] = key_char; } else if ((Processor.Mods == xtc_Ctrl) && (key_char >= L'3' && key_char <= L'7')) { szSubst[0] = (wchar_t)(0x1B + (key_char - L'3')); } else switch (key_char) { case L',': szSubst[0] = 0x2C; break; // Processor.SetKey(lsSubst, L'l'); break; case L'.': szSubst[0] = 0x2E; break; // Processor.SetKey(lsSubst, L'n'); break; //case L'-': // Processor.SetKey(lsSubst, L'm'); break; //case L'0': // Processor.SetKey(lsSubst, L'p'); break; //case L'1': // Processor.SetKey(lsSubst, L'q'); break; // case L'2': // processed above //case L'3': // Processor.SetKey(lsSubst, L's'); break; //case L'4': // Processor.SetKey(lsSubst, L't'); break; //case L'5': // Processor.SetKey(lsSubst, L'u'); break; //case L'6': case L'~': szSubst[0] = 0x1E; break; //case L'7': // Processor.SetKey(lsSubst, L'w'); break; case L'8': szSubst[0] = 0x1B; if ((Processor.Mods == (xtc_Ctrl|xtc_Alt)) || (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift))) szSubst[1] = 0x7F; else szSubst[0] = 0x7F; break; //Processor.SetKey(lsSubst, L'x'); break; //case L'9': // Processor.SetKey(lsSubst, L'y'); break; //case L'=': // Processor.SetKey(lsSubst, L'X'); break; case L'[': case L'\\': case L']': { wchar_t c = (key_char == L'[') ? 0x1B : (key_char == L'\\') ? 0x1C : 0x1D; szSubst[0] = 0x1B; if (Processor.Mods == xtc_Alt) szSubst[1] = 0x40 + c; else if ((Processor.Mods == (xtc_Ctrl|xtc_Alt)) || (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift))) szSubst[1] = c; else szSubst[0] = c; break; } case L'?': if (!(Processor.Mods & xtc_Alt)) szSubst[0] = (Processor.Mods & xtc_Shift) ? 0x7F : 0x1F; else { szSubst[0] = 0x1B; szSubst[1] = (Processor.Mods & xtc_Shift) ? 0x3F : 0x2F; } break; } if (szSubst[0]) { lsSubst.Set(szSubst); return true; } } } return false; }
bool TermX::GetSubstitute(const MOUSE_EVENT_RECORD& m, TermMouseMode MouseMode, CEStr& lsSubst) { _ASSERTE(lsSubst.IsEmpty()); if (!MouseMode) { lsSubst.Clear(); return false; } wchar_t szSubst[16] = L""; // Deprecated. Mouse events mimic xterm behavior now. #if 0 // http://conemu.github.io/en/VimXterm.html#Vim-scrolling-using-mouse-Wheel // https://github.com/Maximus5/ConEmu/issues/1007 if ((m.dwEventFlags & MOUSE_WHEELED) && (MouseMode & tmm_VIM)) { // If the high word of the dwButtonState member contains // a positive value, the wheel was rotated forward, away from the user. // Otherwise, the wheel was rotated backward, toward the user. short dir = (short)HIWORD(m.dwButtonState); // Ctrl/Alt/Shift DWORD mods = (m.dwControlKeyState & (LEFT_ALT_PRESSED|LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED|RIGHT_CTRL_PRESSED|SHIFT_PRESSED)); if (mods == 0) { if (dir <= 0) wcscpy_c(szSubst, L"\033[62~"); // <MouseDown> else wcscpy_c(szSubst, L"\033[63~"); // <MouseUp> } else if (mods == SHIFT_PRESSED) { if (dir <= 0) wcscpy_c(szSubst, L"\033[64~"); // <S-MouseDown> else wcscpy_c(szSubst, L"\033[65~"); // <S-MouseUp> } else return false; lsSubst.Set(szSubst); return true; } #endif if ((m.dwEventFlags & MOUSE_WHEELED) && (MouseMode & tmm_SCROLL)) { KEY_EVENT_RECORD k = {TRUE, 1}; short dir = (short)HIWORD(m.dwButtonState); DWORD mods = (m.dwControlKeyState & (LEFT_ALT_PRESSED|LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED|RIGHT_CTRL_PRESSED|SHIFT_PRESSED)); UINT nCount = 1; if (mods == 0) { k.wVirtualKeyCode = (dir > 0) ? VK_UP : VK_DOWN; nCount = gpConEmu->mouse.GetWheelScrollLines(); } else if (mods == SHIFT_PRESSED) { k.wVirtualKeyCode = (dir > 0) ? VK_PRIOR : VK_NEXT; } else return false; CEStr lsPart; if (!GetSubstitute(k, lsPart) || lsPart.IsEmpty()) return false; if (nCount > 1) { INT_PTR l = lsPart.GetLen(); wchar_t* ptr = lsSubst.GetBuffer(l*nCount); for (UINT i = 1; i <= nCount; ++i, ptr += l) wcscpy_s(ptr, l+1, lsPart); } else { lsSubst.Attach(lsPart.Detach()); } return true; } if (!(MouseMode & ~(tmm_VIM|tmm_SCROLL))) return false; BYTE NewBtns = (m.dwButtonState & 0x1F); if ((NewBtns != MouseButtons) || ((m.dwEventFlags & MOUSE_WHEELED) && HIWORD(m.dwButtonState)) || ((LastMousePos != m.dwMousePosition) && ((MouseMode & tmm_ANY) || ((MouseMode & tmm_BTN) && NewBtns))) ) { // #XTERM_MOUSE Unfortunately, szSubst is too short to pass "missed" coordinates // Like we do for Far events, MouseMove with RBtn pressed in tmm_ANY|tmm_BTN // modes would send all intermediate coordinates between two events BYTE code; bool released = false; if (NewBtns & FROM_LEFT_1ST_BUTTON_PRESSED) code = 0; // MB1 pressed else if (NewBtns & FROM_LEFT_2ND_BUTTON_PRESSED) code = 1; // MB2 pressed else if (NewBtns & RIGHTMOST_BUTTON_PRESSED) code = 2; // MB3 pressed else if (NewBtns & FROM_LEFT_3RD_BUTTON_PRESSED) code = 64; // MB4 pressed else if (NewBtns & FROM_LEFT_4TH_BUTTON_PRESSED) code = 64 + 1; // MB5 pressed else if (m.dwEventFlags & MOUSE_WHEELED) { // #XTERM_MOUSE Post multiple events if dir contains multiple notches short dir = (short)HIWORD(m.dwButtonState); if (dir > 0) code = 64; // MB4 else if (dir < 0) code = 64 + 1; // MB5 } else { released = true; code = 3; } if (m.dwControlKeyState & SHIFT_PRESSED) code |= 4; if (m.dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) code |= 8; if (m.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) code |= 16; if ((m.dwEventFlags & MOUSE_MOVED) && (MouseMode & (tmm_BTN|tmm_ANY))) code |= 32; // (1,1) is upper left character position SHORT coord[] = {std::max<SHORT>(0, m.dwMousePosition.X) + 1, std::max<SHORT>(0, m.dwMousePosition.Y) + 1}; if (MouseMode & tmm_XTERM) { msprintf(szSubst, countof(szSubst), L"\033[<%u;%u;%u%c", code, coord[0], coord[1], released ? 'm' : 'M'); } else if (MouseMode & tmm_URXVT) { msprintf(szSubst, countof(szSubst), L"\033[%u;%u;%uM", code + 0x20, coord[0], coord[1]); } else { wcscpy_c(szSubst, L"\033[M"); size_t i = wcslen(szSubst); szSubst[i++] = code + 32; // And coords. Must be in "screen" coordinate space for (size_t s = 0; s < 2; ++s) { // (1,1) is upper left character position if (!(MouseMode & tmm_UTF8)) szSubst[i++] = std::min<unsigned>(255, coord[s] + 32); else if (coord[s] < 0x80) szSubst[i++] = coord[s]; else if (coord[s] < 0x800) { // xterm #262: positions from 96 to 2015 are encoded as a two-byte UTF-8 sequence szSubst[i++] = 0xC0 + (coord[s] >> 6); szSubst[i++] = 0x80 + (coord[s] & 0x3F); } else { // #XTERM_MOUSE Xterm reports out-of-range positions as a NUL byte. szSubst[i++] = 1; // It's impossible to post NUL byte ATM } }
bool FileExistsSearch(LPCWSTR asFilePath, CEStr& rsFound, bool abSetPath/*= true*/, bool abRegSearch /*= true*/) { if (!asFilePath || !*asFilePath) { _ASSERTEX(asFilePath && *asFilePath); return false; } if (FileExists(asFilePath)) { return true; } // Развернуть переменные окружения if (wcschr(asFilePath, L'%')) { bool bFound = false; wchar_t* pszExpand = ExpandEnvStr(asFilePath); if (pszExpand && FileExists(pszExpand)) { // asFilePath will be invalid after .Set rsFound.Set(pszExpand); bFound = true; } SafeFree(pszExpand); if (bFound) { return true; } } // Search "Path" if (FileSearchInDir(asFilePath, rsFound)) { return true; } // Только если приложение не нашли "по путям" - пытаемся определить его расположение через [App Paths] // В противном случае, в частности, может быть запущен "far" не из папки с ConEmu, а зарегистрированный // в реестре, если на машине их несколько установлено. #if !defined(CONEMU_MINIMAL) _ASSERTE(gfnSearchAppPaths!=NULL); #endif // В ConEmuHk этот блок не активен, потому что может быть "только" перехват CreateProcess, // а о его параметрах должно заботиться вызывающее (текущее) приложение if (abRegSearch && gfnSearchAppPaths && !wcschr(asFilePath, L'\\')) { // Если в asFilePath НЕ указан путь - искать приложение в реестре, // и там могут быть указаны доп. параметры (пока только добавка в %PATH%) if (gfnSearchAppPaths(asFilePath, rsFound, abSetPath, NULL)) { // Нашли по реестру, возможно обновили %PATH% return true; } } return false; }
int CIconList::CreateTabIconInt(LPCWSTR asIconDescr, bool bAdmin, LPCWSTR asWorkDir) { wchar_t* pszExpanded = ExpandEnvStr(asIconDescr); // Need to be created! int iIconIdx = -1; HICON hFileIcon = NULL; CEStr szLoadFile; LPCWSTR lpszExt = NULL; int nIndex = 0; bool bDirChanged = false; if (!szLoadFile.Set(pszExpanded ? pszExpanded : asIconDescr)) { goto wrap; } lpszExt = ParseIconFileIndex(szLoadFile, nIndex); if (asWorkDir && *asWorkDir) { // Executable (or icon) file may be not availbale by %PATH%, let "cd" to it... bDirChanged = gpConEmu->ChangeWorkDir(asWorkDir); } if (!lpszExt) { if (apiSearchPath(NULL, szLoadFile, L".exe", szLoadFile)) { lpszExt = PointToExt(szLoadFile); } if (!lpszExt) goto wrap; } if (lstrcmpi(lpszExt, L".ico") == 0) { hFileIcon = (HICON)LoadImage(0, szLoadFile, IMAGE_ICON, mn_CxIcon, mn_CyIcon, LR_DEFAULTCOLOR|LR_LOADFROMFILE); } else if ((lstrcmpi(lpszExt, L".exe") == 0) || (lstrcmpi(lpszExt, L".dll") == 0)) { HICON hIconLarge = NULL, hIconSmall = NULL; ExtractIconEx(szLoadFile, nIndex, &hIconLarge, &hIconSmall, 1); bool bUseLargeIcon = ((mn_CxIcon > 16) && (hIconLarge != NULL)) || (hIconSmall == NULL); HICON hDestroyIcon = bUseLargeIcon ? hIconSmall : hIconLarge; if (hDestroyIcon) DestroyIcon(hDestroyIcon); hFileIcon = bUseLargeIcon ? hIconLarge : hIconSmall; } else { //TODO: Shell icons for registered files (cmd, bat, sh, pl, py, ...) } if (hFileIcon) { wchar_t szIconInfo[80] = L"", szMergedInfo[80] = L""; GetIconInfoStr(hFileIcon, szIconInfo); if (gpSetCls->isAdvLogging) { CEStr lsLog(lstrmerge(L"Icon `", asIconDescr, L"` was loaded: ", szIconInfo)); gpConEmu->LogString(lsLog); } int iIconIdxAdm = -1; iIconIdx = ImageList_ReplaceIcon(mh_TabIcons, -1, hFileIcon); TabIconCache NewIcon = {lstrdup(asIconDescr), iIconIdx, false}; m_Icons.push_back(NewIcon); if (mn_AdminIcon >= 0) { HIMAGELIST hAdmList = ImageList_Merge(mh_TabIcons, iIconIdx, mh_TabIcons, mn_AdminIcon+2, 0,0); if (hAdmList) { HICON hNewIcon = ImageList_GetIcon(hAdmList, 0, ILD_TRANSPARENT); if (hNewIcon) { CEStr lsLog(lstrmerge(L"Admin icon `", asIconDescr, L"` was created: ", GetIconInfoStr(hNewIcon, szMergedInfo))); gpConEmu->LogString(lsLog); iIconIdxAdm = ImageList_ReplaceIcon(mh_TabIcons, -1, hNewIcon); DestroyIcon(hNewIcon); TabIconCache AdmIcon = {lstrdup(asIconDescr), iIconIdxAdm, true}; m_Icons.push_back(AdmIcon); if (bAdmin && (iIconIdxAdm > 0)) { iIconIdx = iIconIdxAdm; } } else { gpConEmu->LogString(L"GetIcon for admin icon was failed"); } ImageList_Destroy(hAdmList); } else { gpConEmu->LogString(L"Admin icon merging was failed"); } } DestroyIcon(hFileIcon); } wrap: if (bDirChanged) { gpConEmu->ChangeWorkDir(NULL); } SafeFree(pszExpanded); if (gpSetCls->isAdvLogging && (iIconIdx < 0)) { CEStr lsLog(lstrmerge(L"Icon `", asIconDescr, L"` loading was failed")); gpConEmu->LogString(lsLog); } return iIconIdx; }
INT_PTR CRecreateDlg::OnInitDialog(HWND hDlg, UINT messg, WPARAM wParam, LPARAM lParam) { LRESULT lbRc = FALSE; gpConEmu->OnOurDialogOpened(); CDynDialog::LocalizeDialog(hDlg); // Visual SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)hClassIcon); SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hClassIconSm); // Set password style (avoid "bars" on some OS) SendDlgItemMessage(hDlg, tRunAsPassword, WM_SETFONT, (LPARAM)(HFONT)GetStockObject(DEFAULT_GUI_FONT), 0); // Add menu items HMENU hSysMenu = GetSystemMenu(hDlg, FALSE); InsertMenu(hSysMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, 0); InsertMenu(hSysMenu, 0, MF_BYPOSITION | MF_STRING | MF_ENABLED, ID_RESETCMDHISTORY, L"Clear history..."); InsertMenu(hSysMenu, 0, MF_BYPOSITION | MF_STRING | MF_ENABLED | (gpSet->isSaveCmdHistory ? MF_CHECKED : 0), ID_STORECMDHISTORY, L"Store history"); //#ifdef _DEBUG //SetWindowPos(ghOpWnd, HWND_NOTOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE); //#endif RConStartArgsEx* pArgs = mp_Args; _ASSERTE(pArgs); // Fill command and task drop down SendMessage(hDlg, UM_FILL_CMDLIST, TRUE, 0); // Set text in command and folder fields { LPCWSTR pszSetCmd = mpsz_DefCmd ? mpsz_DefCmd : pArgs->pszSpecialCmd ? pArgs->pszSpecialCmd : L""; CEStr lsTempCmd, lsAppend; if (!mpsz_DefCmd && pArgs) { RConStartArgsEx tempArgs; tempArgs.AssignFrom(pArgs); tempArgs.CleanSecure(); tempArgs.RunAsSystem = pArgs->RunAsSystem; tempArgs.eSplit = RConStartArgsEx::eSplitNone; SafeFree(tempArgs.pszSpecialCmd); SafeFree(tempArgs.pszStartupDir); tempArgs.NewConsole = pArgs->NewConsole; lsAppend = tempArgs.CreateCommandLine(); if (!lsAppend.IsEmpty()) { lsTempCmd = lstrmerge(pszSetCmd, ((lsAppend[0] == L' ') ? NULL : L" "), lsAppend); pszSetCmd = lsTempCmd.ms_Val; } } SetDlgItemText(hDlg, IDC_RESTART_CMD, pszSetCmd); // TODO: gh-959: enable autocorrection of cbRunAsAdmin by IDC_RESTART_CMD task contents (first line) } // "%CD%" was specified as startup dir? In Task parameters for example... CEStr lsStartDir; if (pArgs->pszStartupDir && (lstrcmpi(pArgs->pszStartupDir, L"%CD%") == 0)) { lsStartDir.Set(ms_RConCurDir); } // Suggest default ConEmu working directory otherwise (unless it's a cra_RecreateTab) if (lsStartDir.IsEmpty()) { lsStartDir.Set(gpConEmu->WorkDir()); } // Current directory, startup directory, ConEmu startup directory, and may be startup directory history in the future AddDirectoryList(mpsz_DefDir ? mpsz_DefDir : lsStartDir.ms_Val); AddDirectoryList(ms_RConCurDir); AddDirectoryList(ms_RConStartDir); AddDirectoryList(gpConEmu->WorkDir()); LPCWSTR pszShowDir; if ((pArgs->aRecreate == cra_RecreateTab) && !ms_RConCurDir.IsEmpty()) pszShowDir = ms_RConCurDir; else pszShowDir = mpsz_DefDir ? mpsz_DefDir : lsStartDir.ms_Val; SetDlgItemText(hDlg, IDC_STARTUP_DIR, pszShowDir); // Split controls if (pArgs->aRecreate == cra_RecreateTab) { // Hide Split's ShowWindow(GetDlgItem(hDlg, gbRecreateSplit), SW_HIDE); ShowWindow(GetDlgItem(hDlg, rbRecreateSplitNone), SW_HIDE); ShowWindow(GetDlgItem(hDlg, rbRecreateSplit2Right), SW_HIDE); ShowWindow(GetDlgItem(hDlg, rbRecreateSplit2Bottom), SW_HIDE); ShowWindow(GetDlgItem(hDlg, stRecreateSplit), SW_HIDE); ShowWindow(GetDlgItem(hDlg, tRecreateSplit), SW_HIDE); } else { // Fill splits SetDlgItemInt(hDlg, tRecreateSplit, (1000-pArgs->nSplitValue)/10, FALSE); CheckRadioButton(hDlg, rbRecreateSplitNone, rbRecreateSplit2Bottom, rbRecreateSplitNone+pArgs->eSplit); EnableWindow(GetDlgItem(hDlg, tRecreateSplit), (pArgs->eSplit != pArgs->eSplitNone)); EnableWindow(GetDlgItem(hDlg, stRecreateSplit), (pArgs->eSplit != pArgs->eSplitNone)); } // Спрятать флажок "New window" bool bRunInNewWindow_Hidden = (pArgs->aRecreate == cra_EditTab || pArgs->aRecreate == cra_RecreateTab); ShowWindow(GetDlgItem(hDlg, cbRunInNewWindow), bRunInNewWindow_Hidden ? SW_HIDE : SW_SHOWNORMAL); const wchar_t *pszUser = pArgs->pszUserName; const wchar_t *pszDomain = pArgs->pszDomain; bool bResticted = (pArgs->RunAsRestricted == crb_On); int nChecked = rbCurrentUser; int nNetOnly = cbRunAsNetOnly; DWORD nUserNameLen = countof(ms_CurUser); if (!GetUserName(ms_CurUser, &nUserNameLen)) ms_CurUser[0] = 0; wchar_t szRbCaption[MAX_PATH*3]; lstrcpy(szRbCaption, L"Run as current &user: "******"UPN format" остается в pszUser lstrcpyn(szOtherUser, pszUser, MAX_PATH); wcscat_c(szOtherUser, L"@"); lstrcpyn(szOtherUser+_tcslen(szOtherUser), pszDomain, MAX_PATH); } else { // "Старая" нотация domain\user lstrcpyn(szOtherUser, pszDomain, MAX_PATH); wcscat_c(szOtherUser, L"\\"); lstrcpyn(szOtherUser+_tcslen(szOtherUser), pszUser, MAX_PATH); } } else { lstrcpyn(szOtherUser, pszUser, countof(szOtherUser)); } SetDlgItemText(hDlg, tRunAsPassword, pArgs->szUserPassword); EnableWindow(GetDlgItem(hDlg, cbRunAsNetOnly), TRUE); } } SetDlgItemText(hDlg, tRunAsUser, (nChecked == rbAnotherUser) ? szOtherUser : L""); CheckRadioButton(hDlg, rbCurrentUser, rbAnotherUser, nChecked); RecreateDlgProc(hDlg, UM_USER_CONTROLS, 0, 0); if (gOSVer.dwMajorVersion < 6) { // В XP и ниже это просто RunAs - с возможностью ввода имени пользователя и пароля //apiShowWindow(GetDlgItem(hDlg, cbRunAsAdmin), SW_HIDE); SetDlgItemTextA(hDlg, cbRunAsAdmin, "&Run as..."); //GCC hack. иначе не собирается // И уменьшить длину RECT rcBox; GetWindowRect(GetDlgItem(hDlg, cbRunAsAdmin), &rcBox); SetWindowPos(GetDlgItem(hDlg, cbRunAsAdmin), NULL, 0, 0, (rcBox.right-rcBox.left)/2, rcBox.bottom-rcBox.top, SWP_NOMOVE|SWP_NOZORDER); } else if (gpConEmu->mb_IsUacAdmin || (pArgs && (pArgs->RunAsAdministrator == crb_On))) { CheckDlgButton(hDlg, cbRunAsAdmin, BST_CHECKED); if (gpConEmu->mb_IsUacAdmin) // Только в Vista+ если GUI уже запущен под админом { EnableWindow(GetDlgItem(hDlg, cbRunAsAdmin), FALSE); } else //if (gOSVer.dwMajorVersion < 6) { RecreateDlgProc(hDlg, WM_COMMAND, cbRunAsAdmin, 0); } } //} SetClassLongPtr(hDlg, GCLP_HICON, (LONG_PTR)hClassIcon); if (pArgs->aRecreate == cra_RecreateTab) { SetWindowText(hDlg, CLngRc::getRsrc(lng_DlgRestartConsole/*"Restart console"*/)); SendDlgItemMessage(hDlg, IDC_RESTART_ICON, STM_SETICON, (WPARAM)LoadIcon(NULL,IDI_EXCLAMATION), 0); lbRc = TRUE; } else { SetWindowText(hDlg, CLngRc::getRsrc(lng_DlgCreateNewConsole/*"Create new console"*/)); // If we disallowed to create "Multiple consoles in one window" // - Check & Disable "New window" checkbox bool bForceNewWindow = (!gpSetCls->IsMulti() && gpConEmu->isVConExists(0)); CheckDlgButton(hDlg, cbRunInNewWindow, (pArgs->aRecreate == cra_CreateWindow || bForceNewWindow) ? BST_CHECKED : BST_UNCHECKED); EnableWindow(GetDlgItem(hDlg, cbRunInNewWindow), !bForceNewWindow); // SendDlgItemMessage(hDlg, IDC_RESTART_ICON, STM_SETICON, (WPARAM)LoadIcon(NULL,IDI_QUESTION), 0); POINT pt = {0,0}; MapWindowPoints(GetDlgItem(hDlg, IDC_TERMINATE), hDlg, &pt, 1); DestroyWindow(GetDlgItem(hDlg, IDC_TERMINATE)); SetWindowPos(GetDlgItem(hDlg, IDC_START), NULL, pt.x, pt.y, 0,0, SWP_NOSIZE|SWP_NOZORDER); SetDlgItemText(hDlg, IDC_START, (pArgs->aRecreate == cra_EditTab) ? L"&Save" : L"&Start"); DestroyWindow(GetDlgItem(hDlg, IDC_WARNING)); } // Align "New window" and "Run as administrator" checkboxes { RECT rcBox = {}; GetWindowRect(GetDlgItem(hDlg, cbRunAsAdmin), &rcBox); MapWindowPoints(NULL, hDlg, (LPPOINT)&rcBox, 2); const int chk_height = (rcBox.bottom - rcBox.top); POINT pt = {rcBox.left}; if (!bRunInNewWindow_Hidden) { RECT rcIcoBox = {}; GetWindowRect(GetDlgItem(hDlg, IDC_RESTART_ICON), &rcIcoBox); MapWindowPoints(NULL, hDlg, (LPPOINT)&rcIcoBox, 2); const int ico_height = (rcIcoBox.bottom - rcIcoBox.top); const int h2 = (chk_height * 5) / 2; pt.y = rcIcoBox.top + (ico_height - h2)/2; SetWindowPos(GetDlgItem(hDlg, cbRunInNewWindow), NULL, pt.x, pt.y, 0,0, SWP_NOSIZE|SWP_NOZORDER); pt.y += (h2 - chk_height); } else { RECT rcBtnBox = {}; GetWindowRect(GetDlgItem(hDlg, IDC_START), &rcBtnBox); MapWindowPoints(NULL, hDlg, (LPPOINT)&rcBtnBox, 2); const int btn_height = (rcBtnBox.bottom - rcBtnBox.top); pt.y = rcBtnBox.top + (btn_height - chk_height)/2; } SetWindowPos(GetDlgItem(hDlg, cbRunAsAdmin), NULL, pt.x, pt.y, 0,0, SWP_NOSIZE|SWP_NOZORDER); } // Dpi aware processing at the end of sequence // because we done some manual control reposition if (mp_DpiAware) { mp_DpiAware->Attach(hDlg, ghWnd, CDynDialog::GetDlgClass(hDlg)); } // Ensure, it will be "on screen" RECT rect; GetWindowRect(hDlg, &rect); RECT rcCenter = CenterInParent(rect, mh_Parent); MoveWindow(hDlg, rcCenter.left, rcCenter.top, rect.right - rect.left, rect.bottom - rect.top, false); // Была отключена обработка CConEmuMain::OnFocus (лишние телодвижения) PostMessage(hDlg, (WM_APP+1), 0,0); // Default focus control if (pArgs->aRecreate == cra_RecreateTab) SetFocus(GetDlgItem(hDlg, IDC_START)); // Win+~ (Recreate tab), Focus on "Restart" button" else if ((pArgs->pszUserName && *pArgs->pszUserName) && !*pArgs->szUserPassword) SetFocus(GetDlgItem(hDlg, tRunAsPassword)); // We need password, all other fields are ready else SetFocus(GetDlgItem(hDlg, IDC_RESTART_CMD)); // Set focus in command-line field return lbRc; }