📄 jcmd.c
字号:
/* jcmd.c - jEdit buffer properties: *//* :mode=c:tabSize=4:indentSize=4:noTabs=false:indentOnTab=false: *//* :indentOnEnter=true:syntax=true:maxLineLen=80: *//* * jcmd.c - A command interpreter for use with the Java's platform * Runtime.exec() on the Windows family of operating systems, designed * to prevent the display of console windows when executing console-based * programs; specifically designed to be used with jEdit's Console plugin * Copyright (C) 2001 John Gellene * jgellene@nyc.rr.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * Notwithstanding the terms of the General Public License, the author grants * permission to compile and link object code generated by the compilation of * this program with object code and libraries that are not subject to the * GNU General Public License, provided that the use and distribution of * the resulting library or executable file shall be subject to the General * Public License. This condition does not require a licensee of this software * to distribute any proprietary software (including header files and libraries) * that is licensed under terms prohibiting redistribution to third parties. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the jEdit program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id: jcmd.c,v 1.9 2001/09/16 22:59:30 jgellene Exp $ *//* * To compile this file use the following command line: * * cl /nologo /ML /W4 /O2 /Ox /D "WIN32" /D "NDEBUG" /D "_MBCS" jcmd.c \ * /link user32.lib advapi32.lib /subsystem:windows /version:2.0 \ * /entry:mainCRTStartup *//* suppress warning on automatic inline expansion */#pragma warning( disable : 4711)#include <windows.h>#include <stdlib.h>#include "jcmd.h"int main(int argc, char** argv){ PJCMD_EXEC_DATA pData; HANDLE hStdError = GetStdHandle(STD_ERROR_HANDLE); int nTestReturn, nReturn; if(argc < 2) { WriteMessage("jcmd error: no command given.", hStdError); return 1; } pData = LocalAlloc(LPTR, sizeof(JCMD_EXEC_DATA)); if(!InitJcmdData(pData, argc, argv)) { WriteMessage("jcmd error: command is not valid.", hStdError); ClearJcmdData(pData); LocalFree(pData); return 1; } /* * The file and path parameters can have the following combinations: * (1) Full path, full file name - execute SearchCommand once * (2) Full path, no extension - execute SearchCommand once for each * extension in pathext variable * (3) No path, full file name - execute SearchCommand for each directory * in path search using full path name * (4) No path, no extension - for each directory in search path, * execute SearchCommand for each extension in pathext variable */ if(pData->hasPath) { nTestReturn = TestSinglePath(pData); } else { nTestReturn = TestMultiPath(pData); } if(nTestReturn == 0) { WriteMessage("Could not find command.", hStdError); nReturn = 1; } else { nReturn = pData->nReturnCode; } ClearJcmdData(pData); LocalFree(pData); return nReturn;}/* * InitJcmdData() * Initializes application data using command line parameters * Returns 1 if initialization successful and 0 if first parameter * (path string) is empty or if no filename is found in path */int InitJcmdData(PJCMD_EXEC_DATA pData, int argc, char **argv){ // main() tests for argc < 2 char *pPath, *pFileName; int index; pPath = argv[1]; if(pData == 0 || pPath == 0 || *pPath == 0) return 0; /* Check for a path separator */ pData->hasPath = strchr(pPath, '\\') ? 1 : 0; if(pData->hasPath) { GetFullPathName(pPath, MAX_PATH, pData->execPath, &pFileName); if(pFileName == 0 || *pFileName == 0) return 0; strcpy(pData->execName, pFileName); // this will truncate pData->execPath memset(pFileName, 0, strlen(pFileName)); } else { strcpy(pData->execName, pPath); } /* Check file name for extension */ pData->hasExt = strchr(pData->execName, '.') ? 1 : 0; if(pData->hasExt) pData->isExec = IsExec(pPath); /* * Collect the rest of the command line as a single parameter. * The first character will be whitespace because later it will * be joined to a command string. */ if(argc > 2) { for(index = 2; index < argc; ++index) { /* Quote any command line item containing spaces */ char *pSpace = strchr(argv[index], ' '); pData->szParams[strlen(pData->szParams)] = ' '; if(pSpace != 0) strcat(pData->szParams, "\""); strcat(pData->szParams, argv[index]); if(pSpace != 0) strcat(pData->szParams, "\""); } } /* Load the search extensions from the environment or use default. */ if(!pData->hasExt) { if(!GetEnvironmentVariable("PATHEXT", pData->szPathExt, MAX_PATH)) { strcpy(pData->szPathExt, ".CMD;.BAT;.COM;.EXE"); } } /* If there is no file path, get the path environment variable. */ if(!pData->hasPath) { char test; DWORD dwPathLength = GetEnvironmentVariable("PATH", &test, 1); DWORD dwPathBufLength = ((dwPathLength / MAX_PATH) + 1) * MAX_PATH; pData->pPaths = LocalAlloc(LPTR, dwPathBufLength); if(dwPathLength - 1 != GetEnvironmentVariable("PATH", pData->pPaths, dwPathBufLength)) { LocalFree(pData->pPaths); pData->pPaths = 0; } } return 1;}/* * ClearJcmdData() * This performs cleanup of application data object before application exits; * it must be called if pPaths data member is created. */void ClearJcmdData(PJCMD_EXEC_DATA pData){ LocalFree(pData->pPaths);}/* * LaunchCommand() * This is the heart of the command interpreter. Once a file path is * found and tied to an existing file association, this function creates * a process using the fully interpreted command. The main window of the * process is hidden. The function then tests the top-level windows created * by the main thread of the new process to see if a console window has * been created. If no console window has been created, the application * being executed has a Windows GUI (which is now hidden). In that case, * LaunchCommand() closes the main window and restarts the process with * the main window displayed normally. Finally, the function waits for the * new process to exit and return the exit code back to jcmd's * calling function and eventually to its main routine. */int LaunchCommand(PJCMD_EXEC_DATA pData){ STARTUPINFO *psi = &(pData->si); PROCESS_INFORMATION *ppi = &(pData->pi); PTESTCONSOLE ptc = &(pData->tc); DWORD dwResult; if(*(pData->szParams) != 0) { strcat(pData->szCmd, " "); strcat(pData->szCmd, pData->szParams); } // initialize process startup information psi->cb = sizeof(STARTUPINFO); psi->dwFillAttribute = 0; psi->dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; psi->wShowWindow = SW_HIDE; //psi->hStdInput = GetStdHandle(STD_INPUT_HANDLE); psi->hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); psi->hStdError = GetStdHandle(STD_ERROR_HANDLE); if(!CreateProcess(NULL, pData->szCmd, NULL, NULL, TRUE, 0, NULL, NULL, psi, ppi)) { WriteProcessError(psi->hStdError); pData->nReturnCode = (DWORD)-1; return 1; } /* Make sure the process completed its startup */ WaitForInputIdle(ppi->hProcess, 1000); /* * Iterate over top-level windows of the thread * and look for a console. */ EnumThreadWindows(ppi->dwThreadId, FindConsoleWindow, (LPARAM)ptc); if(!FoundConsole(ptc)) { /* * This is a windows program. We will terminate it * as politely as possible and restart it with a normal * instead of a hidden main window. */ EnumThreadWindows(ppi->dwThreadId, CloseThreadWindow, 0); /* If we couldn't kill the window, we kill the process. */ dwResult = WaitForSingleObject(ppi->hThread, 0); if(dwResult == WAIT_TIMEOUT || dwResult == WAIT_ABANDONED) TerminateProcess(ppi->hProcess, 1); psi->wShowWindow = SW_SHOW; psi->dwFlags = STARTF_USESHOWWINDOW; /* A loop here is not necessary. */ if(!CreateProcess(NULL, pData->szCmd, NULL, NULL, TRUE, 0, NULL, NULL, psi, ppi)) { WriteProcessError(psi->hStdError); pData->nReturnCode = (DWORD)-1; return 1; } } /* Start thread to wait on input */ pData->hInputThread = CreateThread(0, 0, &InputThreadProc, (LPVOID)pData, 0, &(pData->nInputThreadID)); if(pData->hInputThread == 0) { WriteProcessError(GetStdHandle(STD_OUTPUT_HANDLE)); } else { WriteMessage("Thread created.\n", GetStdHandle(STD_OUTPUT_HANDLE)); } /* Now we wait for the process to end to get the return code. */ Sleep(2000); switch(WaitForSingleObject(ppi->hProcess,INFINITE)) { case WAIT_FAILED: case WAIT_ABANDONED: case WAIT_TIMEOUT: break; default: GetExitCodeProcess(ppi->hProcess, &(pData->nReturnCode)); } return 1;}/* * SearchCommand() * This function executes a single search for a file * based upon the information containined in the data object * and an optional file extensions. If the file is found, this * function directs substitution of file associations and * environment variables, then calls LaunchCommand() to execute * the fully interpreted command */int SearchCommand(PJCMD_EXEC_DATA pData, char* pExt){ char *pFilePart; if(SearchPath(pData->szTestPath, pData->execName, pExt, 1024, pData->szCmd, &pFilePart)) { strcpy(pData->szScratch, pData->szCmd); if(!IsExec(pFilePart)) { MakeFileAssoc(pData->szCmd, pData->szScratch); } else { ExpandEnvironmentStrings(pData->szScratch, pData->szCmd, 1024); } return LaunchCommand(pData); } return 0;}/* * TestSingleExt() * This wrapper function is used for a single file search when * the file's extension is specified. */int TestSingleExt(PJCMD_EXEC_DATA pData){ return SearchCommand(pData, 0);}/* * TestMultiExt() * This function iterates through all of the default * file extensions, calling SearchCommand() on the * command data object with each extension. It is used * with a specific file path when a file extension must be * supplied. */int TestMultiExt(PJCMD_EXEC_DATA pData){ int nReturn = 0; char *pExt = ExtractExt(pData->szTestExt, pData->szPathExt); while(pExt != 0 && *pExt != 0 && *(pData->szTestExt) != 0) { nReturn = SearchCommand(pData, pData->szTestExt); if(nReturn == 1) break; pExt = ExtractExt(pData->szTestExt, pExt); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -