Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/151.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ CreateProcess cmd.exe读/写管道死锁_C++_Winapi_Cmd - Fatal编程技术网

C++ CreateProcess cmd.exe读/写管道死锁

C++ CreateProcess cmd.exe读/写管道死锁,c++,winapi,cmd,C++,Winapi,Cmd,你好,我正在尝试为cmd.exe制作一个前端GUI,这样我就可以使它更宽,但我被卡住了 我试图设计一个这样的API char* Directory = WriteCommand("dir"); printf("- %s\n", Directory); 输出看起来和cmd窗口中的完全一样,只是我把它放在字符串中,所以它是 DATE TIME FILESIZE FILENAME etc etc etc 然后我可以发布 char* Up = WriteCommand ("cd .."); 它会给

你好,我正在尝试为cmd.exe制作一个前端GUI,这样我就可以使它更宽,但我被卡住了

我试图设计一个这样的API

char* Directory = WriteCommand("dir");
printf("- %s\n", Directory);
输出看起来和cmd窗口中的完全一样,只是我把它放在字符串中,所以它是

DATE TIME FILESIZE FILENAME
etc etc etc
然后我可以发布

char* Up = WriteCommand ("cd ..");
它会给我上面的目录列表。所以我想要一个终端控件,通过使用管道进行读写

基于此MSDN示例代码,我尝试了很多方法-

但我认为这段代码只适用于发出一个命令并读取一个响应,因为在它死锁之后,正如这里所描述的-

我在这里看到了其他几个问题,比如这个问题,也有类似的问题,但没有一个解决方案适合我

这是我的代码

#include <windows.h> 
#include <tchar.h>
#include <stdio.h> 
#include <strsafe.h>

#define BUFSIZE 4096 

HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;

HANDLE g_hInputFile = NULL;

void CreateChildProcess(void);
void WriteToPipe(char* Arg1);
void ReadFromPipe(void);
void ErrorExit(PTSTR);



int _tmain(int argc, TCHAR *argv[])
{
    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"));

    // Create the child process. 

    CreateChildProcess();

    // Get a handle to an input file for the parent. 
    // This example assumes a plain text file and uses string output to verify data flow. 

/*if (argc == 1)
    ErrorExit(TEXT("Please specify an input file.\n"));

g_hInputFile = CreateFile(
    argv[1],
    GENERIC_READ,
    0,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_READONLY,
    NULL);

if (g_hInputFile == INVALID_HANDLE_VALUE)
    ErrorExit(TEXT("CreateFile"));*/

    // Write to the pipe that is the standard input for a child process. 
    // Data is written to the pipe's buffers, so it is not necessary to wait
    // until the child process is running before writing data.



// Read from pipe that is the standard output for child process. 


ReadFromPipe();

WriteToPipe("ipconfig");

// THIS IS WHERE DEADLOCK OCCURS, FROM HERE
// PROGRAM BECOMES UNRESPONSIVE - HOW TO FIX THIS?

ReadFromPipe();



printf("\n->End of parent execution.\n");

// The remaining open handles are cleaned up when this process terminates. 
// To avoid resource leaks in a larger application, close handles explicitly. 

return 0;
}

void CreateChildProcess()
// Create a child process that uses the previously created pipes for     STDIN and STDOUT.
{
   TCHAR szCmdline[] = TEXT("cmd.exe /k");
    PROCESS_INFORMATION piProcInfo;
   STARTUPINFO siStartInfo;
   BOOL bSuccess = FALSE;

    // Set up members of the PROCESS_INFORMATION structure. 

    ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

   // Set up members of the STARTUPINFO structure. 
  // This structure specifies the STDIN and STDOUT handles for redirection.

    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;

// Create the child process. 

bSuccess = CreateProcess(NULL,
    "cmd.exe",     // command line 
    NULL,          // process security attributes 
    NULL,          // primary thread security attributes 
    TRUE,          // handles are inherited 
    0,             // creation flags 
    NULL,          // use parent's environment 
    NULL,          // use parent's current directory 
    &siStartInfo,  // STARTUPINFO pointer 
    &piProcInfo);  // receives PROCESS_INFORMATION 

                   // If an error occurs, exit the application. 
if (!bSuccess)
    ErrorExit(TEXT("CreateProcess"));
else
{
    // Close handles to the child process and its primary thread.
    // Some applications might keep these handles to monitor the status
    // of the child process, for example. 

    CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProcInfo.hThread);
}
}

