Frage

Wenn ich Createprocess verwenden Prozess adb.exe zu erstellen, wird es in ReadFile- blockieren.

void KillAdbProcess()
{
    DWORD aProcesses[1024], cbNeeded, cProcesses;
    unsigned int i;

    if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
        return;

    cProcesses = cbNeeded / sizeof(DWORD);

    for ( i = 0; i < cProcesses; i++ )
        if( aProcesses[i] != 0 ){
            bool shouldKill =false;
            wchar_t szProcessName[MAX_PATH] = L"<unknown>";

                //Get a handle to the process.
                HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
                                   PROCESS_VM_READ | PROCESS_TERMINATE,
                                   FALSE, aProcesses[i] );
                if (NULL != hProcess )
                {
                    HMODULE hMod;
                    DWORD cbNeeded;

                    if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), 
                         &cbNeeded) )
                    {
                        GetModuleFileNameExW( hProcess, hMod, szProcessName, 
                                           sizeof(szProcessName)/sizeof(TCHAR));
                        int len = wcslen(szProcessName);
                        if(!wcscmp(L"\\adb.exe",szProcessName+len-8)){
                            shouldKill = true;
                        }

                    }
                }

                if(shouldKill) TerminateProcess(hProcess,0);
                CloseHandle( hProcess );
        }

} 

int testadb(){
    KillAdbProcess();
    char buff[4096] = {0};
    int len = sizeof(buff);
    DWORD exitCode = 0;

    SECURITY_ATTRIBUTES   sa;   
    ZeroMemory(&sa, sizeof(sa)); 
    sa.bInheritHandle = TRUE;   
    sa.lpSecurityDescriptor = NULL;   
    sa.nLength = sizeof(sa);

    HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
    // Create the child output pipe.
    if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
        return false;

    // Create new output read handle and the input write handles. Set
    // the Properties to FALSE. Otherwise, the child inherits the
    // properties and, as a result, non-closeable handles to the pipes
    // are created.
    if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
        GetCurrentProcess(),
        &hOutputRead, // Address of new handle.
        0,FALSE, // Make it uninheritable.
        DUPLICATE_SAME_ACCESS))
        return false;

    // Close inheritable copies of the handles you do not want to be
    // inherited.
    if (!CloseHandle(hOutputReadTmp)) return false;


    PROCESS_INFORMATION  pi; 
    ZeroMemory(&pi, sizeof(pi));   
    STARTUPINFOW  si;
    GetStartupInfoW(&si);

    si.cb = sizeof(STARTUPINFO);
    si.dwFlags = STARTF_USESTDHANDLES;
    si.wShowWindow = SW_HIDE;
    si.hStdInput   = NULL;
    if(buff) {
        si.hStdOutput   =   hOutputWrite;   
        si.hStdError = hOutputWrite;
    } else {
        si.hStdOutput   =  NULL;   
        si.hStdError = NULL;
    }

    wchar_t cmdBuf[512] = L"adb.exe start-server";
    if( !::CreateProcessW(NULL, cmdBuf, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi) )
    {
        exitCode = -1;
        goto exit;
    }

    ::CloseHandle(hOutputWrite);
    hOutputWrite = NULL;

    len--; //keep it for string end char.
    DWORD dwBytes = 0;
    DWORD dwHasRead = 0;
    while(::ReadFile(hOutputRead, buff+dwHasRead, len-dwHasRead, &dwBytes, NULL))
    {
        printf("read byte=%d\n",dwBytes);
        if(0 == dwBytes) break;
        dwHasRead += dwBytes;
        //GetExitCodeProcess(pi.hProcess, &exitCode);
        //if(STILL_ACTIVE != exitCode) break;
        if(dwHasRead >= len) break;
    }
    buff[dwHasRead] = 0;


    ::GetExitCodeProcess(pi.hProcess, &exitCode);

exit:


    if(hOutputRead) ::CloseHandle(hOutputRead);
    if(hOutputWrite) ::CloseHandle(hOutputWrite);

    ::CloseHandle(pi.hProcess);
    ::CloseHandle(pi.hThread);
    return 0;
}

Wenn ich ändern Code

while(::ReadFile(hOutputRead, buff+dwHasRead, len-dwHasRead, &dwBytes, NULL))
{
    printf("read byte=%d\n",dwBytes);
    if(0 == dwBytes) break;
    dwHasRead += dwBytes;
    GetExitCodeProcess(pi.hProcess, &exitCode);
    if(STILL_ACTIVE != exitCode) break;
    if(dwHasRead >= len) break;
}

es funktioniert, aber wenn ich printf Code löschen, wird es wieder sperren.

while(::ReadFile(hOutputRead, buff+dwHasRead, len-dwHasRead, &dwBytes, NULL))
{
    if(0 == dwBytes) break;
    dwHasRead += dwBytes;
    GetExitCodeProcess(pi.hProcess, &exitCode);
    if(STILL_ACTIVE != exitCode) break;
    if(dwHasRead >= len) break;
}

Im Code von adb.exe sehe ich einige Code wie belows:

