你好這個偉大的社區,的Win32改變爲二進制模式,孩子的標準輸出(管道)
我用的管,以孩子的標準輸出重定向到一個文件時,必須與('\n') 0x0A
到('\n\r') 0x0D 0x0A
自動轉換的問題,孩子的輸出是字節和不是文本。
首先,我已經使用這些例子MSDN-Creating a Child Process with Redirected Input and Output和http://support.microsoft.com/kb/190351),現在我有了這個基本的應用程序,它創建一個管道並將孩子的STDOUT重定向到一個二進制文件。所有這些在Visual C++ 6.0的Win32控制檯應用程序中(是的,它是舊的,但是是一個要求)。
#define BUFSIZE 256
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
int _tmain(int argc, TCHAR *argv[])
{
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
ErrorExit(TEXT("StdoutRd CreatePipe"));
if (! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
ErrorExit(TEXT("Stdout SetHandleInformation"));
CreateChildProcess();
if (!CloseHandle(g_hChildStd_OUT_Wr))
ErrorExit("CloseHandle");
ReadFromPipe();
if (!CloseHandle(g_hChildStd_OUT_Rd))
ErrorExit("CloseHandle");
return 0;
}
void CreateChildProcess()
{
TCHAR szCmdline[]=TEXT("child.exe");
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
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
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
if (! bSuccess)
ErrorExit(TEXT("CreateProcess"));
else
{
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
}
}
void ReadFromPipe(void)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD nTotalBytesRead = 0;
fstream filePk;
filePk.open("result.out", ios::out | ios::trunc | ios::binary);
for (;;)
{
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if(! bSuccess || dwRead == 0) {
if (GetLastError() == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path.
else
ErrorExit("ReadFile"); // Something bad happened.
}
filePk.write(chBuf, dwRead);
nTotalBytesRead += dwRead;
}
filePk.close();
char ibuff[24];
sprintf(ibuff,"%d bytes." , (int)nTotalBytesRead);
::MessageBox(NULL, ibuff, "", 0);
}
而在這個虛擬child.cpp你會發現,如果我設定的標準輸出爲二進制模式,一切都運行得很好(我得到公正的0x0A的0x0A!),但我真正的孩子是一個EXE和我無法訪問該代碼。
int main(int argc, char* argv[])
{
_setmode(_fileno(stdout), _O_BINARY);
printf("\n");
unsigned char buffer[] = {'\n'};
fwrite(buffer, sizeof(unsigned char), sizeof(buffer), stdout);
return 0;
}
所以,搜索約2天,考慮到我有一個基本的C++知識後,我問:有沒有我可以做_setmode
從父stdout的孩子的一個方式,考慮到我不無法訪問孩子的代碼。
作爲一種解決方案,我認真考慮找到每個'0x0D' '0x0A'
並用'0x0A'
替換它。我對這個問題真的很瘋狂......所以如果有人能幫助我,我會非常感激。
相關問題:Win32 Stream Handles - Changing To Binary Mode但他卻獲得了孩子的代碼!
編輯
如,@librik點,最終的解決方案將具有由的0x0A取代0X0D的0x0A的每一個發生。爲此,文件內容必須在內存中存在。有一些問題,但我可以忍受它(分配的內存過多)。我希望這將是有益的:
void ReadFromPipe(void)
{
DWORD dwRead, dwWritten;
CHAR *chBuf = NULL, *chBufTmp = NULL;
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD nTotalBytesRead = 0;
fstream filePk;
filePk.open("result.out", ios::out | ios::trunc | ios::binary);
int nIter = 0;
for (;;)
{
if(chBuf == NULL) {
if((chBuf = (CHAR*)malloc(BUFSIZE*sizeof(CHAR))) == NULL) {
ErrorExit("Malloc");
}
} else {
chBufTmp = chBuf; // save pointer in case realloc fails
if((chBuf = (CHAR*)realloc(chBuf, (nIter+1)*(BUFSIZE*sizeof(CHAR)))) == NULL) {
free(chBufTmp); // free original block
ErrorExit("Realloc");
}
}
CHAR* chBufNew = chBuf+nTotalBytesRead;
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBufNew, BUFSIZE, &dwRead, NULL);
if(! bSuccess || dwRead == 0) {
if (GetLastError() == ERROR_BROKEN_PIPE) {
break; // pipe done - normal exit path.
} else {
ErrorExit("ReadFile"); // Something bad happened.
}
}
nTotalBytesRead += dwRead;
nIter ++;
}
// 0xD 0xA -> 0xA
nTotalBytesRead = ClearBuffer(chBuf, nTotalBytesRead);
filePk.write(chBuf, nTotalBytesRead);
filePk.close();
free(chBuf);
char ibuff[24];
sprintf(ibuff,"%d bytes." , (int)nTotalBytesRead);
::MessageBox(NULL, ibuff, "", 0);
}
int ClearBuffer(char *buffer, int bufferlength) {
// lmiguelhm-es requerido que TODO el buffer esté en memoria
int chdel = 0;
for (int i = 0; (i+chdel) < bufferlength; i++) {
char firstChar = buffer[i+chdel];
buffer[i] = firstChar;
if (firstChar == 0x0D) {
if ((i+chdel+1) < bufferlength) {
char secondChar = buffer[i+chdel+1];
if (secondChar == 0x0A) {
buffer[i] = secondChar;
chdel++;
}
}
}
}
return bufferlength - chdel;
}
謝謝!還有一件事,_my孩子正在用二進制模式編寫_,這個解決方案也適用於二進制模式嗎? – lmiguelmh
我以爲你說過這個孩子在文本模式下有stdout。如果孩子的stdout處於二進制模式,那麼我不明白爲什麼你會看到0x0D 0x0A。你的問題現在很混亂,似乎與自己相矛盾。如果流是文本模式流,則不能以二進制模式寫入,如果尚未調用'_setmode(stdout,O_BINARY)',則stdout流是文本模式流。 – librik
抱歉。我應該說:孩子寫字節而不是文字。我添加了最終解決方案。再次感謝。 – lmiguelmh