void WriteToPipe(char* Command)

// Read from a file and write its contents to the pipe for the    child's STDIN.
// Stop when there is no more data. 
   {
   DWORD dwRead, dwWritten;
    CHAR chBuf[BUFSIZE];
    BOOL bSuccess = FALSE;

    bSuccess = WriteFile(g_hChildStd_IN_Wr, Command, strlen(Command), &dwWritten, NULL);
    if (bSuccess == FALSE)
        printf("write fail\n");

    printf("written = %i\n", dwWritten);


//for (;;)
//{
    //bSuccess = ReadFile(g_hInputFile, chBuf, BUFSIZE, &dwRead, NULL);
    //if (!bSuccess || dwRead == 0) break;

    //bSuccess = WriteFile(g_hChildStd_IN_Wr, Command, strlen(Command), &dwWritten, NULL);
    //if (bSuccess == FALSE)
        //printf("write fail\n");

    //printf("written = %i\n", dwWritten);
//}

// Close the pipe handle so the child process stops reading. 

//if (!CloseHandle(g_hChildStd_IN_Wr))
    //ErrorExit(TEXT("StdInWr CloseHandle"));
}

void ReadFromPipe(void)

// Read output from the child process's pipe for STDOUT
// and write to the parent process's pipe for STDOUT. 
// Stop when there is no more data. 
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

int i;

for (i = 0; i < 4; i++)
{

    /*DWORD dwAvail = 0;
    if (!PeekNamedPipe(g_hChildStd_OUT_Rd, NULL, 0, NULL, &dwAvail, NULL)) {
        // error, the child process might have ended
        break;
    }
    if (!dwAvail) {
        // no data available in the pipe
        break;
    }*/

    bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
    if (!bSuccess || dwRead == 0) break;

    /*bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
    if (!bSuccess) break;*/

    chBuf[dwRead] = '\0';

    printf("%i - %s\n", i, chBuf);
}