#if ADB_HOST
int launch_server()
{
#ifdef HAVE_WIN32_PROC
    /* we need to start the server in the background                    */
    /* we create a PIPE that will be used to wait for the server's "OK" */
    /* message since the pipe handles must be inheritable, we use a     */
    /* security attribute                                               */
    HANDLE                pipe_read, pipe_write;
    SECURITY_ATTRIBUTES   sa;
    STARTUPINFO           startup;
    PROCESS_INFORMATION   pinfo;
    char                  program_path[ MAX_PATH ];
    int                   ret;

    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;

    /* create pipe, and ensure its read handle isn't inheritable */
    ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
    if (!ret) {
        fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
        return -1;
    }

    SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );

    ZeroMemory( &startup, sizeof(startup) );
    startup.cb = sizeof(startup);
    startup.hStdInput  = GetStdHandle( STD_INPUT_HANDLE );
    startup.hStdOutput = pipe_write;
    startup.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
    startup.dwFlags    = STARTF_USESTDHANDLES;

    ZeroMemory( &pinfo, sizeof(pinfo) );

    /* get path of current program */
    GetModuleFileName( NULL, program_path, sizeof(program_path) );

    ret = CreateProcess(
            program_path,                              /* program path  */
            "adb fork-server server",
                                    /* the fork-server argument will set the
                                       debug = 2 in the child           */
            NULL,                   /* process handle is not inheritable */
            NULL,                    /* thread handle is not inheritable */
            TRUE,                          /* yes, inherit some handles */
            DETACHED_PROCESS, /* the new process doesn't have a console */
            NULL,                     /* use parent's environment block */
            NULL,                    /* use parent's starting directory */
            &startup,                 /* startup info, i.e. std handles */
            &pinfo );

    CloseHandle( pipe_write );

    if (!ret) {
        fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
        CloseHandle( pipe_read );
        return -1;
    }

    CloseHandle( pinfo.hProcess );
    CloseHandle( pinfo.hThread );

    /* wait for the "OK\n" message */
    {
        char  temp[3];
        DWORD  count;

        ret = ReadFile( pipe_read, temp, 3, &count, NULL );
        CloseHandle( pipe_read );
        if ( !ret ) {
            fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
            return -1;
        }
        if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
            fprintf(stderr, "ADB server didn't ACK\n" );
            return -1;
        }
    }
#elif defined(HAVE_FORKEXEC)
    char    path[PATH_MAX];
    int     fd[2];

    // set up a pipe so the child can tell us when it is ready.
    // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
    if (pipe(fd)) {
        fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
        return -1;
    }
    get_my_path(path);
    pid_t pid = fork();
    if(pid < 0) return -1;

    if (pid == 0) {
        // child side of the fork

        // redirect stderr to the pipe
        // we use stderr instead of stdout due to stdout's buffering behavior.
        adb_close(fd[0]);
        dup2(fd[1], STDERR_FILENO);
        adb_close(fd[1]);

        // child process
        int result = execl(path, "adb", "fork-server", "server", NULL);
        // this should not return
        fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
    } else  {
        // parent side of the fork

        char  temp[3];

        temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
        // wait for the "OK\n" message
        adb_close(fd[1]);
        int ret = adb_read(fd[0], temp, 3);
        adb_close(fd[0]);
        if (ret < 0) {
            fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", errno);
            return -1;
        }
        if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
            fprintf(stderr, "ADB server didn't ACK\n" );
            return -1;
        }

        setsid();
    }
#else
#error "cannot implement background server start on this platform"
#endif
    return 0;
}
#endif

ich glaube, das Kind Prozess der adb.exe inherit der Griff adb.exe, wenn das Kind Prozess der adb.exe nicht beendet, wird ReadFile- immer blockieren. Aber wenn ich "adb.exe Start-Server" in Befehl exec, ist alles Ok. Wie funktioniert Windows Aufruf Createprocess Befehl und ReadFile-?

War es hilfreich?

Lösung

Ich habe die Antwort gefunden: Umleiten von einer beliebigen Konsole des Input / Output - Codeproject .

  

Die Technik der Eingabe / Ausgabe eines Konsole Prozess der Umleitung ist sehr Beispiel: Die Createprocess () API durch die STARTUP Struktur ermöglicht es uns, die Standard-Griffe eines Kindes Konsole basierten Prozess umzuleiten. So können wir diese Griffe entweder ein Rohr Griff, Datei-Handle oder jeder Handgriff festgelegt, dass wir lesen und schreiben können. Die Einzelheiten dieser Technik hat sich deutlich in MSDN beschrieben: HOWTO:. Spawn Console Prozesse mit umgeleiteten Standard-Handles

     

Allerdings MSDN-Beispielcode hat zwei großes Problem. Erstens nimmt das Kind Prozessausgang zunächst senden wird, dann für die Eingabe wartet, dann den Ausgangspuffer und Ausgang spülen. Wenn das Kind Prozess so verhält sich nicht, wird der übergeordnete Prozess aufgehängt werden. Der Grund hierfür ist die Readfile () Funktion bleibt, bis blockiert das Kind Prozess eine Ausgabe sendet, oder beendet wird.

     

Zweitens hat es Problem, eine 16-Bit-Konsole zu umleiten unter Windows 9x, ReadFile- bleibt blockiert, selbst nachdem das Kind Prozess beendet hat (einschließlich Konsolen MS-DOS-Anwendungen.); Unter Windows NT / XP, kehrt ReadFile- immer FALSCH mit dem Fehlercode Satz ERROR_BROKEN_PIPE, wenn das Kind Prozess eine DOS-Anwendung ist.

     

Die Lösung des Block Problem der ReadFile-

     

, um den übergeordneten Prozess zu verhindern, dass durch ReadFile- blockiert wird, können wir einfach ein Datei-Handle als stdout dem Kind Prozess übergeben, dann diese Datei überwachen. Ein einfacher Weg ist PeekNamedPipe () Funktion aufrufen, bevor Readfile () aufrufen. Die Funktion prüft PeekNamedPipe Informationen über Daten, die in dem Rohr, kehren dann sofort. Wenn es keine Daten verfügbar ist in dem Rohr nicht ReadFile- nennen.

     

Durch den Aufruf PeekNamedPipe vor ReadFile-, wir lösen auch das Block Problem eine 16-Bit-Konsole auf Windows 9x von umgeleitet wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top