1

(必要に応じてZスナップを実行すると、気分が明るくなります)

少なくともその一部については、飛び込むことにしたこの新しいプロジェクトで、私は自分の快適ゾーンからはほど遠い.

プロジェクト全体は、TeamSpeak 3 にロードできる DLL であり、人々が (小さなコマンド セットを介して) ピアノバー (Pandora コマンド ライン プレーヤー) を制御できるようにします。

ここでの答えは、ピアノバー(コンソールアプリケーション)https://stackoverflow.com/a/17502224/1733365を起動して実行するのに十分なほど私を導きました.STDOUTを取得でき、曲の現在の表示位置まで表示されます時間、およびユーザー入力を受け入れる場所。その時点でプロセス全体がロックされます。おそらく、ReadFromPipe() コマンドは、その行が更新され続けているため、読み取る必要があると考えているためです。

外部スレッドから呼び出せるようにするために、最初の WriteToPipe(void) を WriteToPipe(char *cmd) にオーバーライドすることにも挑戦しました。(特定のコマンドについて、TeamSpeak 3 サーバーのチャットをリッスンするもの。)

現在、私のコードは非常に混乱していますが、少し整理したので、誰かが私を理解するのを手伝ってくれることを願っています.

本当にこれは、私が学校を休んでいる間にしようと決めた夏のプロジェクトであり、DLL を作成するのは初めての経験です。

Windows用ピアノバー

以下のコードの多くは、「リダイレクトされた入力と出力を使用した子プロセスの作成」から抜粋したものです。

#include "pianobar.h"
//#include <windows.h> 
//#include <tchar.h>
//#include <stdio.h> 
#include <strsafe.h>
//#include <stdlib.h>
//#include <sys/types.h>
//#include <string.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;
PROCESS_INFORMATION piProcInfo; 
STARTUPINFO siStartInfo;
SECURITY_ATTRIBUTES saAttr; 

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

int pianobar (struct TS3Functions ts3Functions) {
    int iFound = 0;

    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(); 

    // 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.

    // This should cause a help menu to be displayed on the next ReadFromPipe()
    // However, ReadFromPipe() doesn't show help commands
    //WriteToPipe("?\r\n"); 

    // Read from pipe that is the standard output for child process. 
    // Reading causes a lock.
    //ReadFromPipe(); 


    printf("\n->End of parent execution.\n");
    printf("\n->Pianobar started.\n");
    iFound = 1;
    return iFound;
}

void CloseChildProcess() {
    //CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProcInfo.hThread);
    TerminateProcess(piProcInfo.hProcess,0);
}

void CreateChildProcess()
    // Create a child process that uses the previously created pipes for STDIN and STDOUT.
{ 
    TCHAR szCmdline[]=TEXT("c:\\pianobar\\pianobar.exe");
    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, 
        szCmdline,     // command line 
        NULL,          // process security attributes 
        NULL,          // primary thread security attributes 
        TRUE,          // handles are inherited 
        0,             // creation flags 
        NULL,          // use parent's environment 
        TEXT("c:\\pianobar\\"),          // 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. 

        // I think I need these while I'm running...
        //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; 
    DWORD dw;
    CHAR chBuf[BUFSIZE];
    BOOL bSuccess = FALSE;
    LPTSTR lpTStr;

    printf("\n-> In WriteToPipe()\n");
    bSuccess = WriteFile(g_hChildStd_IN_Wr, command, sizeof(command), &dwWritten, NULL);
        if(bSuccess) {
            printf("bSuccess was TRUE\n->Sent: ");
            printf(command);
        } else {
            printf("bSuccess was FALSE\n");
        }

        // Close the pipe handle so the child process stops reading. 
        // my 2nd call to WriteToPipe results in a "The handle is invalid" error
        if ( ! CloseHandle(g_hChildStd_IN_Wr) ) {

        dw = GetLastError(); 
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | 
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            dw,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR) &lpTStr,
            0, NULL );
            printf(lpTStr);
        }
        if(command == "q\r\n") {
            printf("Quit received.\n");
            // this should have killed the process if it was received correctly...
            CloseChildProcess();
        }
} 

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);

    printf("\n-> In ReadFromPipe()\n");
    for (;;) 
    { 
        bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
        if( ! bSuccess || dwRead == 0 ) break; 
        printf("In ReadFromPipe loop\n");
        bSuccess = WriteFile(hParentStdOut, chBuf, 
            dwRead, &dwWritten, NULL);
        if (! bSuccess ) { 
            // we never get to this, it just waits...
            printf("Leaving loop\n");
            break; 
        }
    } 
} 

void ErrorExit(PTSTR lpszFunction) 

    // Format a readable error message, display a message box, 
    // and exit from the application.
{ 
    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);
}
4

1 に答える 1

1

私はあなたの設定をよく理解していませんでしたが、これに関して:

...そして、ユーザー入力を受け入れる場所でもあります。その時点でプロセス全体がロックされます。おそらく、ReadFromPipe() コマンドは、その行が更新され続けているため、読み取る必要があると考えているためです。

その可能性は非常に高いです。パイプから読み取るものが何もない場合、プロセスはブロックされます。つまり、ReadFile() 呼び出し内でスタックします。読み取るものがある場合にのみ読み取りたい場合は、非同期 I/O または通知メカニズムが必要です。Windows についてはよくわかりませんが、IO Completion Ports (IOCP) と非同期コールバック関数が利用できるようです。たぶん、これらのリンクが役立ちます:

Windowsで最高のepoll/kqueue/select equivalientは何ですか?

IOCP と ReadFileEx の使用

于 2013-07-10T07:13:43.303 に答える