printf("done\n");
}
#包括
#包括
#包括
#包括
#定义BUFSIZE 4096
句柄g_hChildStd_IN_Rd=NULL;
句柄g_hChildStd_IN_Wr=NULL;
HANDLE g_hChildStd_OUT_Rd=NULL;
句柄g_hChildStd_OUT_Wr=NULL;
HANDLE g_hInputFile=NULL;
void-CreateChildProcess(void);
无效写入管道(字符*Arg1);
管道中的空隙读数(空隙);
无效错误退出(PTSTR);
int_tmain(int argc,TCHAR*argv[])
{
安全属性saAttr;
printf(“\n->开始父执行。\n”);
//设置bInheritHandle标志,以便继承管道句柄。
saAttr.nLength=sizeof(安全属性);
saAttr.bInheritHandle=TRUE;
saAttr.lpSecurityDescriptor=NULL;
//为子进程的标准输出创建管道。
如果(!CreatePipe(&g_-hchildsd_-OUT_-Rd,&g_-hchildsd_-OUT_-Wr,&saAttr,0))
ErrorExit(文本(“StdoutRd CreatePipe”);
//确保未继承STDOUT管道的读取句柄。
if(!SetHandleInformation(g_hchildsd_OUT_Rd,HANDLE_FLAG_INHERIT,0))
ErrorExit(文本(“标准输出设置句柄信息”);
//为子进程的STDIN创建管道。
如果(!CreatePipe(&g_hChildStd_IN_Rd,&g_hChildStd_IN_Wr,&saAttr,0))
ErrorExit(文本(“stdincreatepipe”);
//确保未继承STDIN管道的写入句柄。
if(!SetHandleInformation(g_hchildsd_IN_Wr,HANDLE_FLAG_INHERIT,0))
ErrorExit(文本(“标准输入设置句柄信息”);
//创建子进程。
CreateChildProcess();
//获取父级输入文件的句柄。
//此示例假定为纯文本文件,并使用字符串输出来验证数据流。
/*如果(argc==1)
ErrorExit(文本(“请指定输入文件。\n”);
g_hInputFile=CreateFile(
argv[1],,
泛读,
0,
无效的
开放式,
文件\属性\只读,
无效);
if(g\u hInputFile==无效的\u句柄\u值)
错误退出(文本(“创建文件”)*/
//写入作为子进程标准输入的管道。
//数据被写入管道的缓冲区,因此无需等待
//直到子进程运行后,才能写入数据。
//从作为子进程标准输出的管道中读取。
ReadFromPipe();
WriteToPipe(“ipconfig”);
//这就是死锁发生的地方,从这里开始
//程序变得无响应-如何修复此问题?
ReadFromPipe();
printf(“\n->父执行结束。\n”);
//此进程终止时,剩余的打开句柄将被清除。
//为了避免大型应用程序中的资源泄漏,请显式关闭句柄。
返回0;
}
void CreateChildProcess()
//创建一个子进程,该子进程使用先前为STDIN和STDOUT创建的管道。
{
TCHAR szCmdline[]=文本(“cmd.exe/k”);
处理信息piProcInfo;
STARTUPINFO-siStartInfo;
BOOL bsucces=假;
//设置流程信息结构的成员。
零内存(&piProcInfo,sizeof(进程信息));
//设置STARTUPINFO结构的成员。
//此结构指定重定向的STDIN和STDOUT句柄。
ZeroMemory(&siStartInfo,sizeof(STARTUPINFO));
siStartInfo.cb=sizeof(STARTUPINFO);
siStartInfo.hStdError=g_hchildsd_OUT_Wr;
siStartInfo.hStdOutput=g_hchildsd_OUT_Wr;
siStartInfo.hStdInput=g_hChildStd_IN_Rd;
siStartInfo.dwFlags |=STARTF_USESTDHANDLES;
//创建子进程。
bSuccess=CreateProcess(空,
“cmd.exe”,//命令行
NULL,//进程安全属性
NULL,//主线程安全属性
TRUE,//句柄被继承
0,//创建标志
NULL,//使用父环境
NULL,//使用父级的当前目录
&siStartInfo,//STARTUPINFO指针
&piProcInfo);//接收进程信息
//如果发生错误,请退出应用程序。
如果(!b成功)
ErrorExit(文本(“CreateProcess”);
其他的
{
//关闭子进程及其主线程的句柄。
//某些应用程序可能保留这些句柄以监视状态
//例如,子进程的。
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
}
}
void WriteToPipe(char*命令)
//从文件中读取并将其内容写入孩子的STDIN的管道。
//没有更多数据时停止。
{
德沃德·德雷德,德沃德·书面;
CHAR chBuf[BUFSIZE];
BOOL bsucces=假;
bSuccess=WriteFile(g_hChildStd_IN_Wr,Command,strlen(Command),&dwwrited,NULL);
if(bSuccess==FALSE)
printf(“写入失败\n”);
printf(“writed=%i\n”,dwwrited);
//对于(;;)
//{
//bSuccess=ReadFile(g_hInputFile,chBuf,BUFSIZE,&dwRead,NULL);
//如果(!bsucces | | dwRead==0)中断;
//bSuccess=WriteFile(g_hChildStd_IN_Wr,Command,strlen(Command),&dwwrited,NULL);
//if(bSuccess==FALSE)
//printf(“写入失败\n”);
//printf(“writed=%i\n”,dwwrited);
//}
//关闭管道句柄,使子进程停止读取。
//如果(!CloseHandle(g_hChildStd_IN_Wr))
//ErrorExit(文本(“StdInWr CloseHandle”);
}
void ReadFromPipe(void)
//从子进程的管道读取标准输出
/和写入PAR
#define _XP_SUPPORT_

struct IO_COUNT 
{
    HANDLE _hFile;
    HANDLE _hEvent;
    LONG _dwIoCount;

    IO_COUNT()
    {
        _dwIoCount = 1;
        _hEvent = 0;
    }

    ~IO_COUNT()
    {
        if (_hEvent)
        {
            CloseHandle(_hEvent);
        }
    }

    ULONG Create(HANDLE hFile);

    void BeginIo()
    {
        InterlockedIncrement(&_dwIoCount);
    }

    void EndIo()
    {
        if (!InterlockedDecrement(&_dwIoCount))
        {
            SetEvent(_hEvent);
        }
    }

    void Wait()
    {
        WaitForSingleObject(_hEvent, INFINITE);
    }
};


struct U_IRP : OVERLAPPED 
{
    enum { read, write };

    IO_COUNT* _pIoObject;
    ULONG _code;
    LONG _dwRef;
    char _buffer[256];

    void AddRef()
    {
        InterlockedIncrement(&_dwRef);
    }

    void Release()
    {
        if (!InterlockedDecrement(&_dwRef)) delete this;
    }

    U_IRP(IO_COUNT* pIoObject) : _pIoObject(pIoObject)
    {
        _dwRef = 1;
        pIoObject->BeginIo();
        RtlZeroMemory(static_cast<OVERLAPPED*>(this), sizeof(OVERLAPPED));
    }

    ~U_IRP()
    {
        _pIoObject->EndIo();
    }

    ULONG CheckIoResult(BOOL fOk)
    {
        if (fOk)
        {
#ifndef _XP_SUPPORT_
            OnIoComplete(NOERROR, InternalHigh);
#endif
            return NOERROR;
        }

        ULONG dwErrorCode = GetLastError();

        if (dwErrorCode != ERROR_IO_PENDING)
        {
            OnIoComplete(dwErrorCode, 0);
        }

        return dwErrorCode;
    }

    ULONG Read()
    {
        _code = read;

        AddRef();

        return CheckIoResult(ReadFile(_pIoObject->_hFile, _buffer, sizeof(_buffer), 0, this));
    }

    ULONG Write(const void* pvBuffer, ULONG cbBuffer)
    {
        _code = write;

        AddRef();

        return CheckIoResult(WriteFile(_pIoObject->_hFile, pvBuffer, cbBuffer, 0, this));
    }

    VOID OnIoComplete(DWORD dwErrorCode, DWORD_PTR dwNumberOfBytesTransfered)
    {
        switch (_code)
        {
        case read:
            if (dwErrorCode == NOERROR)
            {
                if (dwNumberOfBytesTransfered)
                {
                    if (int cchWideChar = MultiByteToWideChar(CP_OEMCP, 0, _buffer, (ULONG)dwNumberOfBytesTransfered, 0, 0))
                    {
                        PWSTR wz = (PWSTR)alloca(cchWideChar * sizeof(WCHAR));

                        if (MultiByteToWideChar(CP_OEMCP, 0, _buffer, (ULONG)dwNumberOfBytesTransfered, wz, cchWideChar))
                        {
                            if (int cbMultiByte = WideCharToMultiByte(CP_ACP, 0, wz, cchWideChar, 0, 0, 0, 0))
                            {
                                PSTR sz = (PSTR)alloca(cbMultiByte);

                                if (WideCharToMultiByte(CP_ACP, 0, wz, cchWideChar, sz, cbMultiByte, 0, 0))
                                {
                                    DbgPrint("%.*s", cbMultiByte, sz);
                                }
                            }
                        }
                    }
                }
                Read();
            }
            break;
        case write:
            break;
        default:
            __debugbreak();
        }

        Release();

        if (dwErrorCode)
        {
            DbgPrint("[%u]: error=%u\n", _code, dwErrorCode);
        }
    }

    static VOID WINAPI _OnIoComplete(
        DWORD dwErrorCode,
        DWORD_PTR dwNumberOfBytesTransfered,
        LPOVERLAPPED lpOverlapped
        )
    {
        static_cast<U_IRP*>(lpOverlapped)->OnIoComplete(RtlNtStatusToDosError(dwErrorCode), dwNumberOfBytesTransfered);
    }
};

ULONG IO_COUNT::Create(HANDLE hFile)
{
    _hFile = hFile;
    // error in declaration LPOVERLAPPED_COMPLETION_ROUTINE : 
    // second parameter must be DWORD_PTR but not DWORD
    return BindIoCompletionCallback(hFile, (LPOVERLAPPED_COMPLETION_ROUTINE)U_IRP::_OnIoComplete, 0) && 
#ifndef _XP_SUPPORT_
        SetFileCompletionNotificationModes(hFile, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) &&
#endif
        (_hEvent = CreateEvent(0, TRUE, FALSE, 0)) ? NOERROR : GetLastError();
}

void ChildTest()
{
    static const WCHAR name[] = L"\\\\?\\pipe\\somename";

    HANDLE hFile = CreateNamedPipeW(name, 
        PIPE_ACCESS_DUPLEX|FILE_READ_DATA|FILE_WRITE_DATA|FILE_FLAG_OVERLAPPED, 
        PIPE_TYPE_BYTE|PIPE_READMODE_BYTE, 1, 0, 0, 0, 0);

    if (hFile != INVALID_HANDLE_VALUE)
    {
        IO_COUNT obj;

        if (obj.Create(hFile) == NOERROR)
        {
            BOOL fOk = FALSE;

            SECURITY_ATTRIBUTES sa = { sizeof(sa), 0, TRUE };

            STARTUPINFOW si = { sizeof(si) };
            PROCESS_INFORMATION pi;

            si.dwFlags = STARTF_USESTDHANDLES;

            si.hStdError = CreateFileW(name, FILE_GENERIC_READ|FILE_GENERIC_WRITE, 
                FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0);

            if (si.hStdError != INVALID_HANDLE_VALUE)
            {
                si.hStdInput = si.hStdOutput = si.hStdError;

                WCHAR ApplicationName[MAX_PATH];
                if (GetEnvironmentVariableW(L"ComSpec", ApplicationName, RTL_NUMBER_OF(ApplicationName)))
                {
                    if (CreateProcessW(ApplicationName, 0, 0, 0, TRUE, 0, 0, 0, &si, &pi))
                    {
                        CloseHandle(pi.hThread);
                        CloseHandle(pi.hProcess);
                        fOk = TRUE;
                    }
                }

                CloseHandle(si.hStdError);
            }

            if (fOk)
            {
                STATIC_ASTRING(help_and_exit, "help\r\nexit\r\n");

                U_IRP* p;

                if (p = new U_IRP(&obj))
                {
                    p->Read();
                    p->Release();
                }

                obj.EndIo();

                //++ simulate user commands
                static PCSTR commands[] = { "help\r\n", "ver\r\n", "dir\r\n", "exit\r\n" };
                ULONG n = RTL_NUMBER_OF(commands);
                PCSTR* psz = commands;
                do 
                {
                    if (MessageBoxW(0,0, L"force close ?", MB_YESNO) == IDYES)
                    {
                        DisconnectNamedPipe(hFile);
                        break;
                    }
                    if (p = new U_IRP(&obj))
                    {
                        PCSTR command = *psz++;
                        p->Write(command, (ULONG)strlen(command) * sizeof(CHAR));
                        p->Release();
                    }    
                } while (--n);
                //--

                obj.Wait();
            }
        }

        CloseHandle(hFile);
    }
}