我正在编码一个WinAPI GUI程序,该程序需要调用 ftp 以及可能的其他控制台程序,同时使它们的控制台输出相应地起作用。等待ftp完成执行,然后再读取其所有输出。
我当前的方法是调用import java.util.Arrays;
import java.util.Enumeration;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
public class Test {
public static void main(String[] args) {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("~");
DefaultTreeModel model = new DefaultTreeModel(root);
DefaultMutableTreeNode docs = new DefaultMutableTreeNode("Documents");
docs.add(new DefaultMutableTreeNode("text1.txt"));
docs.add(new DefaultMutableTreeNode("text2.txt"));
root.add(docs);
DefaultMutableTreeNode pics = new DefaultMutableTreeNode("Pictures");
pics.add(new DefaultMutableTreeNode("text1.txt"));
root.add(pics);
describe(model);
DefaultMutableTreeNode newFolder = new DefaultMutableTreeNode("folder1");
newFolder.add(new DefaultMutableTreeNode("text1.txt"));
insertNodes(model, findNode(model, "~/Pictures"), newFolder);
describe(model);
}
protected static DefaultMutableTreeNode findNode(DefaultTreeModel model, String path) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) model.getRoot();
String[] parts = path.split("/");
if (node.getUserObject().toString().equals(parts[0])) {
return findNode(node, Arrays.copyOfRange(parts, 1, parts.length));
}
return null;
}
protected static DefaultMutableTreeNode findNode(DefaultMutableTreeNode node, String[] path) {
if (path.length == 0) {
return node;
}
Enumeration<TreeNode> children = node.children();
while (children.hasMoreElements()) {
DefaultMutableTreeNode child = (DefaultMutableTreeNode) children.nextElement();
if (child.getUserObject().toString().equals(path[0])) {
return findNode(child, Arrays.copyOfRange(path, 1, path.length));
}
}
return null;
}
private static void insertNodes(
DefaultTreeModel model,
DefaultMutableTreeNode parent,
DefaultMutableTreeNode newNode) {
parent.add(newNode);
model.nodesWereInserted(parent, new int[]{parent.getChildCount() - 1});
}
protected static void describe(DefaultTreeModel model) {
describe((DefaultMutableTreeNode) model.getRoot(), 0);
}
protected static void describe(DefaultMutableTreeNode node, int level) {
StringBuilder padding = new StringBuilder();
for (int index = 0; index < level; index++) {
padding.append(" ");
}
System.out.println(padding + "+ " + node);
padding.append(" ");
Enumeration<TreeNode> children = node.children();
while (children.hasMoreElements()) {
DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) children.nextElement();
if (childNode.isLeaf()) {
System.out.println(padding + "- " + childNode);
} else {
describe(childNode, level + 1);
}
}
}
}
创建一个 cmd.exe 进程,该进程可能隐藏丑陋的控制台窗口CreateProcess()
,使其成为我自己的AttachConsole()
获取输入和输出句柄,GetStdHandle()
到达控制台缓冲区的末尾,SetConsoleCursorPosition()
使用诸如 ftp \ n 或 dir \ n 。但是,该命令已写入但未执行。但是,我可以手动使用同一控制台(将WriteConsole()
与CreateProcess()
标志一起使用)键入 ftp ,然后按enter键并使其执行。
涉及的先前方法:
CREATE_NEW_CONSOLE
调用 ftp 并重定向输入/输出。
在
CreateProcess()
进程结束之前,无法获得 ftp 输出。
CreateProcess()
。
在获得任何输出之前,建议不要使用它。
我当前的精简代码:
system()
如何获取在控制台中编写的命令以执行?除了用结尾的// Next two structures might be a bit misleading, they were used for the 1. previous
// approach
PROCESS_INFORMATION piProcInfo;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION));
STARTUPINFO siStartInfo;
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
SECURITY_ATTRIBUTES security;
security.nLength = sizeof(SECURITY_ATTRIBUTES);
security.lpSecurityDescriptor = NULL;
security.bInheritHandle = FALSE;
CreateProcess( NULL, "cmd", &security, &security, FALSE, NORMAL_PRIORITY_CLASS |
CREATE_NEW_CONSOLE, NULL, NULL, &siStartInfo, &piProcInfo);
uint32_t pidConsole = piProcInfo.dwProcessId;
while ( ! AttachConsole(pidConsole) ){};
HANDLE myConsoleIn, myConsoleOut;
myConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
myConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
Sleep(100);
CONSOLE_SCREEN_BUFFER_INFO myConsoleCursorInformation = {};
GetConsoleScreenBufferInfo(myConsoleOut,&myConsoleCursorInformation);
SetConsoleCursorPosition(myConsoleOut,myConsoleCursorInformation.dwSize);
CHAR myConsoleBuffer[200]="dir\n";
DWORD myConsoleProcessed;
WriteConsole( myConsoleOut, myConsoleBuffer, 4, &myConsoleProcessed, NULL);
ie结束命令之外,我还有其他选择吗? \n
和dir \ n或ftp \ n参数一起使用。
我考虑过在键入所需命令后将按键发送到相关进程。创建的控制台不仅需要手动按下Enter键,还需要具有 dir , ftp 或任何手动键入的命令。
请随时指出任何缺少的信息!
答案 0 :(得分:0)
如何获取在控制台中编写的命令以执行?有没有 替代我尝试以尾随\ n即结束命令的尝试。 使用带有dir \ n或ftp \ n参数的WriteConsole()。
尝试以下代码以查看其是否有效:
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
const wchar_t *cmdPath = L"C:\\Windows\\System32\\cmd.exe";
wchar_t *cmdArgs = (wchar_t *)L"C:\\Windows\\System32\\cmd.exe /k dir";
BOOL result = CreateProcess(cmdPath, cmdArgs, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
DWORD errCode = GetLastError();
if (!result)
{
std::cout << "Create Process failed: " << GetLastError() << std::endl;
}
/ K运行命令,然后返回到CMD提示符。 这对于测试,检查变量很有用
如果要“运行命令然后终止”,请使用/ C。
更新:用于使用管道与子进程(cmd.exe)通信的完整代码。
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
#define BUFSIZE 1024
void ErrorExit(LPCTSTR lpszFunction)
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL);
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(1);
}
void ReadFromPipe(void)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
for (;;)
{
DWORD bytesAvail = 0;
if (!PeekNamedPipe(g_hChildStd_OUT_Rd, NULL, 0, NULL, &bytesAvail, NULL)) {
std::cout << "Failed to call PeekNamedPipe" << std::endl;
}
if (bytesAvail) {
DWORD n;
BOOL success = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &n, NULL);
if (!success || n == 0) {
}
bSuccess = WriteFile(hParentStdOut, chBuf,n, &dwWritten, NULL);
}
else
{
break;
}
}
}
void WriteToPipe(void)
{
DWORD dwWritten;
BOOL bSuccess = FALSE;
CHAR buf[] = "dir\n";
bSuccess = WriteFile(g_hChildStd_IN_Wr, buf, sizeof(buf)-1, &dwWritten, NULL);
}
int main()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES saAttr;
printf("\n->Start of parent execution.\n");
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
ErrorExit(TEXT("StdoutRd CreatePipe"));
// Ensure the read handle to the pipe for STDOUT is not inherited.
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
ErrorExit(TEXT("Stdout SetHandleInformation"));
// Create a pipe for the child process's STDIN.
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
ErrorExit(TEXT("Stdin CreatePipe"));
// Ensure the write handle to the pipe for STDIN is not inherited.
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
ErrorExit(TEXT("Stdin SetHandleInformation"));
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(STARTUPINFO);
si.hStdError = g_hChildStd_OUT_Wr;
si.hStdOutput = g_hChildStd_OUT_Wr;
si.hStdInput = g_hChildStd_IN_Rd;
si.dwFlags |= STARTF_USESTDHANDLES;
TCHAR cmdPath[] = TEXT("C:\\Windows\\System32\\cmd.exe");
BOOL result = CreateProcess(cmdPath, NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
DWORD errCode = GetLastError();
if (!result)
{
std::cout << "Create Process failed: " << GetLastError() << std::endl;
}
for (;;)
{
ReadFromPipe();
WriteToPipe();
}
}