void CSetPgDebug::debugLogShellText(wchar_t* &pszParamEx, LPCWSTR asFile) { _ASSERTE(pszParamEx!=NULL && asFile && *asFile); CEStr szBuf; DWORD cchMax = 32*1024/*32 KB*/; DWORD nRead = 0, nErrCode = (DWORD)-1; #ifdef _DEBUG LPCWSTR pszExt = PointToExt(asFile); bool bCmdBatch = ((lstrcmpi(pszExt, L".bat") == 0) && (lstrcmpi(pszExt, L".cmd") == 0)); #endif // ReadTextFile will use BOM if it exists UINT nDefCP = CP_OEMCP; if (0 == ReadTextFile(asFile, cchMax, szBuf.ms_Val, nRead, nErrCode, nDefCP)) { size_t nAll = 0; wchar_t* pszNew = NULL; nAll = (lstrlen(pszParamEx)+20) + nRead + 1 + 2*lstrlen(asFile); pszNew = (wchar_t*)realloc(pszParamEx, nAll*sizeof(wchar_t)); if (pszNew) { _wcscat_c(pszNew, nAll, L"\r\n\r\n>>>"); _wcscat_c(pszNew, nAll, asFile); _wcscat_c(pszNew, nAll, L"\r\n"); _wcscat_c(pszNew, nAll, szBuf); _wcscat_c(pszNew, nAll, L"\r\n<<<"); _wcscat_c(pszNew, nAll, asFile); pszParamEx = pszNew; } } }
// static bool CConEmuUpdate::IsUpdatePackage(LPCWSTR asFilePath) { bool bIsUpdatePackage = false; if (asFilePath && *asFilePath && lstrlen(asFilePath) <= MAX_PATH) { wchar_t szName[MAX_PATH+1]; LPCWSTR pszName = PointToName(asFilePath); if (pszName && *pszName) { lstrcpyn(szName, pszName, countof(szName)); CharLowerBuff(szName, lstrlen(szName)); LPCWSTR pszExt = PointToExt(szName); if (pszExt) { if ((wcsncmp(szName, L"conemupack.", 11) == 0) && (wcscmp(pszExt, L".7z") == 0)) { bIsUpdatePackage = true; } else if ((wcsncmp(szName, L"conemusetup.", 12) == 0) && (wcscmp(pszExt, L".exe") == 0)) { bIsUpdatePackage = true; } } } } return bIsUpdatePackage; }
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; }
const wchar_t* PointToExt(const wchar_t *lpwszPath) { if (!lpwszPath) return nullptr; const wchar_t *lpwszEndPtr = lpwszPath; while (*lpwszEndPtr) lpwszEndPtr++; return PointToExt(lpwszPath,lpwszEndPtr); }
bool IsExecutable(LPCWSTR aszFilePathName, wchar_t** rsExpandedVars /*= NULL*/) { #ifndef __GNUC__ #pragma warning( push ) #pragma warning(disable : 6400) #endif wchar_t* pszExpand = NULL; for (int i = 0; i <= 1; i++) { LPCWSTR pwszDot = PointToExt(aszFilePathName); if (pwszDot) // Если указан .exe или .com файл { if (lstrcmpiW(pwszDot, L".exe")==0 || lstrcmpiW(pwszDot, L".com")==0) { if (FileExists(aszFilePathName)) return true; } } if (!i && wcschr(aszFilePathName, L'%')) { pszExpand = ExpandEnvStr(aszFilePathName); if (!pszExpand) break; aszFilePathName = pszExpand; } } if (rsExpandedVars) { *rsExpandedVars = pszExpand; pszExpand = NULL; } else { SafeFree(pszExpand); } return false; }
LPCWSTR CIconList::ParseIconFileIndex(CEStr& lsIconFileIndex, int& nIndex) { LPCWSTR lpszExt = PointToExt(lsIconFileIndex); LPCWSTR lpszIndex = wcsrchr(lpszExt ? lpszExt : lsIconFileIndex, L','); if (lpszIndex) { lsIconFileIndex.ms_Val[lpszIndex - lsIconFileIndex.ms_Val] = 0; nIndex = wcstol(lpszIndex + 1, NULL, 10); if (nIndex == LONG_MAX || nIndex == LONG_MIN) { nIndex = 0; } } else { nIndex = 0; } return lpszExt; }
int CIconList::CreateTabIcon(LPCWSTR asIconDescr, bool bAdmin) { if (!asIconDescr || !*asIconDescr) return GetTabIcon(bAdmin); for (INT_PTR i = 0; i < m_Icons.size(); i++) { const TabIconCache& icn = m_Icons[i]; if ((icn.bAdmin!=FALSE) != bAdmin) continue; if (lstrcmpi(icn.pszIconDescr, asIconDescr) != 0) continue; // Already was created! return icn.nIconIdx; } wchar_t* pszExpanded = ExpandEnvStr(asIconDescr); // Need to be created! int iIconIdx = -1; HICON hFileIcon = NULL; wchar_t szTemp[MAX_PATH]; LPCWSTR pszLoadFile = pszExpanded ? pszExpanded : asIconDescr; LPCWSTR lpszExt = (wchar_t*)PointToExt(pszLoadFile); if (!lpszExt) { LPWSTR pszFile = NULL; if (SearchPath(NULL, pszLoadFile, L".exe", countof(szTemp), szTemp, &pszFile)) { pszLoadFile = szTemp; lpszExt = (wchar_t*)PointToExt(pszLoadFile); } if (!lpszExt) goto wrap; } if (lstrcmpi(lpszExt, L".ico") == 0) { hFileIcon = (HICON)LoadImage(0, pszLoadFile, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR|LR_LOADFROMFILE); } else if ((lstrcmpi(lpszExt, L".exe") == 0) || (lstrcmpi(lpszExt, L".dll") == 0)) { //TODO: May be specified index of an icon in the file HICON hIconLarge = NULL; ExtractIconEx(pszLoadFile, 0, &hIconLarge, &hFileIcon, 1); if (hIconLarge) DestroyIcon(hIconLarge); } else { //TODO: Shell icons for registered files (cmd, bat, sh, pl, py, ...) } if (hFileIcon) { int iIconIdxAdm = -1; iIconIdx = ImageList_ReplaceIcon(mh_TabIcons, -1, hFileIcon); TabIconCache NewIcon = {lstrdup(asIconDescr), false, iIconIdx}; m_Icons.push_back(NewIcon); 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) { iIconIdxAdm = ImageList_ReplaceIcon(mh_TabIcons, -1, hNewIcon); DestroyIcon(hNewIcon); TabIconCache AdmIcon = {lstrdup(asIconDescr), true, iIconIdxAdm}; m_Icons.push_back(AdmIcon); if (bAdmin && (iIconIdxAdm > 0)) { iIconIdx = iIconIdxAdm; } } } //TODO: bAdmin!!! DestroyIcon(hFileIcon); } wrap: SafeFree(pszExpanded); return iIconIdx; }
bool FindImageSubsystem(const wchar_t *Module, /*wchar_t* pstrDest,*/ DWORD& ImageSubsystem, DWORD& ImageBits, DWORD& FileAttrs) { if (!Module || !*Module) return false; bool Result = false; //ImageSubsystem = IMAGE_SUBSYSTEM_UNKNOWN; // Исключения нас не интересуют - команда уже сформирована и отдана в CreateProcess! //// нулевой проход - смотрим исключения //// Берем "исключения" из реестра, которые должны исполняться директом, //// например, некоторые внутренние команды ком. процессора. //string strExcludeCmds; //GetRegKey(strSystemExecutor,L"ExcludeCmds",strExcludeCmds,L""); //UserDefinedList ExcludeCmdsList; //ExcludeCmdsList.Set(strExcludeCmds); //while (!ExcludeCmdsList.IsEmpty()) //{ // if (!StrCmpI(Module,ExcludeCmdsList.GetNext())) // { // ImageSubsystem=IMAGE_SUBSYSTEM_WINDOWS_CUI; // Result=true; // break; // } //} //string strFullName=Module; LPCWSTR ModuleExt = PointToExt(Module); wchar_t *strPathExt/*[32767]*/ = NULL; //(L".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WSH"); wchar_t *strPathEnv/*[32767]*/ = NULL; wchar_t *strExpand/*[32767]*/ = NULL; wchar_t *strTmpName/*[32767]*/ = NULL; wchar_t *pszFilePart = NULL; DWORD nPathExtLen = 0; LPCWSTR pszPathExtEnd = NULL; LPWSTR Ext = NULL; typedef LONG (WINAPI *RegOpenKeyExW_t)(HKEY hKey, LPCTSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult); RegOpenKeyExW_t _RegOpenKeyEx = NULL; typedef LONG (WINAPI *RegQueryValueExW_t)(HKEY hKey, LPCTSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData); RegQueryValueExW_t _RegQueryValueEx = NULL; typedef LONG (WINAPI *RegCloseKey_t)(HKEY hKey); RegCloseKey_t _RegCloseKey = NULL; HMODULE hAdvApi = NULL; int cchstrPathExt = 32767; strPathExt = (wchar_t*)malloc(cchstrPathExt*sizeof(wchar_t)); *strPathExt = 0; int cchstrPathEnv = 32767; strPathEnv = (wchar_t*)malloc(cchstrPathEnv*sizeof(wchar_t)); *strPathEnv = 0; int cchstrExpand = 32767; strExpand = (wchar_t*)malloc(cchstrExpand*sizeof(wchar_t)); *strExpand = 0; int cchstrTmpName = 32767; strTmpName = (wchar_t*)malloc(cchstrTmpName*sizeof(wchar_t)); *strTmpName = 0; nPathExtLen = GetEnvironmentVariable(L"PATHEXT", strPathExt, cchstrPathExt-2); if (!nPathExtLen) { _wcscpy_c(strPathExt, cchstrPathExt, L".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WSH"); nPathExtLen = lstrlen(strPathExt); } pszPathExtEnd = strPathExt+nPathExtLen; // Разбить на токены strPathExt[nPathExtLen] = strPathExt[nPathExtLen+1] = 0; Ext = wcschr(strPathExt, L';'); while (Ext) { *Ext = 0; Ext = wcschr(Ext+1, L';'); } TODO("Проверить на превышение длин строк"); // первый проход - в текущем каталоге LPWSTR pszExtCur = strPathExt; while (pszExtCur < pszPathExtEnd) { Ext = pszExtCur; pszExtCur = pszExtCur + lstrlen(pszExtCur)+1; _wcscpyn_c(strTmpName, cchstrTmpName, Module, cchstrTmpName); //-V501 if (!ModuleExt) { if (!*Ext) continue; _wcscatn_c(strTmpName, cchstrTmpName, Ext, cchstrTmpName); } if (GetImageSubsystem(strTmpName, ImageSubsystem, ImageBits/*16/32/64*/, FileAttrs)) { Result = true; goto wrap; } if (ModuleExt) { break; } } // второй проход - по правилам SearchPath // поиск по переменной PATH if (GetEnvironmentVariable(L"PATH", strPathEnv, cchstrPathEnv)) { LPWSTR pszPathEnvEnd = strPathEnv + lstrlen(strPathEnv); LPWSTR pszPathCur = strPathEnv; while (pszPathCur && (pszPathCur < pszPathEnvEnd)) { LPWSTR Path = pszPathCur; LPWSTR pszPathNext = wcschr(pszPathCur, L';'); if (pszPathNext) { *pszPathNext = 0; pszPathCur = pszPathNext+1; } else { pszPathCur = pszPathEnvEnd; } if (!*Path) continue; pszExtCur = strPathExt; while (pszExtCur < pszPathExtEnd) { Ext = pszExtCur; pszExtCur = pszExtCur + lstrlen(pszExtCur)+1; if (!*Ext) continue; if (SearchPath(Path, Module, Ext, cchstrTmpName, strTmpName, &pszFilePart)) { if (GetImageSubsystem(strTmpName, ImageSubsystem, ImageBits, FileAttrs)) { Result = true; goto wrap; } } } } } pszExtCur = strPathExt; while (pszExtCur < pszPathExtEnd) { Ext = pszExtCur; pszExtCur = pszExtCur + lstrlen(pszExtCur)+1; if (!*Ext) continue; if (SearchPath(NULL, Module, Ext, cchstrTmpName, strTmpName, &pszFilePart)) { if (GetImageSubsystem(strTmpName, ImageSubsystem, ImageBits, FileAttrs)) { Result = true; goto wrap; } } } // третий проход - лезем в реестр в "App Paths" if (!wcschr(Module, L'\\')) { hAdvApi = LoadLibrary(L"AdvApi32.dll"); if (!hAdvApi) goto wrap; _RegOpenKeyEx = (RegOpenKeyExW_t)GetProcAddress(hAdvApi, "RegOpenKeyExW"); _RegQueryValueEx = (RegQueryValueExW_t)GetProcAddress(hAdvApi, "RegQueryValueExW"); _RegCloseKey = (RegCloseKey_t)GetProcAddress(hAdvApi, "RegCloseKey"); if (!_RegOpenKeyEx || !_RegQueryValueEx || !_RegCloseKey) goto wrap; LPCWSTR RegPath = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"; // В строке Module заменить исполняемый модуль на полный путь, который // берется из SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths // Сначала смотрим в HKCU, затем - в HKLM HKEY RootFindKey[] = {HKEY_CURRENT_USER,HKEY_LOCAL_MACHINE,HKEY_LOCAL_MACHINE}; BOOL lbAddExt = FALSE; pszExtCur = strPathExt; while (pszExtCur < pszPathExtEnd) { if (!lbAddExt) { Ext = NULL; lbAddExt = TRUE; } else { Ext = pszExtCur; pszExtCur = pszExtCur + lstrlen(pszExtCur)+1; if (!*Ext) continue; } _wcscpy_c(strTmpName, cchstrTmpName, RegPath); _wcscatn_c(strTmpName, cchstrTmpName, Module, cchstrTmpName); if (Ext) _wcscatn_c(strTmpName, cchstrTmpName, Ext, cchstrTmpName); DWORD samDesired = KEY_QUERY_VALUE; DWORD RedirectionFlag = 0; // App Paths key is shared in Windows 7 and above OSVERSIONINFO osv = {sizeof(OSVERSIONINFO)}; GetVersionEx(&osv); if (osv.dwMajorVersion < 6 || (osv.dwMajorVersion == 6 && osv.dwMinorVersion < 1)) { #ifdef _WIN64 RedirectionFlag = KEY_WOW64_32KEY; #else RedirectionFlag = IsWindows64() ? KEY_WOW64_64KEY : 0; #endif } for (size_t i = 0; i < countof(RootFindKey); i++) { if (i == (countof(RootFindKey)-1)) { if (RedirectionFlag) samDesired |= RedirectionFlag; else break; } HKEY hKey; if (_RegOpenKeyEx(RootFindKey[i], strTmpName, 0, samDesired, &hKey) == ERROR_SUCCESS) { DWORD nType = 0, nSize = sizeof(strTmpName)-2; int RegResult = _RegQueryValueEx(hKey, L"", NULL, &nType, (LPBYTE)strTmpName, &nSize); _RegCloseKey(hKey); if ((RegResult == ERROR_SUCCESS) && (nType == REG_SZ || nType == REG_EXPAND_SZ || nType == REG_MULTI_SZ)) { strTmpName[(nSize >> 1)+1] = 0; if (!ExpandEnvironmentStrings(strTmpName, strExpand, cchstrExpand)) _wcscpy_c(strExpand, cchstrExpand, strTmpName); if (GetImageSubsystem(Unquote(strExpand), ImageSubsystem, ImageBits, FileAttrs)) { Result = true; goto wrap; } } } }
bool GetImageSubsystem(const wchar_t *FileName,DWORD& ImageSubsystem,DWORD& ImageBits/*16/32/64*/,DWORD& FileAttrs) { bool Result = false; ImageSubsystem = IMAGE_SUBSYSTEM_UNKNOWN; ImageBits = 0; FileAttrs = (DWORD)-1; wchar_t* pszExpand = NULL; // Пытаться в UNC? Хотя сам CreateProcess UNC не поддерживает, так что смысла пока нет HANDLE hModuleFile = CreateFile(FileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); // Переменные окружения if ((hModuleFile == INVALID_HANDLE_VALUE) && FileName && wcschr(FileName, L'%')) { pszExpand = ExpandEnvStr(FileName); if (pszExpand) { hModuleFile = CreateFile(pszExpand,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); if (hModuleFile != INVALID_HANDLE_VALUE) { FileName = pszExpand; } } } #if 0 // Если не указан путь к файлу - попробовать найти его в %PATH% if (hModuleFile != INVALID_HANDLE_VALUE && FileName && wcschr(FileName, L'\\') == NULL && wcschr(FileName, L'.') != NULL) { DWORD nErrCode = GetLastError(); if (nErrCode) { wchar_t szFind[MAX_PATH], *psz; DWORD nLen = SearchPath(NULL, FileName, NULL, countof(szFind), szFind, &psz); if (nLen && nLen < countof(szFind)) hModuleFile = CreateFile(szFind,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); } } #endif if (hModuleFile != INVALID_HANDLE_VALUE) { BY_HANDLE_FILE_INFORMATION bfi = {0}; IMAGE_DOS_HEADER DOSHeader; DWORD ReadSize; if (GetFileInformationByHandle(hModuleFile, &bfi)) FileAttrs = bfi.dwFileAttributes; // Это это батник - сразу вернуть IMAGE_SUBSYSTEM_BATCH_FILE LPCWSTR pszExt = PointToExt(FileName); if (pszExt && (!lstrcmpi(pszExt, L".cmd") || !lstrcmpiW(pszExt, L".bat") || !lstrcmpiW(pszExt, L".btm") // take command )) { CloseHandle(hModuleFile); ImageSubsystem = IMAGE_SUBSYSTEM_BATCH_FILE; ImageBits = IsWindows64() ? 64 : 32; //-V112 Result = true; goto wrap; } if (ReadFile(hModuleFile,&DOSHeader,sizeof(DOSHeader),&ReadSize,NULL)) { _ASSERTE(IMAGE_DOS_SIGNATURE==0x5A4D); if (DOSHeader.e_magic != IMAGE_DOS_SIGNATURE) { //const wchar_t *pszExt = wcsrchr(FileName, L'.'); if (pszExt && lstrcmpiW(pszExt, L".com") == 0) { ImageSubsystem = IMAGE_SUBSYSTEM_DOS_EXECUTABLE; ImageBits = 16; Result = true; } } else { ImageSubsystem = IMAGE_SUBSYSTEM_DOS_EXECUTABLE; ImageBits = 16; Result = true; if (SetFilePointer(hModuleFile,DOSHeader.e_lfanew,NULL,FILE_BEGIN)) { IMAGE_HEADERS PEHeader; if (ReadFile(hModuleFile,&PEHeader,sizeof(PEHeader),&ReadSize,NULL)) { _ASSERTE(IMAGE_NT_SIGNATURE==0x00004550); if (PEHeader.Signature == IMAGE_NT_SIGNATURE) { switch(PEHeader.OptionalHeader32.Magic) { case IMAGE_NT_OPTIONAL_HDR32_MAGIC: { ImageSubsystem = PEHeader.OptionalHeader32.Subsystem; _ASSERTE((ImageSubsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) || (ImageSubsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)); ImageBits = 32; //-V112 } break; case IMAGE_NT_OPTIONAL_HDR64_MAGIC: { ImageSubsystem = PEHeader.OptionalHeader64.Subsystem; _ASSERTE((ImageSubsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) || (ImageSubsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)); ImageBits = 64; } break; /*default: { // unknown magic }*/ } } else if ((WORD)PEHeader.Signature == IMAGE_OS2_SIGNATURE) { ImageBits = 32; //-V112 /* NE, хмм... а как определить что оно ГУЕВОЕ? Andrzej Novosiolov <*****@*****.**> AN> ориентироваться по флагу "Target operating system" NE-заголовка AN> (1 байт по смещению 0x36). Если там Windows (значения 2, 4) - подразумеваем AN> GUI, если OS/2 и прочая экзотика (остальные значения) - подразумеваем консоль. */ BYTE ne_exetyp = reinterpret_cast<PIMAGE_OS2_HEADER>(&PEHeader)->ne_exetyp; if (ne_exetyp==2||ne_exetyp==4) //-V112 { ImageSubsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; } else { ImageSubsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; } } /*else { // unknown signature }*/ } /*else { // обломс вышел с чтением следующего заголовка ;-( }*/ } /*else { // видимо улетели куда нить в трубу, т.к. dos_head.e_lfanew указал // слишком в неправдоподное место (например это чистой воды DOS-файл) }*/ } /*else { // это не исполняемый файл - у него нету заголовка MZ, например, NLM-модуль // TODO: здесь можно разбирать POSIX нотацию, например "/usr/bin/sh" }*/ } /*else { // ошибка чтения }*/ CloseHandle(hModuleFile); } /*else { // ошибка открытия }*/ wrap: SafeFree(pszExpand); return Result; }
void ConEmuUpdateSettings::ResetToDefaults() { // Указатели должны быть освобождены перед вызовом _ASSERTE(szUpdateExeCmdLine==NULL); szUpdateVerLocation = NULL; isUpdateCheckOnStartup = false; isUpdateCheckHourly = false; isUpdateConfirmDownload = true; // true-Show MessageBox, false-notify via TSA only isUpdateUseBuilds = 0; // 0-спросить пользователя при первом запуске, 1-stable only, 2-latest isUpdateUseProxy = false; szUpdateProxy = szUpdateProxyUser = szUpdateProxyPassword = NULL; // "Server:port" // Проверяем, была ли программа установлена через ConEmuSetup.exe? isUpdateDownloadSetup = 0; // 0-Auto, 1-Installer (ConEmuSetup.exe), 2-7z archieve (ConEmu.7z), WinRar or 7z required isSetupDetected = 0; // 0-пока не проверялся, 1-установлено через Installer, пути совпали, 2-Installer не запускался szUpdateExeCmdLineDef = lstrdup(L"\"%1\" /p:%3 /qr"); SafeFree(szUpdateExeCmdLine); bool bWinRar = false; wchar_t* pszArcPath = NULL; BOOL bWin64 = IsWindows64(); for (int i = 0; !(pszArcPath && *pszArcPath) && (i <= 5); i++) { SettingsRegistry regArc; switch (i) { case 0: if (regArc.OpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\7-Zip", KEY_READ|(bWin64?KEY_WOW64_32KEY:0))) { regArc.Load(L"Path", &pszArcPath); } break; case 1: if (bWin64 && regArc.OpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\7-Zip", KEY_READ|KEY_WOW64_64KEY)) { regArc.Load(L"Path", &pszArcPath); } break; case 2: if (regArc.OpenKey(HKEY_CURRENT_USER, L"SOFTWARE\\7-Zip", KEY_READ)) { regArc.Load(L"Path", &pszArcPath); } break; case 3: if (regArc.OpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\WinRAR", KEY_READ|(bWin64?KEY_WOW64_32KEY:0))) { bWinRar = true; regArc.Load(L"exe32", &pszArcPath); } break; case 4: if (bWin64 && regArc.OpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\WinRAR", KEY_READ|KEY_WOW64_64KEY)) { bWinRar = true; regArc.Load(L"exe64", &pszArcPath); } break; case 5: if (regArc.OpenKey(HKEY_CURRENT_USER, L"SOFTWARE\\WinRAR", KEY_READ)) { bWinRar = true; if (!regArc.Load(L"exe32", &pszArcPath) && bWin64) { regArc.Load(L"exe64", &pszArcPath); } } break; } } if (!pszArcPath || !*pszArcPath) { szUpdateArcCmdLineDef = lstrdup(L"\"%ProgramFiles%\\7-Zip\\7zg.exe\" x -y \"%1\""); // "%1"-archive file, "%2"-ConEmu base dir } else { LPCWSTR pszExt = PointToExt(pszArcPath); int cchMax = lstrlen(pszArcPath)+64; szUpdateArcCmdLineDef = (wchar_t*)malloc(cchMax*sizeof(wchar_t)); if (szUpdateArcCmdLineDef) { if (pszExt && lstrcmpi(pszExt, L".exe") == 0) { _ASSERTE(bWinRar==true); //Issue 537: old WinRAR beta's fails //_wsprintf(szUpdateArcCmdLineDef, SKIPLEN(cchMax) L"\"%s\" x -y \"%%1\"%s", pszArcPath, bWinRar ? L" \"%%2\\\"" : L""); _wsprintf(szUpdateArcCmdLineDef, SKIPLEN(cchMax) L"\"%s\" x -y \"%%1\"", pszArcPath); } else { _ASSERTE(bWinRar==false); int nLen = lstrlen(pszArcPath); bool bNeedSlash = (*pszArcPath && (pszArcPath[nLen-1] != L'\\')) ? true : false; _wsprintf(szUpdateArcCmdLineDef, SKIPLEN(cchMax) L"\"%s%s7zg.exe\" x -y \"%%1\"", pszArcPath, bNeedSlash ? L"\\" : L""); } } } SafeFree(pszArcPath); SafeFree(szUpdateArcCmdLine); szUpdateDownloadPath = lstrdup(L"%TEMP%\\ConEmu"); isUpdateLeavePackages = false; szUpdatePostUpdateCmd = lstrdup(L"echo Last successful update>ConEmuUpdate.info && date /t>>ConEmuUpdate.info && time /t>>ConEmuUpdate.info"); // Юзер может чего-то свое делать с распакованными файлами }
//------------------------------------------------------------------------ ///| 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; }
//------------------------------------------------------------------------ ///| 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) }
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; }
bool IsNeedCmd(BOOL bRootCmd, LPCWSTR asCmdLine, CmdArg &szExe, LPCWSTR* rsArguments /*= NULL*/, BOOL* rpbNeedCutStartEndQuot /*= NULL*/, BOOL* rpbRootIsCmdExe /*= NULL*/, BOOL* rpbAlwaysConfirmExit /*= NULL*/, BOOL* rpbAutoDisableConfirmExit /*= NULL*/) { _ASSERTE(asCmdLine && *asCmdLine); bool rbNeedCutStartEndQuot = false; bool rbRootIsCmdExe = true; bool rbAlwaysConfirmExit = false; bool rbAutoDisableConfirmExit = false; if (rsArguments) *rsArguments = NULL; bool lbRc = false; int iRc = 0; BOOL lbFirstWasGot = FALSE; LPCWSTR pwszCopy; int nLastChar; #ifdef _DEBUG // Это минимальные проверки, собственно к коду - не относятся CmdArg szDbgFirst; 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(); // 17.10.2010 - поддержка переданного исполняемого файла без параметров, но с пробелами в пути LPCWSTR pchEnd = pwszCopy + lstrlenW(pwszCopy); while (pchEnd > pwszCopy && *(pchEnd-1) == L' ') pchEnd--; if ((pchEnd - pwszCopy) < MAX_PATH) { szExe.Set(pwszCopy, (pchEnd - pwszCopy)); _ASSERTE(szExe[(pchEnd - pwszCopy)] == 0); if (lstrcmpiW(szExe, L"start") == 0) { // Команду start обрабатывает только процессор #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } // Обработка переменных окружения и поиск в PATH if (FileExistsSearch((LPCWSTR)szExe, szExe)) { if (rsArguments) *rsArguments = pchEnd; } else { szExe.Empty(); } } 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; } if (lstrcmpiW(szExe, L"start") == 0) { // Команду start обрабатывает только процессор #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } // Обработка переменных окружения и поиск в 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" } } // Пробуем найти "по путям" соответствующий exe-шник. DWORD nCchMax = szExe.mn_MaxLen; // выделить память, длинее чем szExe вернуть не сможем wchar_t* pszSearch = (wchar_t*)malloc(nCchMax*sizeof(wchar_t)); if (pszSearch) { #ifndef CONEMU_MINIMAL MWow64Disable wow; wow.Disable(); // Отключить редиректор! #endif wchar_t *pszName = NULL; DWORD nRc = SearchPath(NULL, szExe, bHasExt ? NULL : L".exe", nCchMax, pszSearch, &pszName); if (nRc && (nRc < nCchMax)) { // Нашли, возвращаем что нашли szExe.Set(pszSearch); } free(pszSearch); } } // 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 wchar_t *pwszEndSpace = szExe.ms_Arg + 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) { wchar_t szSearch[MAX_PATH+1], *pszPart = NULL; DWORD n = SearchPath(NULL, pwszCopy, L".exe", countof(szSearch), szSearch, &pszPart); if (n && (n < countof(szSearch))) { if (lstrcmpi(PointToExt(pszPart), 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 true, if application was found in registry: // [HKCU|HKLM]\Software\Microsoft\Windows\CurrentVersion\App Paths // Also, function may change local process %PATH% variable bool SearchAppPaths(LPCWSTR asFilePath, CmdArg& rsFound, bool abSetPath, CmdArg* rpsPathRestore /*= NULL*/) { if (rpsPathRestore) rpsPathRestore->Empty(); if (!asFilePath || !*asFilePath) return false; LPCWSTR pszSearchFile = PointToName(asFilePath); LPCWSTR pszExt = PointToExt(pszSearchFile); // Lets try find it in "App Paths" // "HKCU\Software\Microsoft\Windows\CurrentVersion\App Paths\" // "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" LPCWSTR pszRoot = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"; HKEY hk; LONG lRc; CmdArg lsName; lsName.Attach(lstrmerge(pszRoot, pszSearchFile, pszExt ? NULL : L".exe")); // Seems like 32-bit and 64-bit registry branches are the same now, but just in case - will check both DWORD nWOW[2] = {WIN3264TEST(KEY_WOW64_32KEY,KEY_WOW64_64KEY), WIN3264TEST(KEY_WOW64_64KEY,KEY_WOW64_32KEY)}; for (int i = 0; i < 3; i++) { bool bFound = false; DWORD nFlags = ((i && IsWindows64()) ? nWOW[i-1] : 0); if ((i == 2) && !nFlags) break; // This is 32-bit OS lRc = RegOpenKeyEx(i ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, lsName, 0, KEY_READ|nFlags, &hk); if (lRc != 0) continue; wchar_t szVal[MAX_PATH+1] = L""; DWORD nType, nSize = sizeof(szVal)-sizeof(szVal[0]); lRc = RegQueryValueEx(hk, NULL, NULL, &nType, (LPBYTE)szVal, &nSize); if (lRc == 0) { wchar_t *pszCheck = NULL; if (nType == REG_SZ) { pszCheck = szVal; } else if (nType == REG_EXPAND_SZ) { pszCheck = ExpandEnvStr(szVal); } // May be quoted if (pszCheck) { LPCWSTR pszPath = Unquote(pszCheck, true); if (FileExists(pszPath)) { // asFilePath will be invalid after .Set rsFound.Set(pszPath); bFound = true; if (pszCheck != szVal) free(pszCheck); // The program may require additional "%PATH%". So, if allowed... if (abSetPath) { nSize = 0; lRc = RegQueryValueEx(hk, L"PATH", NULL, &nType, NULL, &nSize); if (lRc == 0 && nSize) { wchar_t* pszCurPath = GetEnvVar(L"PATH"); wchar_t* pszAddPath = (wchar_t*)calloc(nSize+4,1); wchar_t* pszNewPath = NULL; if (pszAddPath) { lRc = RegQueryValueEx(hk, L"PATH", NULL, &nType, (LPBYTE)pszAddPath, &nSize); if (lRc == 0 && *pszAddPath) { // Если в "%PATH%" этого нет (в начале) - принудительно добавить int iCurLen = pszCurPath ? lstrlen(pszCurPath) : 0; int iAddLen = lstrlen(pszAddPath); bool bNeedAdd = true; if ((iCurLen >= iAddLen) && (pszCurPath[iAddLen] == L';' || pszCurPath[iAddLen] == 0)) { wchar_t ch = pszCurPath[iAddLen]; pszCurPath[iAddLen] = 0; if (lstrcmpi(pszCurPath, pszAddPath) == 0) bNeedAdd = false; pszCurPath[iAddLen] = ch; } // Если пути еще нет if (bNeedAdd) { if (rpsPathRestore) { rpsPathRestore->SavePathVar(pszCurPath); } pszNewPath = lstrmerge(pszAddPath, L";", pszCurPath); if (pszNewPath) { SetEnvironmentVariable(L"PATH", pszNewPath); } else { _ASSERTE(pszNewPath!=NULL && "Allocation failed?"); } } } } SafeFree(pszAddPath); SafeFree(pszCurPath); SafeFree(pszNewPath); } } } } } RegCloseKey(hk); if (bFound) return true; } return false; }
BOOL DumpImage(HDC hScreen, HBITMAP hBitmap, int anX, int anY, int anWidth, int anHeight, LPCWSTR pszFile, bool PreserveTransparency/*=true*/) { BOOL lbRc = FALSE; LPBYTE pScreen = NULL; DWORD cbOut = 0; wchar_t* pszDot = NULL; wchar_t szFile[MAX_PATH+1] = {}; if (pszFile) { lstrcpynW(szFile, pszFile, MAX_PATH); pszDot = (wchar_t*)PointToExt(szFile); } #ifdef PNGDUMP // Если передали готовый hBitmap - сохранить сразу if (pszDot) lstrcpyW(pszDot, L".png"); if (hBitmap && SaveImageEx(szFile, hBitmap)) { return TRUE; } #endif // иначе - снять копию с hScreen if (!LoadScreen(hScreen, anX, anY, anWidth, anHeight, &pScreen, &cbOut, PreserveTransparency)) return FALSE; if (!*szFile) { //static wchar_t szLastDumpFile[MAX_PATH]; SYSTEMTIME st; GetLocalTime(&st); _wsprintf(szFile, SKIPLEN(countof(szFile)) L"%02u%02u%02u%02u%02u%02u", st.wYear%100, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); OPENFILENAME ofn; memset(&ofn,0,sizeof(ofn)); ofn.lStructSize=sizeof(ofn); HWND h = GetForegroundWindow(); DWORD nPID = 0; if (h) GetWindowThreadProcessId(h, &nPID); ofn.hwndOwner = (nPID == GetCurrentProcessId()) ? h : ghWnd; #ifdef PNGDUMP ofn.lpstrFilter = L"PNG (*.png)\0*.png\0JPEG (*.jpg)\0*.jpg\0BMP (*.bmp)\0*.bmp\0\0"; ofn.lpstrDefExt = L"png"; #else ofn.lpstrFilter = L"BMP (*.bmp)\0*.bmp\0\0"; ofn.lpstrDefExt = L"bmp"; #endif ofn.nFilterIndex = 1; ofn.lpstrFile = szFile; ofn.nMaxFile = countof(szFile); ofn.lpstrTitle = L"Save screenshot"; ofn.Flags = OFN_ENABLESIZING|OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST|OFN_EXPLORER|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT; if (!GetSaveFileName(&ofn) || ((pszDot = (wchar_t*)PointToExt(szFile)) == NULL)) { lbRc = TRUE; // чтобы не ругалось... goto wrap; } //wcscpy_c(szFile, szLastDumpFile); } #ifdef PNGDUMP if (SaveImageEx(szFile, pScreen, cbOut)) { lbRc = TRUE; goto wrap; } #endif if (pScreen && cbOut) { if (pszDot) { #ifdef PNGDUMP lstrcpyW(pszDot, L".png"); #else lstrcpyW(pszDot, L".bmp"); #endif HANDLE hFile = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (hFile != INVALID_HANDLE_VALUE) { DWORD dwWritten = 0; lbRc = WriteFile(hFile, pScreen, cbOut, &dwWritten, 0); CloseHandle(hFile); } } } wrap: SafeFree(pScreen); return lbRc; }
const wchar_t* PointToExt(string& strPath) { const wchar_t *lpwszPath=strPath.CPtr(); const wchar_t *lpwszEndPtr=lpwszPath+strPath.GetLength(); return PointToExt(lpwszPath,lpwszEndPtr); }
int PrepareHookModule(wchar_t (&szModule)[MAX_PATH+16]) { int iRc = -251; wchar_t szNewPath[MAX_PATH+16] = {}, szAddName[32] = {}, szVer[2] = {}; INT_PTR nLen = 0; bool bAlreadyExists = false; // Copy szModule to CSIDL_LOCAL_APPDATA and return new path HRESULT hr = SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0/*SHGFP_TYPE_CURRENT*/, szNewPath); if ((hr != S_OK) || !*szNewPath) { iRc = -251; goto wrap; } szVer[0] = MVV_4a[0]; _wsprintf(szAddName, SKIPLEN(countof(szAddName)) L"\\" CEDEFTERMDLLFORMAT /*L"ConEmuHk%s.%02u%02u%02u%s.dll"*/, WIN3264TEST(L"",L"64"), MVV_1, MVV_2, MVV_3, szVer); nLen = lstrlen(szNewPath); if (szNewPath[nLen-1] != L'\\') { szNewPath[nLen++] = L'\\'; szNewPath[nLen] = 0; } if ((nLen + lstrlen(szAddName) + 8) >= countof(szNewPath)) { iRc = -252; goto wrap; } wcscat_c(szNewPath, L"ConEmu"); if (!DirectoryExists(szNewPath)) { if (!CreateDirectory(szNewPath, NULL)) { iRc = -253; goto wrap; } } wcscat_c(szNewPath, szAddName); if ((bAlreadyExists = FileExists(szNewPath)) && FileCompare(szNewPath, szModule)) { // OK, file exists and match the required } else { if (bAlreadyExists) { _ASSERTE(FALSE && "Continue to overwrite existing ConEmuHk in AppLocal"); // Try to delete or rename old version if (!DeleteFile(szNewPath)) { //SYSTEMTIME st; GetLocalTime(&st); wchar_t szBakPath[MAX_PATH+32]; wcscpy_c(szBakPath, szNewPath); wchar_t* pszExt = (wchar_t*)PointToExt(szBakPath); msprintf(pszExt, 16, L".%u.dll", GetTickCount()); DeleteFile(szBakPath); MoveFile(szNewPath, szBakPath); } } if (!CopyFile(szModule, szNewPath, FALSE)) { iRc = -254; goto wrap; } } wcscpy_c(szModule, szNewPath); iRc = 0; wrap: return iRc; }
int CIconList::CreateTabIconInt(LPCWSTR asIconDescr, bool bAdmin, LPCWSTR asWorkDir) { wchar_t* pszExpanded = ExpandEnvStr(asIconDescr); // Need to be created! int iIconIdx = -1; HICON hFileIcon = NULL; wchar_t szTemp[MAX_PATH]; LPCWSTR pszLoadFile = pszExpanded ? pszExpanded : asIconDescr; LPCWSTR lpszExt = (wchar_t*)PointToExt(pszLoadFile); bool bDirChanged = false; if (asWorkDir && *asWorkDir) { // Executable (or icon) file may be not availbale by %PATH%, let "cd" to it... bDirChanged = gpConEmu->ChangeWorkDir(asWorkDir); } if (!lpszExt) { LPWSTR pszFile = NULL; if (SearchPath(NULL, pszLoadFile, L".exe", countof(szTemp), szTemp, &pszFile)) { pszLoadFile = szTemp; lpszExt = (wchar_t*)PointToExt(pszLoadFile); } if (!lpszExt) goto wrap; } if (lstrcmpi(lpszExt, L".ico") == 0) { hFileIcon = (HICON)LoadImage(0, pszLoadFile, IMAGE_ICON, mn_CxIcon, mn_CyIcon, LR_DEFAULTCOLOR|LR_LOADFROMFILE); } else if ((lstrcmpi(lpszExt, L".exe") == 0) || (lstrcmpi(lpszExt, L".dll") == 0)) { //TODO: May be specified index of an icon in the file HICON hIconLarge = NULL, hIconSmall = NULL; ExtractIconEx(pszLoadFile, 0, &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; }
// В asDir могут быть переменные окружения. wchar_t* CConEmuUpdate::CreateTempFile(LPCWSTR asDir, LPCWSTR asFileNameTempl, HANDLE& hFile) { wchar_t szFile[MAX_PATH*2+2]; wchar_t szName[128]; if (!asDir || !*asDir) asDir = L"%TEMP%\\ConEmu"; if (!asFileNameTempl || !*asFileNameTempl) asFileNameTempl = L"ConEmu.tmp"; if (wcschr(asDir, L'%')) { DWORD nExp = ExpandEnvironmentStrings(asDir, szFile, MAX_PATH); if (!nExp || (nExp >= MAX_PATH)) { ReportError(L"CreateTempFile.ExpandEnvironmentStrings(%s) failed, code=%u", asDir, GetLastError()); return NULL; } } else { lstrcpyn(szFile, asDir, MAX_PATH); } // Checking %TEMP% for valid path LPCWSTR pszColon1, pszColon2; if ((pszColon1 = wcschr(szFile, L':')) != NULL) { if ((pszColon2 = wcschr(pszColon1+1, L':')) != NULL) { ReportError(L"Invalid download path (%%TEMP%% variable?)\n%s", szFile, 0); return NULL; } } int nLen = lstrlen(szFile); if (nLen <= 0) { ReportError(L"CreateTempFile.asDir(%s) failed, path is null", asDir, 0); return NULL; } if (szFile[nLen-1] != L'\\') { szFile[nLen++] = L'\\'; szFile[nLen] = 0; } wchar_t* pszFilePart = szFile + nLen; wchar_t* pszDirectory = lstrdup(szFile); LPCWSTR pszName = PointToName(asFileNameTempl); _ASSERTE(pszName == asFileNameTempl); if (!pszName || !*pszName || (*pszName == L'.')) { _ASSERTE(pszName && *pszName && (*pszName != L'.')); pszName = L"ConEmu"; } LPCWSTR pszExt = PointToExt(pszName); if (pszExt == NULL) { _ASSERTE(pszExt != NULL); pszExt = L".tmp"; } lstrcpyn(szName, pszName, countof(szName)-16); wchar_t* psz = wcsrchr(szName, L'.'); if (psz) *psz = 0; wchar_t* pszResult = NULL; DWORD dwErr = 0; for (UINT i = 0; i <= 9999; i++) { _wcscpy_c(pszFilePart, MAX_PATH, szName); if (i) _wsprintf(pszFilePart+_tcslen(pszFilePart), SKIPLEN(16) L"(%u)", i); _wcscat_c(pszFilePart, MAX_PATH, pszExt); hFile = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_TEMPORARY, NULL); //ERROR_PATH_NOT_FOUND? if (!hFile || (hFile == INVALID_HANDLE_VALUE)) { dwErr = GetLastError(); // на первом обломе - попытаться создать директорию, может ее просто нет? if ((dwErr == ERROR_PATH_NOT_FOUND) && (i == 0)) { if (!MyCreateDirectory(pszDirectory)) { ReportError(L"CreateTempFile.asDir(%s) failed", asDir, 0); goto wrap; } } } if (hFile && hFile != INVALID_HANDLE_VALUE) { psz = lstrdup(szFile); if (!psz) { CloseHandle(hFile); hFile = NULL; ReportError(L"Can't allocate memory (%i bytes)", lstrlen(szFile)); } pszResult = psz; goto wrap; } } ReportError(L"Can't create temp file(%s), code=%u", szFile, dwErr); hFile = NULL; wrap: SafeFree(pszDirectory); return pszResult; }
int CIconList::CreateTabIconInt(LPCWSTR asIconDescr, bool bAdmin, LPCWSTR asWorkDir) { wchar_t* pszExpanded = ExpandEnvStr(asIconDescr); // Need to be created! int iIconIdx = -1; HICON hFileIcon = NULL; wchar_t szTemp[MAX_PATH]; LPCWSTR pszLoadFile = pszExpanded ? pszExpanded : asIconDescr; LPCWSTR lpszExt = (wchar_t*)PointToExt(pszLoadFile); bool bDirChanged = false; if (asWorkDir && *asWorkDir) { // Executable (or icon) file may be not availbale by %PATH%, let "cd" to it... bDirChanged = gpConEmu->ChangeWorkDir(asWorkDir); } if (!lpszExt) { LPWSTR pszFile = NULL; if (SearchPath(NULL, pszLoadFile, L".exe", countof(szTemp), szTemp, &pszFile)) { pszLoadFile = szTemp; lpszExt = (wchar_t*)PointToExt(pszLoadFile); } if (!lpszExt) goto wrap; } if (lstrcmpi(lpszExt, L".ico") == 0) { hFileIcon = (HICON)LoadImage(0, pszLoadFile, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR|LR_LOADFROMFILE); } else if ((lstrcmpi(lpszExt, L".exe") == 0) || (lstrcmpi(lpszExt, L".dll") == 0)) { //TODO: May be specified index of an icon in the file HICON hIconLarge = NULL; ExtractIconEx(pszLoadFile, 0, &hIconLarge, &hFileIcon, 1); if (hIconLarge) DestroyIcon(hIconLarge); } else { //TODO: Shell icons for registered files (cmd, bat, sh, pl, py, ...) } if (hFileIcon) { int iIconIdxAdm = -1; iIconIdx = ImageList_ReplaceIcon(mh_TabIcons, -1, hFileIcon); TabIconCache NewIcon = {lstrdup(asIconDescr), false, iIconIdx}; m_Icons.push_back(NewIcon); 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) { iIconIdxAdm = ImageList_ReplaceIcon(mh_TabIcons, -1, hNewIcon); DestroyIcon(hNewIcon); TabIconCache AdmIcon = {lstrdup(asIconDescr), true, iIconIdxAdm}; m_Icons.push_back(AdmIcon); if (bAdmin && (iIconIdxAdm > 0)) { iIconIdx = iIconIdxAdm; } } } //TODO: bAdmin!!! DestroyIcon(hFileIcon); } wrap: if (bDirChanged) { gpConEmu->ChangeWorkDir(NULL); } SafeFree(pszExpanded); return iIconIdx; }
bool CConEmuUpdate::StartLocalUpdate(LPCWSTR asDownloadedPackage) { bool bRc = false; LPCWSTR pszName, pszExt; HANDLE hTarget = NULL; wchar_t *pszLocalPackage = NULL, *pszBatchFile = NULL; DWORD nLocalCRC = 0; BOOL lbDownloadRc = FALSE, lbExecuteRc = FALSE; LPCWSTR pszPackPref = L"conemupack."; size_t lnPackPref = _tcslen(pszPackPref); LPCWSTR pszSetupPref = L"conemusetup."; size_t lnSetupPref = _tcslen(pszSetupPref); _ASSERTE(gpConEmu && gpConEmu->isMainThread()); if (InUpdate() != us_NotStarted) { MBoxError(L"Checking for updates already started"); goto wrap; } if (mb_InCheckProcedure) { Assert(mb_InCheckProcedure==FALSE); goto wrap; } DeleteBadTempFiles(); Inet.Deinit(true); pszName = PointToName(asDownloadedPackage); pszExt = PointToExt(pszName); if (!pszName || !*pszName || !pszExt || !*pszExt) { AssertMsg(L"Invalid asDownloadedPackage"); goto wrap; } // Запомнить текущие параметры обновления if (!mp_Set) mp_Set = new ConEmuUpdateSettings; mp_Set->LoadFrom(&gpSet->UpdSet); mb_ManualCallMode = TRUE; // Clear possible last error { MSectionLock SC; SC.Lock(mp_LastErrorSC, TRUE); SafeFree(ms_LastErrorInfo); } ms_NewVersion[0] = 0; if ((lstrcmpni(pszName, pszPackPref, lnPackPref) == 0) && (lstrcmpi(pszExt, L".7z") == 0) && (((pszExt - pszName) - lnPackPref + 1) < sizeof(ms_NewVersion))) { // Check it was NOT installed with "Setupper" if (mp_Set->UpdateDownloadSetup() == 1) { DontEnable de; LPCWSTR pszConfirm = L"ConEmu was installed with setup!\nAre you sure to update installation with 7zip?"; int iBtn = MessageBox(NULL, pszConfirm, ms_DefaultTitle, MB_ICONEXCLAMATION|MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_YESNO|MB_DEFBUTTON2); if (iBtn != IDYES) { goto wrap; } } if (!Check7zipInstalled()) goto wrap; // Error already reported // Forcing usage of 7zip package! mp_Set->isUpdateDownloadSetup = 2; //if (!CanUpdateInstallation()) //{ // // Значит 7zip обломается при попытке распаковки // goto wrap; //} // OK size_t nLen = (pszExt - pszName) - lnPackPref; wmemmove(ms_NewVersion, pszName+lnPackPref, nLen); ms_NewVersion[nLen] = 0; } else if ((lstrcmpni(pszName, pszSetupPref, lnSetupPref) == 0) && (lstrcmpi(pszExt, L".exe") == 0) && (((pszExt - pszName) - lnSetupPref + 1) < sizeof(ms_NewVersion))) { // Must be installed with "Setupper" if (mp_Set->UpdateDownloadSetup() != 1) { MBoxError(L"ConEmu was not installed with setup! Can't update!"); goto wrap; } // OK size_t nLen = (pszExt - pszName) - lnSetupPref; wmemmove(ms_NewVersion, pszName+lnSetupPref, nLen); ms_NewVersion[nLen] = 0; } else { AssertMsg(L"Invalid asDownloadedPackage (2)"); goto wrap; } // Сразу проверим, как нужно будет запускаться bNeedRunElevation = NeedRunElevation(); _wsprintf(ms_CurVersion, SKIPLEN(countof(ms_CurVersion)) L"%02u%02u%02u%s", (MVV_1%100),MVV_2,MVV_3,_T(MVV_4a)); //ms_NewVersion // StartLocalUpdate - запуск обновления из локального пакета mb_InetMode = false; mb_DroppedMode = true; pszLocalPackage = CreateTempFile(mp_Set->szUpdateDownloadPath, PointToName(asDownloadedPackage), hTarget); if (!pszLocalPackage) goto wrap; lbDownloadRc = DownloadFile(asDownloadedPackage, pszLocalPackage, hTarget, nLocalCRC, TRUE); CloseHandle(hTarget); if (!lbDownloadRc) goto wrap; if (mb_RequestTerminate) goto wrap; pszBatchFile = CreateBatchFile(pszLocalPackage); if (!pszBatchFile) goto wrap; if (!QueryConfirmation(us_ConfirmUpdate)) { goto wrap; } Assert(mb_ManualCallMode==TRUE); Assert(mpsz_PendingBatchFile==NULL); mpsz_PendingPackageFile = pszLocalPackage; pszLocalPackage = NULL; mpsz_PendingBatchFile = pszBatchFile; pszBatchFile = NULL; m_UpdateStep = us_ExitAndUpdate; if (gpConEmu) gpConEmu->RequestExitUpdate(); lbExecuteRc = TRUE; wrap: _ASSERTE(mpsz_DeleteIniFile==NULL); _ASSERTE(mpsz_DeletePackageFile==NULL); mpsz_DeletePackageFile = NULL; if (pszLocalPackage) { if (*pszLocalPackage && (!lbDownloadRc || (!lbExecuteRc && !mp_Set->isUpdateLeavePackages))) mpsz_DeletePackageFile = pszLocalPackage; //DeleteFile(pszLocalPackage); else SafeFree(pszLocalPackage); } _ASSERTE(mpsz_DeleteBatchFile==NULL); mpsz_DeleteBatchFile = NULL; if (pszBatchFile) { if (*pszBatchFile && !lbExecuteRc) mpsz_DeleteBatchFile = pszBatchFile; //DeleteFile(pszBatchFile); else SafeFree(pszBatchFile); } if (!lbExecuteRc) { m_UpdateStep = us_NotStarted; mb_DroppedMode = false; } return bRc; }
static string_view ProcessMetasymbol(string_view const CurStr, subst_data& SubstData, string& Out) { const auto append_with_escape = [EscapeAmpersands = SubstData.EscapeAmpersands](string& Destination, string_view const Str) { if (EscapeAmpersands && contains(Str, L"&"sv)) { string Escaped(Str); replace(Escaped, L"&"sv, L"&&"sv); append(Destination, Escaped); } else { append(Destination, Str); } }; if (const auto Tail = tokens::skip(CurStr, tokens::passive_panel)) { SubstData.PassivePanel = true; return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::active_panel)) { SubstData.PassivePanel = false; return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::exclamation)) { if (!starts_with(Tail, L'?')) { Out.push_back(L'!'); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::name_extension)) { if (!starts_with(Tail, L'?')) { append_with_escape(Out, SubstData.Default().Normal.Name); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::short_name)) { append_with_escape(Out, SubstData.Default().Short.NameOnly); return Tail; } const auto GetExtension = [](string_view const Name) { const auto Extension = PointToExt(Name); return Extension.empty()? Extension : Extension.substr(1); }; if (const auto Tail = tokens::skip(CurStr, tokens::short_extension)) { append_with_escape(Out, GetExtension(SubstData.Default().Short.Name)); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::extension)) { append_with_escape(Out, GetExtension(SubstData.Default().Normal.Name)); return Tail; } const auto CollectNames = [&SubstData, &append_with_escape](string& Str, auto const Selector) { append_with_escape(Str, join(select(SubstData.Default().Panel->enum_selected(), Selector), L" "sv)); }; if (const auto Tail = tokens::skip(CurStr, tokens::short_list)) { if (!starts_with(Tail, L'?')) { CollectNames(Out, &os::fs::find_data::AlternateFileName); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::list)) { if (!starts_with(Tail, L'?')) { CollectNames(Out, [](const os::fs::find_data& Data) { return quote_space(Data.FileName); }); return Tail; } } const auto GetListName = [&Out, &append_with_escape](string_view const Tail, subst_data& Data, bool Short) { const auto ExclPos = Tail.find(L'!'); if (ExclPos == Tail.npos || starts_with(Tail.substr(ExclPos + 1), L'?')) return size_t{}; const auto Modifiers = Tail.substr(0, ExclPos); if (Data.ListNames) { string Str; if (Data.Default().Panel->MakeListFile(Str, Short, Modifiers)) { if (Short) Str = ConvertNameToShort(Str); append_with_escape(Out, Str); Data.ListNames->add(std::move(Str)); } } else { append(Out, L'!', Short? L'$' : L'@', Modifiers, L'!'); } return Modifiers.size() + 1; }; if (const auto Tail = tokens::skip(CurStr, tokens::list_file)) { if (const auto Offset = GetListName(Tail, SubstData, false)) return string_view(Tail).substr(Offset); } if (const auto Tail = tokens::skip(CurStr, tokens::short_list_file)) { if (const auto Offset = GetListName(Tail, SubstData, true)) return string_view(Tail).substr(Offset); } if (const auto Tail = tokens::skip(CurStr, tokens::short_name_extension)) { if (!starts_with(Tail, L'?')) { append_with_escape(Out, SubstData.Default().Short.Name); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::short_name_extension_safe)) { if (!starts_with(Tail, L'?')) { append_with_escape(Out, SubstData.Default().Short.Name); SubstData.PreserveLFN = true; return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::current_drive)) { const auto CurDir = IsAbsolutePath(SubstData.This.Normal.Name)? SubstData.This.Normal.Name : SubstData.PassivePanel? SubstData.Another.Panel->GetCurDir() : SubstData.CmdDir; auto RootDir = GetPathRoot(CurDir); DeleteEndSlash(RootDir); append_with_escape(Out, RootDir); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::description)) { Out += SubstData.Default().GetDescription(); return Tail; } const auto GetPath = [](string_view const Tail, const subst_data& Data, bool Short, bool Real) { // TODO: paths on plugin panels are ambiguous auto CurDir = Data.PassivePanel? Data.Another.Panel->GetCurDir() : Data.CmdDir; if (Real) CurDir = ConvertNameToReal(CurDir); if (Short) CurDir = ConvertNameToShort(CurDir); AddEndSlash(CurDir); return CurDir; }; if (const auto Tail = tokens::skip(CurStr, tokens::path)) { Out += GetPath(Tail, SubstData, false, false); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::short_path)) { Out += GetPath(Tail, SubstData, true, false); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::real_path)) { Out += GetPath(Tail, SubstData, false, true); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::real_short_path)) { Out += GetPath(Tail, SubstData, true, true); return Tail; } // !?<title>?<init>! if (const auto Tail = tokens::skip(CurStr, tokens::input)) { auto SkipSize = SkipInputToken(CurStr); // if bad format string skip 1 char if (!SkipSize) SkipSize = 1; Out.append(CurStr.data(), SkipSize); return CurStr.substr(SkipSize); } if (const auto Tail = tokens::skip(CurStr, tokens::name)) { append(Out, PointToName(SubstData.Default().Normal.NameOnly)); return Tail; } return CurStr; }
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); }