void CConEmuInside::InsideUpdateDir() { CVConGuard VCon; if (mh_InsideParentPath && IsWindow(mh_InsideParentPath) && (gpConEmu->GetActiveVCon(&VCon) >= 0) && VCon->RCon()) { wchar_t szCurText[512] = {}; DWORD_PTR lRc = 0; if (SendMessageTimeout(mh_InsideParentPath, WM_GETTEXT, countof(szCurText), (LPARAM)szCurText, SMTO_ABORTIFHUNG|SMTO_NORMAL, 300, &lRc)) { if (gnOsVer < 0x600) { // Если в заголовке нет полного пути if (wcschr(szCurText, L'\\') == NULL) { // Сразу выходим return; } } LPCWSTR pszPath = NULL; // Если тут уже путь - то префикс не отрезать if ((szCurText[0] == L'\\' && szCurText[1] == L'\\' && szCurText[2]) // сетевой путь || (szCurText[0] && szCurText[1] == L':' && szCurText[2] == L'\\' /*&& szCurText[3]*/)) // Путь через букву диска { pszPath = szCurText; } else { // Иначе - отрезать префикс. На английской винде это "Address: D:\dir1\dir2" pszPath = wcschr(szCurText, L':'); if (pszPath) pszPath = SkipNonPrintable(pszPath+1); } // Если успешно - сравниваем с ms_InsideParentPath if (pszPath && *pszPath && (lstrcmpi(ms_InsideParentPath, pszPath) != 0)) { int nLen = lstrlen(pszPath); if (nLen >= (int)countof(ms_InsideParentPath)) { _ASSERTE((nLen<countof(ms_InsideParentPath)) && "Too long path?"); } else //if (VCon->RCon()) { // Запомнить для сравнения lstrcpyn(ms_InsideParentPath, pszPath, countof(ms_InsideParentPath)); // Подготовить команду для выполнения в Shell VCon->RCon()->PostPromptCmd(true, pszPath); } } } } }
// 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; }
CBackgroundInfo* CBackgroundInfo::CreateBackgroundObject(LPCWSTR inPath, bool abShowErrors) { if (inPath && _tcslen(inPath)>=MAX_PATH) { if (abShowErrors) MBoxA(L"Invalid 'BgImagePath' in CBackgroundInfo::CreateBackgroundObject"); return NULL; } // Допускается и пустой путь! inPath = SkipNonPrintable(inPath); if (!inPath) inPath = L""; CBackgroundInfo* p = NULL; for (INT_PTR i = 0; i < g_Backgrounds.size(); i++) { if (!g_Backgrounds[i]) { _ASSERTE(g_Backgrounds[i]!=NULL); continue; } if (lstrcmpi(g_Backgrounds[i]->BgImage(), inPath) == 0) { p = g_Backgrounds[i]; break; } } if (p) { p->AddRef(); } else { p = new CBackgroundInfo(inPath); if (inPath && *inPath && !p->LoadBackgroundFile(abShowErrors)) { SafeRelease(p); } } return p; }
// Comes from ConEmu's settings (Environment setting page) void CProcessEnvCmd::AddLines(LPCWSTR asLines, bool bPriority) { LPCWSTR pszLines = asLines; CEStr lsLine; INT_PTR nBefore = bPriority ? 0 : -1; while (0 == NextLine(&pszLines, lsLine)) { // Skip empty lines LPCWSTR pszLine = SkipNonPrintable(lsLine); if (!pszLine || !*pszLine) continue; // A comment? if ((pszLine[0] == L'#') || ((pszLine[0] == L'/') && (pszLine[1] == L'/')) || ((pszLine[0] == L'-') && (pszLine[1] == L'-')) || (lstrcmpni(pszLine, L"REM ", 4) == 0) ) continue; // Process this line if (AddCommands(pszLine, NULL, true, nBefore) && bPriority) nBefore++; } }
int CTabBarClass::PrepareTab(CTab& pTab, CVirtualConsole *apVCon) { int iTabIcon = -1; #ifdef _DEBUG if (this != gpConEmu->mp_TabBar) { _ASSERTE(this == gpConEmu->mp_TabBar); } #endif MCHKHEAP // get file name TCHAR dummy[MAX_PATH*2]; TCHAR fileName[MAX_PATH+4]; fileName[0] = 0; TCHAR szFormat[32]; TCHAR szEllip[MAX_PATH+1]; //wchar_t /**tFileName=NULL,*/ *pszNo=NULL, *pszTitle=NULL; int nSplit = 0; int nMaxLen = 0; //gpSet->nTabLenMax - _tcslen(szFormat) + 2/* %s */; int origLength = 0; //_tcslen(tFileName); CRealConsole* pRCon = apVCon ? apVCon->RCon() : NULL; bool bIsFar = pRCon ? pRCon->isFar() : false; // Far 4040 - new "Desktop" window type has "0" index if (apVCon && (pTab->Info.nFarWindowID == 0 || pTab->Type() == fwt_Panels)) { iTabIcon = apVCon->RCon()->GetRootProcessIcon(); } LPCWSTR pszTabName = pRCon->GetTabTitle(pTab); if (pTab->Name.Empty() || (pTab->Type() == fwt_Panels)) { //_tcscpy(szFormat, _T("%s")); lstrcpyn(szFormat, bIsFar ? gpSet->szTabPanels : gpSet->szTabConsole, countof(szFormat)); nMaxLen = gpSet->nTabLenMax - _tcslen(szFormat) + 2/* %s */; lstrcpyn(fileName, pszTabName, countof(fileName)); if (gpSet->pszTabSkipWords && *gpSet->pszTabSkipWords) { StripWords(fileName, gpSet->pszTabSkipWords); } origLength = _tcslen(fileName); //if (origLength>6) { // // Чтобы в заголовке было что-то вроде "{C:\Program Fil...- Far" // // вместо "{C:\Program F...} - Far" // После добавления суффиков к заголовку фара - оно уже влезать не будет в любом случае... Так что если панели - '...' строго ставить в конце // if (lstrcmp(tFileName + origLength - 6, L" - Far") == 0) // nSplit = nMaxLen - 6; //} } else { LPTSTR tFileName = NULL; if (GetFullPathName(pszTabName, countof(dummy), dummy, &tFileName) && tFileName && *tFileName) lstrcpyn(fileName, tFileName, countof(fileName)); else lstrcpyn(fileName, pszTabName, countof(fileName)); if (pTab->Type() == fwt_Editor) { if (pTab->Flags() & fwt_ModifiedFarWnd) lstrcpyn(szFormat, gpSet->szTabEditorModified, countof(szFormat)); else lstrcpyn(szFormat, gpSet->szTabEditor, countof(szFormat)); } else if (pTab->Type() == fwt_Viewer) { lstrcpyn(szFormat, gpSet->szTabViewer, countof(szFormat)); } else { _ASSERTE(FALSE && "Must be processed in previous branch"); lstrcpyn(szFormat, bIsFar ? gpSet->szTabPanels : gpSet->szTabConsole, countof(szFormat)); } } // restrict length if (!nMaxLen) nMaxLen = gpSet->nTabLenMax - _tcslen(szFormat) + 2/* %s */; if (!origLength) origLength = _tcslen(fileName); if (nMaxLen<15) nMaxLen=15; else if (nMaxLen>=MAX_PATH) nMaxLen=MAX_PATH-1; if (origLength > nMaxLen) { /*_tcsnset(fileName, _T('\0'), MAX_PATH); _tcsncat(fileName, tFileName, 10); _tcsncat(fileName, _T("..."), 3); _tcsncat(fileName, tFileName + origLength - 10, 10);*/ //if (!nSplit) // nSplit = nMaxLen*2/3; //// 2009-09-20 Если в заголовке нет расширения (отсутствует точка) //const wchar_t* pszAdmin = gpSet->szAdminTitleSuffix; //const wchar_t* pszFrom = tFileName + origLength - (nMaxLen - nSplit); //if (!wcschr(pszFrom, L'.') && (*pszAdmin && !wcsstr(tFileName, pszAdmin))) //{ // // то троеточие ставить в конец, а не середину // nSplit = nMaxLen; //} // "{C:\Program Files} - Far 2.1283 Administrator x64" // После добавления суффиков к заголовку фара - оно уже влезать не будет в любом случае... Так что если панели - '...' строго ставить в конце nSplit = nMaxLen; _tcsncpy(szEllip, fileName, nSplit); szEllip[nSplit]=0; szEllip[nSplit] = L'\x2026' /*"…"*/; szEllip[nSplit+1] = 0; //_tcscat(szEllip, L"\x2026" /*"…"*/); //_tcscat(szEllip, tFileName + origLength - (nMaxLen - nSplit)); //tFileName = szEllip; lstrcpyn(fileName, szEllip, countof(fileName)); } // szFormat различается для Panel/Viewer(*)/Editor(*) // Пример: "%i-[%s] *" ////pszNo = wcsstr(szFormat, L"%i"); ////pszTitle = wcsstr(szFormat, L"%s"); ////if (pszNo == NULL) //// _wsprintf(fileName, SKIPLEN(countof(fileName)) szFormat, tFileName); ////else if (pszNo < pszTitle || pszTitle == NULL) //// _wsprintf(fileName, SKIPLEN(countof(fileName)) szFormat, pTab->Pos, tFileName); ////else //// _wsprintf(fileName, SKIPLEN(countof(fileName)) szFormat, tFileName, pTab->Pos); //wcscpy(pTab->Name, fileName); const TCHAR* pszFmt = szFormat; TCHAR* pszDst = dummy; TCHAR* pszStart = pszDst; TCHAR* pszEnd = dummy + countof(dummy) - 1; // в конце еще нужно зарезервировать место для '\0' if (!pszFmt || !*pszFmt) { pszFmt = _T("%s"); } *pszDst = 0; bool bRenamedTab = false; if (pTab->Flags() & fwt_Renamed) { if (wcsstr(pszFmt, L"%s") == NULL) { if (wcsstr(pszFmt, L"%n") != NULL) bRenamedTab = true; else pszFmt = _T("%s"); } } TCHAR szTmp[64]; CmdArg szArg; bool bAppendAdmin = gpSet->isAdminSuffix() && (pTab->Flags() & fwt_Elevated); while (*pszFmt && pszDst < pszEnd) { if (*pszFmt == _T('%')) { pszFmt++; LPCTSTR pszText = NULL; switch (*pszFmt) { case _T('s'): case _T('S'): pszText = fileName; break; case _T('i'): case _T('I'): _wsprintf(szTmp, SKIPLEN(countof(szTmp)) _T("%i"), pTab->Info.nIndex); pszText = szTmp; break; case _T('p'): case _T('P'): if (!apVCon || !apVCon->RCon()) { wcscpy_c(szTmp, _T("?")); } else { _wsprintf(szTmp, SKIPLEN(countof(szTmp)) _T("%u"), apVCon->RCon()->GetActivePID()); } pszText = szTmp; break; case _T('c'): case _T('C'): { int iCon = gpConEmu->isVConValid(apVCon); if (iCon > 0) _wsprintf(szTmp, SKIPLEN(countof(szTmp)) _T("%u"), iCon); else wcscpy_c(szTmp, _T("?")); pszText = szTmp; } break; case _T('n'): case _T('N'): { pszText = bRenamedTab ? fileName : pRCon ? pRCon->GetActiveProcessName() : NULL; wcscpy_c(szTmp, (pszText && *pszText) ? pszText : L"?"); pszText = szTmp; } break; case _T('d'): case _T('D'): { pszText = pRCon ? pRCon->GetConsoleCurDir(szArg) : NULL; if (!pszText || !*pszText) pszText = L"?"; } break; case _T('a'): case _T('A'): pszText = bAppendAdmin ? gpSet->szAdminTitleSuffix : NULL; bAppendAdmin = false; break; case _T('%'): pszText = L"%"; break; case 0: pszFmt--; break; } pszFmt++; if (pszText) { if ((*(pszDst-1) == L' ') && (*pszText == L' ')) pszText = SkipNonPrintable(pszText); while (*pszText && pszDst < pszEnd) { *(pszDst++) = *(pszText++); } } } else if ((pszDst > pszStart) && (*(pszDst-1) == L' ') && (*pszFmt == L' ')) { pszFmt++; // Avoid adding sequential spaces (e.g. if some macros was empty) } else { *(pszDst++) = *(pszFmt++); } } // Fin. Append smth else? if (bAppendAdmin) { LPCTSTR pszText = gpSet->szAdminTitleSuffix; if (pszText) { while (*pszText && pszDst < pszEnd) { *(pszDst++) = *(pszText++); } } } *pszDst = 0; #ifdef _DEBUG if (dummy[0] && *(pszDst-1) == L' ') *pszDst = 0; #endif pTab->SetLabel(dummy); MCHKHEAP; return iTabIcon; }
BOOL WINAPI OnReadConsoleW(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, MY_CONSOLE_READCONSOLE_CONTROL* pInputControl) { //typedef BOOL (WINAPI* OnReadConsoleW_t)(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, MY_CONSOLE_READCONSOLE_CONTROL* pInputControl); SUPPRESSORIGINALSHOWCALL; ORIGINAL_KRNL(ReadConsoleW); BOOL lbRc = FALSE; DWORD nErr = GetLastError(); DWORD nStartTick = GetTickCount(), nEndTick = 0; OnReadConsoleStart(true, hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, pInputControl); lbRc = F(ReadConsoleW)(hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, pInputControl); nErr = GetLastError(); // Debug purposes nEndTick = GetTickCount(); // gh#465: Terminate Go input with Ctrl-Z if (lbRc && lpBuffer && lpNumberOfCharsRead && *lpNumberOfCharsRead && (!pInputControl) // Probably, if application pass this structure it really knows what it's doing && (*lpNumberOfCharsRead <= 3)) { // To avoid checking of the mapping, we check result first const wchar_t* pchTest = (const wchar_t*)lpBuffer; if ((pchTest[0] == 26 /* Ctrl-Z / ^Z / (char)('Z' - '@') */) && (((*lpNumberOfCharsRead == 3) && (pchTest[1] == '\r') && (pchTest[2] == '\n')) // Expected variant || ((*lpNumberOfCharsRead == 2) && (pchTest[1] == '\n')) // Possible variant? )) { if (isProcessCtrlZ()) *lpNumberOfCharsRead = 0; } } OnReadConsoleEnd(lbRc, true, hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, pInputControl); // cd \\server\share\dir\... if (gbAllowUncPaths && lpBuffer && lpNumberOfCharsRead && *lpNumberOfCharsRead && (nNumberOfCharsToRead >= *lpNumberOfCharsRead) && (nNumberOfCharsToRead > 6)) { wchar_t* pszCmd = (wchar_t*)lpBuffer; // "cd " ? if ((pszCmd[0]==L'c' || pszCmd[0]==L'C') && (pszCmd[1]==L'd' || pszCmd[1]==L'D') && pszCmd[2] == L' ') { pszCmd[*lpNumberOfCharsRead] = 0; wchar_t* pszPath = (wchar_t*)SkipNonPrintable(pszCmd+3); // Don't worry about local paths, check only network if (pszPath[0] == L'\\' && pszPath[1] == L'\\') { wchar_t* pszEnd; if (*pszPath == L'"') pszEnd = wcschr(++pszPath, L'"'); else pszEnd = wcspbrk(pszPath, L"\r\n\t&| "); if (!pszEnd) pszEnd = pszPath + lstrlen(pszPath); if ((pszEnd - pszPath) < MAX_PATH) { wchar_t ch = *pszEnd; *pszEnd = 0; BOOL bSet = SetCurrentDirectory(pszPath); if (ch) *pszEnd = ch; if (bSet) { if (*pszEnd == L'"') pszEnd++; pszEnd = (wchar_t*)SkipNonPrintable(pszEnd); if (*pszEnd && wcschr(L"&|", *pszEnd)) { while (*pszEnd && wcschr(L"&|", *pszEnd)) pszEnd++; pszEnd = (wchar_t*)SkipNonPrintable(pszEnd); } // Return anything... if (*pszEnd) { int nLeft = lstrlen(pszEnd); memmove(lpBuffer, pszEnd, (nLeft+1)*sizeof(*pszEnd)); } else { lstrcpyn((wchar_t*)lpBuffer, L"cd\r\n", nNumberOfCharsToRead); } *lpNumberOfCharsRead = lstrlen((wchar_t*)lpBuffer); } } } } } SetLastError(nErr); UNREFERENCED_PARAMETER(nStartTick); UNREFERENCED_PARAMETER(nEndTick); return lbRc; }
//------------------------------------------------------------------------ ///| 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; CmdArg szArg, szNext; CEStr szExeName, szExeNameOnly; // Set %ConEmuArgs% env var // It may be useful 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 (!(pszTemp = NextArg(pszTemp, szArg))) { _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 ((pszTemp = NextArg(pszTemp, szArg))) { 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; } } } struct RunAsAdmin { static bool Check(LPCWSTR asSwitch) { bool bRunAsAdmin = false; // isPressed(VK_SHIFT); return bRunAsAdmin; }; }; // Let parse the reset szArg.Empty(); szNext.Empty(); // Processing loop begin if (cmdLineRest && *cmdLineRest) { pszCopyToEnvStart = cmdLineRest; opt.cfgSwitches.Set(pszCopyToEnvStart); while ((cmdLineRest = NextArg(cmdLineRest, szArg, &pszArgStart))) { bool lbNotFound = false; TODO("Replace NeedNextArg with GetCfgParm?") #define NeedNextArg() \ if (!(cmdLineRest = NextArg(cmdLineRest, szNext))) { iResult = CERR_CARGUMENT; goto wrap; } if (!szArg.IsPossibleSwitch()) { // -- // continue; // Try next switch? // Show error on unknown switch psUnknown = pszArgStart; break; } // Main processing cycle { opt.params++; if (szArg.IsSwitch(L"-autosetup")) { BOOL lbTurnOn = TRUE; NeedNextArg(); if (szNext.Compare(L"0") == 0) { lbTurnOn = FALSE; } else if (szNext.Compare(L"1") == 0) { NeedNextArg(); DWORD dwAttr = GetFileAttributes(szNext); if (dwAttr == (DWORD)-1 || (dwAttr & FILE_ATTRIBUTE_DIRECTORY)) { iResult = 102; goto wrap; } } else { iResult = CERR_CARGUMENT; 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 = szNext.GetLen(); 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)); swprintf_c(pszCmd, cchMax/*#SECURELEN*/, L"\"%s\"%s%s%s", szNext.ms_Val, 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 (szArg.OneOfSwitches(L"-bypass", L"-apparent", L"-system:", L"-interactive:", L"-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 ((pszTemp = NextArg(pszTemp, szNext)) && szNext.OneOfSwitches(L"-run",L"-cmd")) { opt.runCommand.Set(pszTemp); } else { opt.runCommand.Set(cmdLineRest); } if (opt.runCommand.IsEmpty()) { CEStr lsMsg(L"Invalid command line. '", szArg, 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 (szArg.OneOfSwitches(L"-demote", L"-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": ", szArg, L" `", opt.runCommand.ms_Val, L"`"); LogString(lsLog); } if (szArg.IsSwitch(L"-demote")) { b = CreateProcessDemoted(opt.runCommand.ms_Val, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, szCurDir, &si, &pi, &nErr); } else if (szArg.IsSwitch(L"-system:")) { DWORD nSessionID = wcstoul(szArg.ms_Val+wcslen(L"-system:"), NULL, 10); b = CreateProcessSystem(nSessionID, opt.runCommand.ms_Val, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, szCurDir, &si, &pi); } else if (szArg.IsSwitch(L"-interactive:")) { DWORD nSessionID = wcstoul(szArg.ms_Val+wcslen(L"-interactive:"), NULL, 10); b = CreateProcessInteractive(nSessionID, 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) swprintf_c(szExtra, L", PID=%u", pi.dwProcessId); lsLog = lstrmerge( L"Process was created successfully", szExtra); } else { swprintf_c(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 (szArg.IsSwitch(L"-multi")) { gpConEmu->AppendExtraArgs(szArg); gpConEmu->opt.MultiConValue = true; } else if (szArg.IsSwitch(L"-NoMulti")) { gpConEmu->AppendExtraArgs(szArg); gpConEmu->opt.MultiConValue = false; } else if (szArg.IsSwitch(L"-visible")) { gpConEmu->opt.VisValue = true; } else if (szArg.OneOfSwitches(L"-ct", L"-cleartype", L"-ct0", L"-ct1", L"-ct2")) { switch (szArg[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 (szArg.IsSwitch(L"-lng")) { NeedNextArg(); if (!gpConEmu->opt.Language.Exists) { gpConEmu->opt.Language = (LPCWSTR)szNext; gpConEmu->AppendExtraArgs(L"-lng", szNext); } } // Optional specific "ConEmu.l10n" else if (szArg.IsSwitch(L"-lngfile")) { NeedNextArg(); if (!gpConEmu->opt.LanguageFile.Exists) { gpConEmu->opt.LanguageFile = (LPCWSTR)szNext; gpConEmu->AppendExtraArgs(L"-lngfile", szNext); } } // Change font name else if (szArg.IsSwitch(L"-Font")) { NeedNextArg(); if (!gpConEmu->opt.FontVal.Exists) { gpConEmu->opt.FontVal = (LPCWSTR)szNext; gpConEmu->AppendExtraArgs(L"-font", szNext); } } // Change font height else if (szArg.IsSwitch(L"-FontSize") || szArg.IsSwitch(L"-Size")) { NeedNextArg(); if (!gpConEmu->opt.SizeVal.Exists) { gpConEmu->opt.SizeVal.SetInt(szNext); } } // ADD fontname; by Mors else if (szArg.IsSwitch(L"-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 (szArg.IsSwitch(L"-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 (szArg.IsSwitch(L"-fs")) { gpConEmu->opt.WindowModeVal = wmFullScreen; } else if (szArg.IsSwitch(L"-max")) { gpConEmu->opt.WindowModeVal = wmMaximized; } else if (szArg.OneOfSwitches(L"-min", L"-MinTSA", L"-StartTSA")) { gpConEmu->WindowStartMinimized = true; if (!szArg.IsSwitch(L"-min")) { gpConEmu->WindowStartTsa = true; gpConEmu->WindowStartNoClose = szArg.IsSwitch(L"-MinTSA"); } } else if (szArg.OneOfSwitches(L"-tsa", L"-tray")) { gpConEmu->ForceMinimizeToTray = true; } else if (szArg.IsSwitch(L"-detached")) { gpConEmu->m_StartDetached = crb_On; opt.Detached = true; } else if (szArg.IsSwitch(L"-NoAutoClose")) { opt.NoAutoClose = true; } else if (szArg.IsSwitch(L"-here")) { gpConEmu->mb_ConEmuHere = true; gpConEmu->StoreWorkDir(); } else if (szArg.IsSwitch(L"-update")) { gpConEmu->opt.AutoUpdateOnStart = true; } else if (szArg.IsSwitch(L"-NoUpdate")) { // This one has more weight than AutoUpdateOnStart gpConEmu->opt.DisableAutoUpdate = true; } else if (szArg.IsSwitch(L"-NoHooksWarn")) { // Don't try to warn users about known problems with third-party detours gpConEmu->opt.NoHooksWarn = true; } else if (szArg.OneOfSwitches(L"-NoKeyHook", L"-NoKeyHooks", L"-NoKeybHook", L"-NoKeybHooks")) { gpConEmu->DisableKeybHooks = true; } else if (szArg.IsSwitch(L"-NoCloseConfirm")) { gpConEmu->DisableCloseConfirm = true; } else if (szArg.IsSwitch(L"-NoMacro")) { gpConEmu->DisableAllMacro = true; } else if (szArg.OneOfSwitches(L"-NoHotkey", L"-NoHotkeys")) { gpConEmu->DisableAllHotkeys = true; } else if (szArg.OneOfSwitches(L"-NoDefTrm", L"-NoDefTerm")) { gpConEmu->DisableSetDefTerm = true; } else if (szArg.OneOfSwitches(L"-NoRegFont", L"-NoRegFonts")) { gpConEmu->DisableRegisterFonts = true; } else if (szArg.OneOfSwitches(L"-inside", L"-inside=")) { bool bRunAsAdmin = RunAsAdmin::Check(szArg.ms_Val); bool bSyncDir = false; LPCWSTR pszSyncFmt = NULL; gpConEmu->mb_ConEmuHere = true; gpConEmu->StoreWorkDir(); // Both `-inside:...` and `-inside=...` are supported if (szArg.IsSwitch(L"-inside=")) { bSyncDir = true; pszSyncFmt = szArg.ms_Val+8; // \eCD /d %1 - \e - ESC, \b - BS, \n - ENTER, %1 - "dir", %2 - "bash dir" } CConEmuInside::InitInside(bRunAsAdmin, bSyncDir, pszSyncFmt, 0, NULL); } else if (szArg.IsSwitch(L"-InsidePID")) { NeedNextArg(); bool bRunAsAdmin = RunAsAdmin::Check(szArg.ms_Val); wchar_t* pszEnd; // Здесь указывается PID, в который нужно внедриться. DWORD nInsideParentPID = wcstol(szNext, &pszEnd, 10); if (nInsideParentPID) { CConEmuInside::InitInside(bRunAsAdmin, false, NULL, nInsideParentPID, NULL); } } else if (szArg.IsSwitch(L"-InsideWnd")) { NeedNextArg(); LPCWSTR pszHWnd = szNext.ms_Val; if (pszHWnd[0] == L'0' && (pszHWnd[1] == L'x' || pszHWnd[1] == L'X')) pszHWnd += 2; else if (pszHWnd[0] == L'x' || pszHWnd[0] == L'X') pszHWnd ++; bool bRunAsAdmin = RunAsAdmin::Check(szArg.ms_Val); wchar_t* pszEnd; // Здесь указывается HWND, в котором нужно создаваться. HWND hParent = (HWND)(DWORD_PTR)wcstoul(pszHWnd, &pszEnd, 16); if (hParent && IsWindow(hParent)) { CConEmuInside::InitInside(bRunAsAdmin, false, NULL, 0, hParent); } } else if (szArg.IsSwitch(L"-icon")) { NeedNextArg(); if (!gpConEmu->opt.IconPrm.Exists && !szNext.IsEmpty()) { gpConEmu->opt.IconPrm = true; gpConEmu->mps_IconPath = ExpandEnvStr(szNext); } } else if (szArg.IsSwitch(L"-dir")) { NeedNextArg(); if (!szNext.IsEmpty()) { // Например, "%USERPROFILE%" CEStr szExpand; if (wcschr(szNext, L'%') && ((szExpand = ExpandEnvStr(szNext)) != NULL)) { gpConEmu->StoreWorkDir(szExpand); } else { gpConEmu->StoreWorkDir(szNext); } } } else if (szArg.IsSwitch(L"-UpdateJumpList")) { // Copy current Task list to Win7 Jump list (Taskbar icon) gpConEmu->mb_UpdateJumpListOnStartup = true; } else if (szArg.OneOfSwitches(L"-log", L"-log0", L"-log1", L"-log2", L"-log3", L"-log4")) { if (szArg.OneOfSwitches(L"-log", L"-log0")) gpConEmu->opt.AdvLogging.SetInt(1); else gpConEmu->opt.AdvLogging.SetInt((BYTE)(szArg[4] - L'0')); // 1..4 // Do create logging service DEBUGSTRSTARTUP(L"Creating log file"); gpConEmu->CreateLog(); } else if (szArg.OneOfSwitches(L"-Single", L"-Reuse")) { // "/reuse" switch to be remastered gpConEmu->AppendExtraArgs(szArg); gpSetCls->SingleInstanceArg = sgl_Enabled; } else if (szArg.IsSwitch(L"-NoSingle")) { gpConEmu->AppendExtraArgs(szArg); gpSetCls->SingleInstanceArg = sgl_Disabled; } else if (szArg.IsSwitch(L"-DesktopMode")) { gpConEmu->opt.DesktopMode = true; } else if (szArg.OneOfSwitches(L"-Quake", L"-QuakeAuto", L"-NoQuake")) { if (szArg.IsSwitch(L"-Quake")) gpConEmu->opt.QuakeMode = 1; else if (szArg.IsSwitch(L"-QuakeAuto")) gpConEmu->opt.QuakeMode = 2; else { gpConEmu->opt.QuakeMode = 0; if (gpSetCls->SingleInstanceArg == sgl_Default) gpSetCls->SingleInstanceArg = sgl_Disabled; } } else if (szArg.OneOfSwitches(L"-FrameWidth", L"-Frame")) { NeedNextArg(); if (!gpConEmu->opt.FrameWidth.Exists) gpConEmu->opt.FrameWidth.SetInt(szNext); } else if (szArg.OneOfSwitches(L"-ShowHide", L"-ShowHideTSA")) { gpSetCls->SingleInstanceArg = sgl_Enabled; gpSetCls->SingleInstanceShowHide = szArg.IsSwitch(L"-ShowHide") ? sih_ShowMinimize : sih_ShowHideTSA; } else if (szArg.OneOfSwitches(L"-Reset", L"-ResetDefault", L"-Basic")) { gpConEmu->opt.ResetSettings = true; if (szArg.IsSwitch(L"-ResetDefault")) { gpSetCls->isFastSetupDisabled = true; } else if (szArg.IsSwitch(L"-Basic")) { gpSetCls->isFastSetupDisabled = true; gpSetCls->isResetBasicSettings = true; } } else if (szArg.OneOfSwitches(L"-NoCascade", L"-DontCascade")) { gpConEmu->AppendExtraArgs(szArg); gpSetCls->isDontCascade = true; } else if (szArg.OneOfSwitches(L"-WndX", L"-WndY", L"-WndW", L"-WndWidth", L"-WndH", L"-WndHeight")) { wchar_t ch = szArg[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 (szArg.IsSwitch(L"-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 (szArg.IsSwitch(L"-Theme")) { const wchar_t* kDefaultTheme = L"DarkMode_Explorer"; bool bParm = false; if (!cmdLineRest || (*cmdLineRest == L'-' || *cmdLineRest == L'/') || !GetCfgParm(cmdLineRest, bParm, gpConEmu->opt.WindowTheme, 128)) { gpConEmu->opt.WindowTheme.SetStr(kDefaultTheme); } } else if (szArg.OneOfSwitches(L"-Buffer", L"-BufferHeight")) { NeedNextArg(); if (!gpConEmu->opt.BufferHeightVal.Exists) { gpConEmu->opt.BufferHeightVal.SetInt(szNext); 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 (szArg.IsSwitch(L"-Config")) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.ConfigVal, 127)) { goto wrap; } } else if (szArg.IsSwitch(L"-Palette")) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.PaletteVal, MAX_PATH)) { goto wrap; } } else if (szArg.IsSwitch(L"-LoadRegistry")) { gpConEmu->AppendExtraArgs(szArg); gpConEmu->opt.ForceUseRegistryPrm = true; } else if (szArg.OneOfSwitches(L"-LoadCfgFile", L"-LoadXmlFile")) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.LoadCfgFile, MAX_PATH, true)) { goto wrap; } } else if (szArg.OneOfSwitches(L"-SaveCfgFile", L"-SaveXmlFile")) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.SaveCfgFile, MAX_PATH, true)) { goto wrap; } } else if (szArg.IsSwitch(L"-GuiMacro")) { // -- выполняется только последний if (!GetCfgParm(cmdLineRest, gpConEmu->opt.ExecGuiMacro, 0x8000, false)) { goto wrap; } } else if (szArg.IsSwitch(L"-UpdateSrcSet")) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.UpdateSrcSet, MAX_PATH*4, false)) { goto wrap; } } else if (szArg.IsSwitch(L"-AnsiLog")) { // -- используем последний из параметров, если их несколько if (!GetCfgParm(cmdLineRest, gpConEmu->opt.AnsiLogPath, MAX_PATH-40, true)) { goto wrap; } } else if (szArg.IsSwitch(L"-SetDefTerm")) { gpConEmu->opt.SetUpDefaultTerminal = true; } else if (szArg.IsSwitch(L"-ZoneId")) { gpConEmu->opt.FixZoneId = true; } else if (szArg.IsSwitch(L"-Exit")) { gpConEmu->opt.ExitAfterActionPrm = true; } else if (szArg.IsSwitch(L"-QuitOnClose")) { gpConEmu->mb_ForceQuitOnClose = true; } else if (szArg.IsSwitch(L"-Title")) { bool bOk = false; CESwitch pszTitle(sw_Str); if (!GetCfgParm(cmdLineRest, bOk, pszTitle, 127)) { goto wrap; } gpConEmu->SetTitleTemplate(pszTitle.GetStr()); } else if (szArg.IsSwitch(L"-Settings")) { gpConEmu->mb_SettingsRequested = true; } else if (szArg.IsSwitch(L"-FindBugMode")) { gpConEmu->mb_FindBugMode = true; } else if (szArg.OneOfSwitches(L"-debug", L"-debugw", L"-debugi")) { // These switches were already processed } else if (szArg.OneOfSwitches(L"-?", L"-h", L"-help")) { if (gpLng) gpLng->Reload(); ConEmuAbout::OnInfo_About(); iResult = -1; goto wrap; } // Final `-run ...` or `-runlist ...` (old names `-cmd ...` or `-cmdlist ...`) else if ( szArg.OneOfSwitches(L"-run", L"-runlist", L"-cmd", L"-cmdlist") ) { if (opt.cfgSwitches.ms_Val) { _ASSERTE(pszArgStart>=pszCopyToEnvStart); // If there is only "-run cmd" in arguments _ASSERTE((INT_PTR)(pszArgStart - pszCopyToEnvStart) <= opt.cfgSwitches.GetLen()); opt.cfgSwitches.ms_Val[pszArgStart - pszCopyToEnvStart] = 0; } opt.runCommand.Set(SkipNonPrintable(cmdLineRest)); opt.isScript = szArg.OneOfSwitches(L"-runlist", L"-cmdlist"); break; } else { // Show error on unknown switch psUnknown = pszArgStart; break; } } // Main processing cycle end // Avoid assertions in NextArg szArg.Empty(); szNext.Empty(); } // while (NextArg(&cmdLineRest, szArg, &pszArgStart) == 0) }
// 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; }
// Called from OnShellExecCmdLine HRESULT OurShellExecCmdLine(HWND hwnd, LPCWSTR pwszCommand, LPCWSTR pwszStartDir, bool bRunAsAdmin, bool bForce) { HRESULT hr = E_UNEXPECTED; BOOL bShell = FALSE; CEStr lsLog = lstrmerge(L"OnShellExecCmdLine", bRunAsAdmin ? L"(RunAs): " : L": ", pwszCommand); DefTermLogString(lsLog); // Bad thing, ShellExecuteEx needs File&Parm, but we get both in pwszCommand CmdArg szExe; LPCWSTR pszFile = pwszCommand; LPCWSTR pszParm = pwszCommand; if (NextArg(&pszParm, szExe) == 0) { pszFile = szExe; pszParm = SkipNonPrintable(pszParm); } else { // Failed pszFile = pwszCommand; pszParm = NULL; } if (!bForce) { DWORD nCheckSybsystem1 = 0, nCheckBits1 = 0; if (!FindImageSubsystem(pszFile, nCheckSybsystem1, nCheckBits1)) { hr = (HRESULT)-1; DefTermLogString(L"OnShellExecCmdLine: FindImageSubsystem failed"); goto wrap; } if (nCheckSybsystem1 != IMAGE_SUBSYSTEM_WINDOWS_CUI) { hr = (HRESULT)-1; DefTermLogString(L"OnShellExecCmdLine: !=IMAGE_SUBSYSTEM_WINDOWS_CUI"); goto wrap; } } // "Run as admin" was requested? if (bRunAsAdmin) { SHELLEXECUTEINFO sei = {sizeof(sei), 0, hwnd, L"runas", pszFile, pszParm, pwszStartDir, SW_SHOWNORMAL}; bShell = OnShellExecuteExW(&sei); } else { wchar_t* pwCommand = lstrdup(pwszCommand); DWORD nCreateFlags = CREATE_NEW_CONSOLE|CREATE_UNICODE_ENVIRONMENT|CREATE_DEFAULT_ERROR_MODE; STARTUPINFO si = {sizeof(si)}; PROCESS_INFORMATION pi = {}; bShell = OnCreateProcessW(NULL, pwCommand, NULL, NULL, FALSE, nCreateFlags, NULL, pwszStartDir, &si, &pi); if (bShell) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } } hr = bShell ? S_OK : HRESULT_FROM_WIN32(GetLastError()); wrap: return hr; }
BOOL WINAPI OnReadConsoleW(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, MY_CONSOLE_READCONSOLE_CONTROL* pInputControl) { //typedef BOOL (WINAPI* OnReadConsoleW_t)(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, MY_CONSOLE_READCONSOLE_CONTROL* pInputControl); SUPPRESSORIGINALSHOWCALL; ORIGINAL_KRNL(ReadConsoleW); BOOL lbRc = FALSE; DWORD nErr = GetLastError(); DWORD nStartTick = GetTickCount(), nEndTick = 0; OnReadConsoleStart(true, hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, pInputControl); lbRc = F(ReadConsoleW)(hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, pInputControl); nErr = GetLastError(); // Debug purposes nEndTick = GetTickCount(); OnReadConsoleEnd(lbRc, true, hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, pInputControl); // cd \\server\share\dir\... if (gbAllowUncPaths && lpBuffer && lpNumberOfCharsRead && *lpNumberOfCharsRead && (nNumberOfCharsToRead >= *lpNumberOfCharsRead) && (nNumberOfCharsToRead > 6)) { wchar_t* pszCmd = (wchar_t*)lpBuffer; // "cd " ? if ((pszCmd[0]==L'c' || pszCmd[0]==L'C') && (pszCmd[1]==L'd' || pszCmd[1]==L'D') && pszCmd[2] == L' ') { pszCmd[*lpNumberOfCharsRead] = 0; wchar_t* pszPath = (wchar_t*)SkipNonPrintable(pszCmd+3); // Don't worry about local paths, check only network if (pszPath[0] == L'\\' && pszPath[1] == L'\\') { wchar_t* pszEnd; if (*pszPath == L'"') pszEnd = wcschr(++pszPath, L'"'); else pszEnd = wcspbrk(pszPath, L"\r\n\t&| "); if (!pszEnd) pszEnd = pszPath + lstrlen(pszPath); if ((pszEnd - pszPath) < MAX_PATH) { wchar_t ch = *pszEnd; *pszEnd = 0; BOOL bSet = SetCurrentDirectory(pszPath); if (ch) *pszEnd = ch; if (bSet) { if (*pszEnd == L'"') pszEnd++; pszEnd = (wchar_t*)SkipNonPrintable(pszEnd); if (*pszEnd && wcschr(L"&|", *pszEnd)) { while (*pszEnd && wcschr(L"&|", *pszEnd)) pszEnd++; pszEnd = (wchar_t*)SkipNonPrintable(pszEnd); } // Return anything... if (*pszEnd) { int nLeft = lstrlen(pszEnd); memmove(lpBuffer, pszEnd, (nLeft+1)*sizeof(*pszEnd)); } else { lstrcpyn((wchar_t*)lpBuffer, L"cd\r\n", nNumberOfCharsToRead); } *lpNumberOfCharsRead = lstrlen((wchar_t*)lpBuffer); } } } } } SetLastError(nErr); UNREFERENCED_PARAMETER(nStartTick); UNREFERENCED_PARAMETER(nEndTick); return lbRc; }
// Return true if "SetEnvironmentVariable" was processed // if (bDoSet==false) - just skip all "set" commands // Supported commands: // set abc=val // "set PATH=C:\Program Files;%PATH%" // chcp [utf8|ansi|oem|<cp_no>] // title "Console init title" bool ProcessSetEnvCmd(LPCWSTR& asCmdLine, bool bDoSet, CmdArg* rpsTitle /*= NULL*/) { LPCWSTR lsCmdLine = asCmdLine; bool bEnvChanged = false; CmdArg lsSet, lsAmp; // Example: "set PATH=C:\Program Files;%PATH%" & set abc=def & cmd while (NextArg(&lsCmdLine, lsSet) == 0) { bool bTokenOk = false; wchar_t* lsNameVal = NULL; // It may contains only "set" if was not quoted if (lstrcmpi(lsSet, L"set") == 0) { // Now we shell get in lsSet "abc=def" token if ((NextArg(&lsCmdLine, lsSet) == 0) && (wcschr(lsSet, L'=') > lsSet.ms_Arg)) { lsNameVal = lsSet.ms_Arg; } } // Or full "set PATH=C:\Program Files;%PATH%" command (without quotes ATM) else if (lstrcmpni(lsSet, L"set ", 4) == 0) { LPCWSTR psz = SkipNonPrintable(lsSet.ms_Arg+4); if (wcschr(psz, L'=') > psz) { lsNameVal = (wchar_t*)psz; } } // Process "chcp <cp>" too else if (lstrcmpi(lsSet, L"chcp") == 0) { if (NextArg(&lsCmdLine, lsSet) == 0) { UINT nCP = GetCpFromString(lsSet); if (nCP > 0 && nCP <= 0xFFFF) { bTokenOk = true; _ASSERTE(lsNameVal == NULL); // Ask to be changed? if (bDoSet) { //Issue 60: BUGBUG: На некоторых системых (Win2k3, WinXP) SetConsoleCP (и иже с ними) просто зависают DWORD nTID; HANDLE hThread = CreateThread(NULL, 0, OurSetConsoleCPThread, (LPVOID)nCP, 0, &nTID); if (hThread) { DWORD nWait = WaitForSingleObject(hThread, 1000); if (nWait == WAIT_TIMEOUT) { TerminateThread(hThread,100); } CloseHandle(hThread); } } } } } // Change title without need of cmd.exe else if (lstrcmpi(lsSet, L"title") == 0) { if (NextArg(&lsCmdLine, lsSet) == 0) { bTokenOk = true; _ASSERTE(lsNameVal == NULL); // Ask to be changed? if (rpsTitle) rpsTitle->Set(lsSet); } } // Well, known command was detected. What is next? if (lsNameVal || bTokenOk) { lsAmp.GetPosFrom(lsSet); if (NextArg(&lsCmdLine, lsAmp) != 0) { // End of command? Use may call only "set" without following app? Run simple "cmd" in that case _ASSERTE(lsCmdLine!=NULL && *lsCmdLine==0); bTokenOk = true; // And process SetEnvironmentVariable } else { if (lstrcmp(lsAmp, L"&") == 0) { // Only simple conveyer is supported! bTokenOk = true; // And process SetEnvironmentVariable } // Update last pointer (debug and asserts purposes) lsSet.GetPosFrom(lsAmp); } } if (!bTokenOk) { break; // Stop processing command line } else if (lsNameVal) { // And split name/value _ASSERTE(lsNameVal!=NULL); wchar_t* pszEq = wcschr(lsNameVal, L'='); if (!pszEq) { _ASSERTE(pszEq!=NULL); break; } if (bDoSet) { *(pszEq++) = 0; // Expand value wchar_t* pszExpanded = ExpandEnvStr(pszEq); LPCWSTR pszSet = pszExpanded ? pszExpanded : pszEq; SetEnvironmentVariable(lsNameVal, (pszSet && *pszSet) ? pszSet : NULL); SafeFree(pszExpanded); } bEnvChanged = true; } // Remember processed position asCmdLine = lsCmdLine; } // end of "while (NextArg(&lsCmdLine, lsSet) == 0)" // Fin if (!asCmdLine || !*asCmdLine) { static wchar_t szSimple[] = L"cmd"; asCmdLine = szSimple; } return bEnvChanged; }
// Load current value of "HKCU\Software\Microsoft\Command Processor" : "AutoRun" // (bClear==true) - remove from it our "... Cmd_Autorun.cmd ..." part wchar_t* CSetPgComspec::LoadAutorunValue(HKEY hkCmd, bool bClear) { size_t cchCmdMax = 65535; wchar_t *pszCmd = (wchar_t*)malloc(cchCmdMax*sizeof(*pszCmd)); if (!pszCmd) { _ASSERTE(pszCmd!=NULL); return NULL; } _ASSERTE(hkCmd!=NULL); //HKEY hkCmd = NULL; //if (0 == RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Command Processor", 0, KEY_READ, &hkCmd)) DWORD cbMax = (cchCmdMax-2) * sizeof(*pszCmd); if (0 == RegQueryValueEx(hkCmd, L"AutoRun", NULL, NULL, (LPBYTE)pszCmd, &cbMax)) { pszCmd[cbMax>>1] = 0; if (bClear && *pszCmd) { // Просили почистить от "... Cmd_Autorun.cmd ..." wchar_t* pszFind = StrStrI(pszCmd, L"\\ConEmu\\Cmd_Autorun.cmd"); if (pszFind) { // "... Cmd_Autorun.cmd ..." found, need to find possible start and end of our part ('&' separated) wchar_t* pszStart = pszFind; while ((pszStart > pszCmd) && (*(pszStart-1) != L'&')) pszStart--; const wchar_t* pszEnd = wcschr(pszFind, L'&'); if (!pszEnd) { pszEnd = pszFind + _tcslen(pszFind); } else { while (*pszEnd == L'&') pszEnd++; } // Ok, There are another commands? if ((pszStart > pszCmd) || *pszEnd) { // Possibilities if (!*pszEnd) { // app1.exe && Cmd_Autorun.cmd while ((pszStart > pszCmd) && ((*(pszStart-1) == L'&') || (*(pszStart-1) == L' '))) pszStart--; _ASSERTE(pszStart > pszCmd); // Command to left is empty? *pszStart = 0; // just trim } else { // app1.exe && Cmd_Autorun.cmd & app2.exe // app1.exe & Cmd_Autorun.cmd && app2.exe // Cmd_Autorun.cmd & app2.exe if (pszStart == pszCmd) { pszEnd = SkipNonPrintable(pszEnd); } size_t cchLeft = _tcslen(pszEnd)+1; // move command (from right) to the 'Cmd_Autorun.cmd' place memmove(pszStart, pszEnd, cchLeft*sizeof(wchar_t)); } } else { // No, we are alone *pszCmd = 0; } } } // Skip spaces? LPCWSTR pszChar = SkipNonPrintable(pszCmd); if (!pszChar || !*pszChar) { *pszCmd = 0; } }
//------------------------------------------------------------------------ ///| 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; }
void CSetPgIntegr::RegisterShell(LPCWSTR asName, LPCWSTR asMode, LPCWSTR asConfig, LPCWSTR asCmd, LPCWSTR asIcon) { if (!asName || !*asName) asName = L"ConEmu"; if (!asCmd || !*asCmd) asCmd = CONEMU_HERE_CMD; asCmd = SkipNonPrintable(asCmd); #ifdef _DEBUG CEStr szMode(asMode); _ASSERTE(szMode.IsSwitch(L"-here") || szMode.IsSwitch(L"-inside") || szMode.IsSwitch(L"-inside:")); #endif CEStr lsExta; LPCWSTR pszExtraArgs = gpConEmu->MakeConEmuStartArgs(lsExta, asConfig); size_t cchMax = _tcslen(gpConEmu->ms_ConEmuExe) + (asMode ? (_tcslen(asMode) + 3) : 0) + (pszExtraArgs ? (_tcslen(pszExtraArgs) + 1) : 0) + _tcslen(asCmd) + 32; wchar_t* pszCmd = (wchar_t*)malloc(cchMax*sizeof(*pszCmd)); if (!pszCmd) return; //[HKEY_CURRENT_USER\Software\Classes\*\shell\ConEmu inside] //"Icon"="C:\\Program Files\\ConEmu\\ConEmu.exe,1" //[HKEY_CURRENT_USER\Software\Classes\*\shell\ConEmu inside\command] //@="C:\\Program Files\\ConEmu\\ConEmu.exe /inside /config shell /cmd {powershell} -cur_console:n" //[HKEY_CURRENT_USER\Software\Classes\Directory\Background\shell\ConEmu inside] //"Icon"="C:\\Program Files\\ConEmu\\ConEmu.exe,1" //[HKEY_CURRENT_USER\Software\Classes\Directory\Background\shell\ConEmu inside\command] //@="C:\\Program Files\\ConEmu\\ConEmu.exe /inside /config shell /cmd {powershell} -cur_console:n" //[HKEY_CURRENT_USER\Software\Classes\Directory\shell\ConEmu inside] //"Icon"="C:\\Program Files\\ConEmu\\ConEmu.exe,1" //[HKEY_CURRENT_USER\Software\Classes\Directory\shell\ConEmu inside\command] //@="C:\\Program Files\\ConEmu\\ConEmu.exe /inside /config shell /dir \"%1\" /cmd {powershell} -cur_console:n" //[HKEY_CURRENT_USER\Software\Classes\Drive\shell\ConEmu inside] //"Icon"="C:\\Program Files\\ConEmu\\ConEmu.exe,1" //[HKEY_CURRENT_USER\Software\Classes\Drive\shell\ConEmu inside\command] //@="C:\\Program Files\\ConEmu\\ConEmu.exe /inside /config shell /dir \"%1\" /cmd {powershell} -cur_console:n" int iSucceeded = 0; bool bHasLibraries = IsWindows7; for (int i = 1; i <= 6; i++) { _wcscpy_c(pszCmd, cchMax, L"\""); _wcscat_c(pszCmd, cchMax, gpConEmu->ms_ConEmuExe); _wcscat_c(pszCmd, cchMax, L"\" "); // `-here`, `-inside` or `-inside:cd ...` if (asMode && *asMode) { bool bQ = IsQuotationNeeded(asMode); if (bQ) _wcscat_c(pszCmd, cchMax, L"\""); _wcscat_c(pszCmd, cchMax, asMode); _wcscat_c(pszCmd, cchMax, bQ ? L"\" " : L" "); } // -FontDir, -LoadCfgFile, -Config, etc. if (pszExtraArgs && *pszExtraArgs) { _wcscat_c(pszCmd, cchMax, pszExtraArgs); _wcscat_c(pszCmd, cchMax, L" "); } LPCWSTR pszRoot = NULL; switch (i) { case 1: pszRoot = L"Software\\Classes\\*\\shell"; break; case 2: pszRoot = L"Software\\Classes\\Directory\\Background\\shell"; break; case 3: if (!bHasLibraries) continue; pszRoot = L"Software\\Classes\\LibraryFolder\\Background\\shell"; break; case 4: pszRoot = L"Software\\Classes\\Directory\\shell"; _wcscat_c(pszCmd, cchMax, L"-dir \"%1\" "); break; case 5: pszRoot = L"Software\\Classes\\Drive\\shell"; _wcscat_c(pszCmd, cchMax, L"-dir \"%1\" "); break; case 6: // Issue 1191: ConEmu was launched instead of explorer from taskbar pinned library icon continue; //if (!bHasLibraries) // continue; //pszRoot = L"Software\\Classes\\LibraryFolder\\shell"; //_wcscat_c(pszCmd, cchMax, L"-dir \"%1\" "); //break; } bool bCmdKeyExist = false; if (*asCmd == L'/') { CEStr lsArg; LPCWSTR pszTemp = asCmd; while (0 == NextArg(&pszTemp, lsArg)) { if (lsArg.OneOfSwitches(L"-run",L"-runlist",L"-cmd",L"-cmdlist")) { bCmdKeyExist = true; break; } } } if (!bCmdKeyExist) _wcscat_c(pszCmd, cchMax, L"-run "); _wcscat_c(pszCmd, cchMax, asCmd); HKEY hkRoot; if (0 == RegCreateKeyEx(HKEY_CURRENT_USER, pszRoot, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkRoot, NULL)) { HKEY hkConEmu; if (0 == RegCreateKeyEx(hkRoot, asName, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkConEmu, NULL)) { // Если задана "иконка" if (asIcon) RegSetValueEx(hkConEmu, L"Icon", 0, REG_SZ, (LPBYTE)asIcon, (lstrlen(asIcon)+1)*sizeof(*asIcon)); else RegDeleteValue(hkConEmu, L"Icon"); // Команда HKEY hkCmd; if (0 == RegCreateKeyEx(hkConEmu, L"command", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkCmd, NULL)) { if (0 == RegSetValueEx(hkCmd, NULL, 0, REG_SZ, (LPBYTE)pszCmd, (lstrlen(pszCmd)+1)*sizeof(*pszCmd))) iSucceeded++; RegCloseKey(hkCmd); } RegCloseKey(hkConEmu); } RegCloseKey(hkRoot); } } free(pszCmd); }
// May comes from Task or ConEmu's -run switch // or from Setting\Environment page where one line is a single command (bAlone == true) bool CProcessEnvCmd::AddCommands(LPCWSTR asCommands, LPCWSTR* ppszEnd/*= NULL*/, bool bAlone /*= false*/, INT_PTR anBefore /*= -1*/) { bool bNew = false; LPCWSTR lsCmdLine = asCommands; CEStr lsSet, lsAmp, lsCmd; if (ppszEnd) *ppszEnd = asCommands; // Example: "set PATH=C:\Program Files;%PATH%" & set abc=def & cmd while (NextArg(&lsCmdLine, lsSet) == 0) { bool bTokenOk = false; wchar_t* lsNameVal = NULL; // It may contains only "set" or "alias" if was not quoted if ((lstrcmpi(lsSet, L"set") == 0) || (lstrcmpi(lsSet, L"alias") == 0)) { lsCmd.Set(lsSet); _ASSERTE(*lsCmdLine != L' '); // Now we shell get in lsSet "abc=def" token // Or to simplify usage, the rest of line is supported too, // so user may type in our Settings\Environment: // set V1=From Settings // instead of // set "V1=From Settings" bool bProcessed = false; if ((*lsCmdLine != L'"') || bAlone) { LPCWSTR pszAmp = bAlone ? NULL : wcschr(lsCmdLine, L'&'); if (!pszAmp) // No ampersand or bAlone? Use var value as the rest of line pszAmp = lsCmdLine + lstrlen(lsCmdLine); // Set tail pointer LPCWSTR pszValEnd = pszAmp; // Trim trailing spaces (only \x20) while ((pszValEnd > lsCmdLine) && (*(pszValEnd-1) == L' ')) pszValEnd--; // Trim possible leading/trailing quotes if (bAlone && (*lsCmdLine == L'"')) { lsCmdLine++; if (((pszValEnd-1) > lsCmdLine) && (*(pszValEnd-1) == L'"')) { _ASSERTE(*pszValEnd == 0); pszValEnd--; } } // OK, return it lsSet.Empty(); // to avoid debug asserts lsSet.Set(lsCmdLine, pszValEnd - lsCmdLine); lsCmdLine = SkipNonPrintable(pszAmp); // Leave possible '&' at pointer bProcessed = true; } // OK, lets get token like "name=var value" if (!bProcessed) { bProcessed = (NextArg(&lsCmdLine, lsSet) == 0); } if (bProcessed && (wcschr(lsSet, L'=') > lsSet.ms_Val)) { lsNameVal = lsSet.ms_Val; } } // Or full "set PATH=C:\Program Files;%PATH%" command (without quotes ATM) else if (lstrcmpni(lsSet, L"set ", 4) == 0) { lsCmd = L"set"; LPCWSTR psz = SkipNonPrintable(lsSet.ms_Val+4); if (wcschr(psz, L'=') > psz) { lsNameVal = (wchar_t*)psz; } } // Support "alias token=value" too else if (lstrcmpni(lsSet, L"alias ", 6) == 0) { lsCmd = L"alias"; LPCWSTR psz = SkipNonPrintable(lsSet.ms_Val+6); if (wcschr(psz, L'=') > psz) { lsNameVal = (wchar_t*)psz; } } // Process "chcp <cp>" too else if (lstrcmpi(lsSet, L"chcp") == 0) { lsCmd = L"chcp"; if (NextArg(&lsCmdLine, lsSet) == 0) { UINT nCP = GetCpFromString(lsSet); if (nCP > 0 && nCP <= 0xFFFF) { bTokenOk = true; _ASSERTE(lsNameVal == NULL); if (mp_CmdChCp) { SafeFree(mp_CmdChCp->pszName); mp_CmdChCp->pszName = lstrdup(lsSet); } else { bNew |= (NULL != Add(lsCmd, lsSet, NULL, anBefore)); } } } } // Change title without need of cmd.exe else if (lstrcmpi(lsSet, L"title") == 0) { lsCmd = L"title"; if (NextArg(&lsCmdLine, lsSet) == 0) { bTokenOk = true; _ASSERTE(lsNameVal == NULL); if (mp_CmdTitle) { SafeFree(mp_CmdTitle->pszName); mp_CmdTitle->pszName = lstrdup(lsSet); } else { bNew |= (NULL != Add(lsCmd, lsSet, NULL, anBefore)); } } } // Echo the "text" before console starts // Type the "text file" before console starts else if ((lstrcmpi(lsSet, L"echo") == 0) || (lstrcmpi(lsSet, L"type") == 0)) { lsCmd.Set(lsSet); // echo [-r] [-n] [-x] [-b] "String to echo" // type [-b] [-CP] "Path to text file to echo" CEStr lsSwitches; while (*lsCmdLine == L'-') { if (NextArg(&lsCmdLine, lsSet) != 0) break; lstrmerge(&lsSwitches.ms_Val, lsSwitches.IsEmpty() ? NULL : L" ", lsSet.ms_Val); } // Rest arguments are expected to be processed text or file CEStr lsAdd; while (NextArg(&lsCmdLine, lsSet) == 0) { bTokenOk = true; lstrmerge(&lsAdd.ms_Val, lsAdd.IsEmpty() ? NULL : L" ", lsSet.mb_Quoted ? L"\"" : NULL, lsSet.ms_Val, lsSet.mb_Quoted ? L"\"" : NULL); lsCmdLine = SkipNonPrintable(lsCmdLine); if (!*lsCmdLine || (*lsCmdLine == L'&') || (*lsCmdLine == L'|')) break; } if (!lsAdd.IsEmpty()) { bNew |= (NULL != Add(lsCmd, lsSwitches, lsAdd, anBefore)); } } else { lsCmd.Empty(); } // Well, known command was detected. What is next? if (lsNameVal || bTokenOk) { lsAmp.GetPosFrom(lsSet); if (NextArg(&lsCmdLine, lsAmp) != 0) { // End of command? Use may call only "set" without following app? Run simple "cmd" in that case _ASSERTE(lsCmdLine!=NULL && *lsCmdLine==0); bTokenOk = true; // And process SetEnvironmentVariable } else { if (lstrcmp(lsAmp, L"&") == 0) { // Only simple conveyer is supported! bTokenOk = true; // And process SetEnvironmentVariable } // Update last pointer (debug and asserts purposes) lsSet.GetPosFrom(lsAmp); } } if (!bTokenOk) { break; // Stop processing command line } else if (lsNameVal) { // And split name/value _ASSERTE(lsNameVal!=NULL); wchar_t* pszEq = wcschr(lsNameVal, L'='); if (!pszEq) { _ASSERTE(pszEq!=NULL); break; } *(pszEq++) = 0; bNew |= (NULL != Add(lsCmd, lsNameVal, pszEq ? pszEq : L"", anBefore)); } // Remember processed position if (ppszEnd) { *ppszEnd = lsCmdLine; } } // end of "while (NextArg(&lsCmdLine, lsSet) == 0)" // Fin if (ppszEnd && (!*ppszEnd || !**ppszEnd)) { static wchar_t szSimple[] = L"cmd"; *ppszEnd = szSimple; } return bNew; }