Pergunta

Estou agrupando o código C++ existente de um BSD projeto em nosso próprio wrapper personalizado e quero integrá-lo ao nosso código com o mínimo de alterações possível.Este código usa fprintf imprimir para stderr para registrar/relatar erros.

Quero redirecionar isso para um local alternativo dentro do mesmo processo.Sobre Unix Eu fiz isso com um socketpair e um thread:uma extremidade do soquete é para onde eu envio stderr (através de uma chamada para dup2) e a outra extremidade é monitorada em um thread, onde posso processar a saída.

Isso não funciona janelas embora porque um soquete não seja o mesmo que um identificador de arquivo.

Todos os documentos que encontrei na web mostram como redirecionar a saída de um processo filho, o que não é o que desejo.Como posso redirecionar stderr dentro do mesmo processo, obtendo algum tipo de retorno de chamada quando a saída é gravada?(e antes que você diga, eu tentei SetStdHandle mas não consigo encontrar nenhuma maneira de fazer isso funcionar)...

Foi útil?

Solução

Você pode usar uma técnica semelhante no Windows, basta usar palavras diferentes para os mesmos conceitos.:) Este artigo: http://msdn.microsoft.com/en-us/library/ms682499.aspx usa um canal win32 para lidar com E/S de outro processo, você só precisa fazer a mesma coisa com threads dentro do mesmo processo.Claro, no seu caso, toda a saída para stderr de qualquer lugar do processo será redirecionada para o seu consumidor.

Na verdade, outras peças do quebra-cabeça que você pode precisar são _fdopen e _open_osfhandle.Na verdade, aqui está um exemplo relacionado de alguns código Eu lancei anos atrás:

DWORD CALLBACK DoDebugThread(void *)
{
    AllocConsole();
    SetConsoleTitle("Copilot Debugger");
    // The following is a really disgusting hack to make stdin and stdout attach
    // to the newly created console using the MSVC++ libraries. I hope other
    // operating systems don't need this kind of kludge.. :)
    stdout->_file = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
    stdin->_file  = _open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT);
    debug();
    stdout->_file = -1;
    stdin->_file  = -1;
    FreeConsole();
    CPU_run();
    return 0;
}   

Nesse caso, o processo principal era um processo GUI que não inicia com identificadores stdio.Ele abre um console e, em seguida, coloca as alças corretas em stdout e stdin para que a função debug() (que foi projetada como uma função interativa stdio) possa interagir com o console recém-criado.Você deve ser capaz de abrir alguns pipes e fazer o mesmo para redirecionar o stderr.

Outras dicas

Você deve lembrar que o que o MSVCRT chama de "identificadores de sistema operacional" não são identificadores Win32, mas outra camada de identificadores adicionada apenas para confundi-lo.MSVCRT tenta emular os números de identificador Unix onde stdin = 0, stdout = 1, stderr = 2 e assim por diante.Os identificadores Win32 são numerados de forma diferente e seus valores sempre são múltiplos de 4.Abrir o tubo e configurar todas as alças corretamente exigirá bagunça nas mãos.Usar o código-fonte MSVCRT e um depurador é provavelmente um requisito.

Você mencionou que não deseja usar um canal nomeado para uso interno;provavelmente vale a pena ressaltar que a documentação para CriarPipe() estados, "Canais anônimos são implementados usando um canal nomeado com um nome exclusivo.Portanto, muitas vezes você pode passar um identificador para um canal anônimo para uma função que requer um identificador para um canal nomeado." Então, sugiro que você apenas escreva uma função que crie um canal semelhante com as configurações corretas para leitura assíncrona.Costumo usar um GUID como uma string (gerada usando CoCreateGUID() e StringFromIID()) para me fornecer um nome exclusivo e, em seguida, criar as extremidades do servidor e do cliente do canal nomeado com as configurações corretas para E/S sobrepostas (mais detalhes sobre isso e código, aqui: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html).

Depois de fazer isso, conecto algum código que preciso ler um arquivo usando E/S sobreposta com uma porta de conclusão de E/S e, bem, então recebo notificações assíncronas dos dados conforme eles chegam ...No entanto, tenho uma boa quantidade de código de biblioteca bem testado que faz tudo acontecer...

Provavelmente é possível configurar o pipe nomeado e então fazer uma leitura sobreposta com um evento no seu OVERLAPPED estrutura e verificar o evento para ver se os dados estavam disponíveis...Não tenho nenhum código disponível que faça isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top