제목에 모두 나와 있습니다. 나는 다음과 같은 코드를 실행하면 :SetStdHandle은 cout/printf에 아무런 영향을 미치지 않습니다.
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hFile = CreateFile(TEXT("Foo.txt"), GENERIC_WRITE, FILE_READ_ACCESS | FILE_WRITE_ACCESS,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
SetStdHandle(STD_OUTPUT_HANDLE, hFile);
std::cout << "Hello, ";
printf("world!\n");
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "Hello, world!\n", 13, NULL, NULL);
SetStdHandle(STD_OUTPUT_HANDLE, hOut);
CloseHandle(hFile);
결과는 Hello, world!
가 cout
및 printf
에 대한 호출의 결과로 콘솔에 기록됩니다 것을, 그리고 Hello, world!
도 호출의 결과로서 파일 Foo.txt
에 기록됩니다 ~ WriteFile
. 내 가정은 처음에 모든 것이 초기화 될 때 GetStdHandle
에 의해 반환 된 HANDLE
이 캐쉬되어 cout
과 printf
모두에 대해 재사용된다는 것입니다. 그게 완벽하게 합리적이고 정확히 내가 원하는 것일까 요 GetStdHandle
은 운영 체제를 호출해야합니다 (오래 걸릴 수도 있습니다!). 문제는 가능한 경우 해당 동작을 무시하고 응용 프로그램의 표준 핸들과 함께 cout 및 printf를 "동기화"하려는 것입니다.
어떤 대안을 제안하기 전에 내가 정확히 무엇을하려고하는지 설명해주십시오 (예,이 목적으로 freopen
을 사용할 수 있음을 알고 있습니다). 내가 할 수 있기를 바란 것은 이전 표준 출력 핸들을 복원 할 수 있도록 변경하기 전에 현재 표준 출력 핸들을 스택과 같은 데이터 구조에 "저장"하는 것입니다. 이 상황에서는 그다지 부족한 부분이 있습니다 (예 : CONOUT$
등으로 복원 할 수 없음). 이것은 재귀 적이어야한다. 나는. 당신이 그것을 기대하는 것처럼 다음과 같은 작업을해야합니다 :
std::cout << "A1" << std::endl;
StartStdOutRedirection(TEXT("Foo.txt"));
std::cout << "B1" << std::endl;
StartStdOutRedirection(TEXT("Bar.txt"));
std::cout << "C1" << std::endl;
EndStdOutRedirection();
std::cout << "B2" << std::endl;
EndStdOutRedirection();
std::cout << "A2" << std::endl;
수있는 방법이 있다면 이것은 너무 쉬운 것입니다 트릭해야 다음 코드로 "재 동기화"stdout
에 :
std::vector<HANDLE> vStdOutHandles;
void StartStdOutRedirection(_In_ LPCTSTR lpFile)
{
vStdOutHandles.push_back(GetStdHandle(STD_OUTPUT_HANDLE));
SetStdHandle(STD_OUTPUT_HANDLE, CreateFile(lpFile, GENERIC_WRITE,
FILE_WRITE_ACCESS | FILE_READ_ACCESS, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
}
void EndStdOutRedirection(void)
{
CloseHandle(GetStdHandle(STD_INPUT_HANDLE));
SetStdHandle(STD_OUTPUT_HANDLE, vStdOutHandles.back());
vStdOutHandles.pop_back();
}
을
cout
대신 GetStdHandle(STD_OUTPUT_HANDLE)
을 호출하여 WriteFile
을 사용하여 위 코드의 정확성을 확인할 수 있습니다. 내가 이상적으로 필요로하는 것은 에 해당하는 것인데 HANDLE
에서 작동합니다. 그 방법으로 을 GetStdHandle
으로 반환 한 다음이 MyReopenHandle
이 내 기본 설정 파일 인 HANDLE
을 자신이 좋아하는 파일로 설정할 수 있습니다. 나는 그것이 printf
과 cout
모두 어딘가에 깊은 아래에 저장된 HANDLE
을 가지고 있다고 가정 할 때 그것이 작동 할 것이라고 믿습니다. 나는 "awake it"을 표준 출력 핸들을 복사하여 핸들을 닫은 다음 CreateFile
을 호출하여 동일한 HANDLE
값을 줄 수 있기를 희망했지만 가끔씩은 잘 작동합니다. 당신이 관심이 있다면 여기에 내 코드입니다 :
std::vector<HANDLE> vStdOutHandles;
bool StartStdOutRedirection(_In_ LPCTSTR lpFile)
{
bool fResult = false;
HANDLE hProc = GetCurrentProcess();
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut != INVALID_HANDLE_VALUE)
{
HANDLE hDup;
if (DuplicateHandle(hProc, hOut, hProc, &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
// Need to close the current handle before we open the new one
CloseHandle(hOut);
HANDLE hFile = CreateFile(lpFile, GENERIC_WRITE, FILE_WRITE_ACCESS | FILE_READ_ACCESS,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
// Should be same HANDLE; else we're screwed...
assert(hFile == hOut);
SetStdHandle(STD_OUTPUT_HANDLE, hFile);
vStdOutHandles.push_back(hDup);
fResult = true;
}
else
{
// Otherwise, reopen the previous output HANDLE on failure
DuplicateHandle(hProc, hDup, hProc, &hFile, 0, FALSE, DUPLICATE_SAME_ACCESS);
assert(hFile == hOut);
CloseHandle(hDup);
}
}
}
return fResult;
}
bool EndStdOutRedirection(void)
{
bool fResult = false;
HANDLE hProc = GetCurrentProcess();
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut != INVALID_HANDLE_VALUE && vStdOutHandles.size() != 0)
{
HANDLE hDup;
HANDLE hNext = vStdOutHandles.back();
// Close current handle and re-open previous one
CloseHandle(hOut);
if (DuplicateHandle(hProc, hNext, hProc, &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
// Again, we're screwed if these are not the same
assert(hOut == hDup);
SetStdHandle(STD_OUTPUT_HANDLE, hDup);
vStdOutHandles.pop_back();
fResult = true;
}
}
return fResult;
}
위 어설 절반의 시간을 실패 (난 정말 기대 또는 작업이에 계산되지 않았습니다 ... 난 그냥 관심이 있었다). 이것은 제가이 문제에 관해서 한 것입니다. 누구든지 제안이 있으면 알려주십시오.
'GetStdHandle'에서 반환 된'HANDLE'에 대한'WriteFile'에 의존하는 것은 부작용이 있습니다. 여전히 원래 장치에 기록됩니다. 내가 해낼 수 있었던 해법이 좀 덜 해킹 된 것을보고 OS와 함께 작동 – Duncan
동의! 당신은 해결책이 훨씬 낫습니다! 그리고 그것은 내 해킹이 아닙니다. – xMRi
표준 출력 (또는 표준 장치)으로 freopen을 호출하는 것이 정의되지 않은 동작이라고 생각합니다. 적어도 그것은 내 연구에서 나온 것입니다. 최소한 "cout"을 사용한다는 측면에서는 아무 것도 보장되지 않습니다. Windows에서의 구현 (그리고 대부분의 다른 주요 플랫폼들도 그렇다고 생각합니다)은 당신이 바라는 것을 수행합니다. – Duncan