Call AllocConsole (#1351)
This commit is contained in:
parent
e7f3c7c62e
commit
729a98adfc
|
|
@ -20,7 +20,8 @@ FileOutputManager::FileOutputManager(bool fEnableNativeLogging) :
|
||||||
m_disposed(false),
|
m_disposed(false),
|
||||||
stdoutWrapper(nullptr),
|
stdoutWrapper(nullptr),
|
||||||
stderrWrapper(nullptr),
|
stderrWrapper(nullptr),
|
||||||
m_fEnableNativeRedirection(fEnableNativeLogging)
|
m_fEnableNativeRedirection(fEnableNativeLogging),
|
||||||
|
m_fCreatedConsole(false)
|
||||||
{
|
{
|
||||||
InitializeSRWLock(&m_srwLock);
|
InitializeSRWLock(&m_srwLock);
|
||||||
}
|
}
|
||||||
|
|
@ -50,6 +51,21 @@ FileOutputManager::Start()
|
||||||
FILETIME processCreationTime;
|
FILETIME processCreationTime;
|
||||||
FILETIME dummyFileTime;
|
FILETIME dummyFileTime;
|
||||||
|
|
||||||
|
// To make Console.* functions work, allocate a console
|
||||||
|
// in the current process.
|
||||||
|
if (!AllocConsole())
|
||||||
|
{
|
||||||
|
// ERROR_ACCESS_DENIED means there is a console already present.
|
||||||
|
if (GetLastError() != ERROR_ACCESS_DENIED)
|
||||||
|
{
|
||||||
|
RETURN_LAST_ERROR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_fCreatedConsole = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Concatenate the log file name and application path
|
// Concatenate the log file name and application path
|
||||||
RETURN_IF_FAILED(FILE_UTILITY::ConvertPathToFullPath(
|
RETURN_IF_FAILED(FILE_UTILITY::ConvertPathToFullPath(
|
||||||
m_wsStdOutLogFileName.QueryStr(),
|
m_wsStdOutLogFileName.QueryStr(),
|
||||||
|
|
@ -129,6 +145,11 @@ FileOutputManager::Stop()
|
||||||
|
|
||||||
m_disposed = true;
|
m_disposed = true;
|
||||||
|
|
||||||
|
if (m_fCreatedConsole)
|
||||||
|
{
|
||||||
|
RETURN_LAST_ERROR_IF(!FreeConsole());
|
||||||
|
}
|
||||||
|
|
||||||
if (m_hLogFileHandle == INVALID_HANDLE_VALUE)
|
if (m_hLogFileHandle == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ private:
|
||||||
STRA m_straFileContent;
|
STRA m_straFileContent;
|
||||||
BOOL m_disposed;
|
BOOL m_disposed;
|
||||||
BOOL m_fEnableNativeRedirection;
|
BOOL m_fEnableNativeRedirection;
|
||||||
|
BOOL m_fCreatedConsole;
|
||||||
SRWLOCK m_srwLock{};
|
SRWLOCK m_srwLock{};
|
||||||
std::unique_ptr<StdWrapper> stdoutWrapper;
|
std::unique_ptr<StdWrapper> stdoutWrapper;
|
||||||
std::unique_ptr<StdWrapper> stderrWrapper;
|
std::unique_ptr<StdWrapper> stderrWrapper;
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,18 @@ LoggingHelpers::CreateLoggingProvider(
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Check if there is an existing active console window before redirecting
|
||||||
|
// Window == IISExpress with active console window, don't redirect to a pipe
|
||||||
|
// if true.
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO dummy;
|
||||||
|
|
||||||
if (fIsLoggingEnabled)
|
if (fIsLoggingEnabled)
|
||||||
{
|
{
|
||||||
auto manager = std::make_unique<FileOutputManager>(fEnableNativeLogging);
|
auto manager = std::make_unique<FileOutputManager>(fEnableNativeLogging);
|
||||||
hr = manager->Initialize(pwzStdOutFileName, pwzApplicationPath);
|
hr = manager->Initialize(pwzStdOutFileName, pwzApplicationPath);
|
||||||
outputManager = std::move(manager);
|
outputManager = std::move(manager);
|
||||||
}
|
}
|
||||||
else if (!GetConsoleWindow())
|
else if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &dummy))
|
||||||
{
|
{
|
||||||
outputManager = std::make_unique<PipeOutputManager>(fEnableNativeLogging);
|
outputManager = std::make_unique<PipeOutputManager>(fEnableNativeLogging);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ PipeOutputManager::PipeOutputManager(bool fEnableNativeLogging) :
|
||||||
m_disposed(FALSE),
|
m_disposed(FALSE),
|
||||||
m_fEnableNativeRedirection(fEnableNativeLogging),
|
m_fEnableNativeRedirection(fEnableNativeLogging),
|
||||||
stdoutWrapper(nullptr),
|
stdoutWrapper(nullptr),
|
||||||
stderrWrapper(nullptr)
|
stderrWrapper(nullptr),
|
||||||
|
m_fCreatedConsole(false)
|
||||||
{
|
{
|
||||||
InitializeSRWLock(&m_srwLock);
|
InitializeSRWLock(&m_srwLock);
|
||||||
}
|
}
|
||||||
|
|
@ -43,6 +44,21 @@ HRESULT PipeOutputManager::Start()
|
||||||
HANDLE hStdErrReadPipe;
|
HANDLE hStdErrReadPipe;
|
||||||
HANDLE hStdErrWritePipe;
|
HANDLE hStdErrWritePipe;
|
||||||
|
|
||||||
|
// To make Console.* functions work, allocate a console
|
||||||
|
// in the current process.
|
||||||
|
if (!AllocConsole())
|
||||||
|
{
|
||||||
|
// ERROR_ACCESS_DENIED means there is a console already present.
|
||||||
|
if (GetLastError() != ERROR_ACCESS_DENIED)
|
||||||
|
{
|
||||||
|
RETURN_LAST_ERROR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_fCreatedConsole = true;
|
||||||
|
}
|
||||||
|
|
||||||
RETURN_LAST_ERROR_IF(!CreatePipe(&hStdErrReadPipe, &hStdErrWritePipe, &saAttr, 0 /*nSize*/));
|
RETURN_LAST_ERROR_IF(!CreatePipe(&hStdErrReadPipe, &hStdErrWritePipe, &saAttr, 0 /*nSize*/));
|
||||||
|
|
||||||
m_hErrReadPipe = hStdErrReadPipe;
|
m_hErrReadPipe = hStdErrReadPipe;
|
||||||
|
|
@ -92,6 +108,11 @@ HRESULT PipeOutputManager::Stop()
|
||||||
|
|
||||||
m_disposed = true;
|
m_disposed = true;
|
||||||
|
|
||||||
|
if (m_fCreatedConsole)
|
||||||
|
{
|
||||||
|
FreeConsole();
|
||||||
|
}
|
||||||
|
|
||||||
// Both pipe wrappers duplicate the pipe writer handle
|
// Both pipe wrappers duplicate the pipe writer handle
|
||||||
// meaning we are fine to close the handle too.
|
// meaning we are fine to close the handle too.
|
||||||
if (m_hErrWritePipe != INVALID_HANDLE_VALUE)
|
if (m_hErrWritePipe != INVALID_HANDLE_VALUE)
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ private:
|
||||||
SRWLOCK m_srwLock {};
|
SRWLOCK m_srwLock {};
|
||||||
BOOL m_disposed;
|
BOOL m_disposed;
|
||||||
BOOL m_fEnableNativeRedirection;
|
BOOL m_fEnableNativeRedirection;
|
||||||
|
BOOL m_fCreatedConsole;
|
||||||
std::unique_ptr<StdWrapper> stdoutWrapper;
|
std::unique_ptr<StdWrapper> stdoutWrapper;
|
||||||
std::unique_ptr<StdWrapper> stderrWrapper;
|
std::unique_ptr<StdWrapper> stderrWrapper;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -35,13 +35,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path;
|
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path;
|
||||||
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_RANDOM_VALUE"] = randomNumberString;
|
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_RANDOM_VALUE"] = randomNumberString;
|
||||||
|
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
await AssertFailsToStart(path, deploymentParameters);
|
||||||
|
|
||||||
var response = await deploymentResult.HttpClient.GetAsync(path);
|
|
||||||
|
|
||||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
|
||||||
|
|
||||||
StopServer();
|
|
||||||
|
|
||||||
Assert.Contains(TestSink.Writes, context => context.Message.Contains($"Random number: {randomNumberString}"));
|
Assert.Contains(TestSink.Writes, context => context.Message.Contains($"Random number: {randomNumberString}"));
|
||||||
}
|
}
|
||||||
|
|
@ -56,6 +50,25 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.StartupExceptionWebsite, publish: true);
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.StartupExceptionWebsite, publish: true);
|
||||||
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path;
|
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path;
|
||||||
|
|
||||||
|
await AssertFailsToStart(path, deploymentParameters);
|
||||||
|
|
||||||
|
Assert.Contains(TestSink.Writes, context => context.Message.Contains(new string('a', 4096)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
public async Task CheckValidConsoleFunctions()
|
||||||
|
{
|
||||||
|
var path = "CheckConsoleFunctions";
|
||||||
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.StartupExceptionWebsite, publish: true);
|
||||||
|
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path;
|
||||||
|
|
||||||
|
await AssertFailsToStart(path, deploymentParameters);
|
||||||
|
|
||||||
|
Assert.Contains(TestSink.Writes, context => context.Message.Contains("Is Console redirection: True"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AssertFailsToStart(string path, IntegrationTesting.IIS.IISDeploymentParameters deploymentParameters)
|
||||||
|
{
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
var response = await deploymentResult.HttpClient.GetAsync(path);
|
var response = await deploymentResult.HttpClient.GetAsync(path);
|
||||||
|
|
@ -63,8 +76,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
|
|
||||||
StopServer();
|
StopServer();
|
||||||
|
|
||||||
Assert.Contains(TestSink.Writes, context => context.Message.Contains(new string('a', 4096)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace IISTestSite
|
namespace IISTestSite
|
||||||
{
|
{
|
||||||
|
|
@ -41,6 +43,14 @@ namespace IISTestSite
|
||||||
Console.Error.WriteLine(new string('a', 4096));
|
Console.Error.WriteLine(new string('a', 4096));
|
||||||
Console.Error.Flush();
|
Console.Error.Flush();
|
||||||
}
|
}
|
||||||
|
else if (envVariable == "CheckConsoleFunctions")
|
||||||
|
{
|
||||||
|
// Call a bunch of console functions and make sure none return invalid handle.
|
||||||
|
Console.OutputEncoding = Encoding.UTF8;
|
||||||
|
Console.Title = "Test";
|
||||||
|
Console.WriteLine($"Is Console redirection: {Console.IsOutputRedirected}");
|
||||||
|
Console.BackgroundColor = ConsoleColor.Blue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue