Call AllocConsole (#1351)
This commit is contained in:
parent
e7f3c7c62e
commit
729a98adfc
|
|
@ -20,7 +20,8 @@ FileOutputManager::FileOutputManager(bool fEnableNativeLogging) :
|
|||
m_disposed(false),
|
||||
stdoutWrapper(nullptr),
|
||||
stderrWrapper(nullptr),
|
||||
m_fEnableNativeRedirection(fEnableNativeLogging)
|
||||
m_fEnableNativeRedirection(fEnableNativeLogging),
|
||||
m_fCreatedConsole(false)
|
||||
{
|
||||
InitializeSRWLock(&m_srwLock);
|
||||
}
|
||||
|
|
@ -49,6 +50,21 @@ FileOutputManager::Start()
|
|||
STRU struPath;
|
||||
FILETIME processCreationTime;
|
||||
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
|
||||
RETURN_IF_FAILED(FILE_UTILITY::ConvertPathToFullPath(
|
||||
|
|
@ -129,6 +145,11 @@ FileOutputManager::Stop()
|
|||
|
||||
m_disposed = true;
|
||||
|
||||
if (m_fCreatedConsole)
|
||||
{
|
||||
RETURN_LAST_ERROR_IF(!FreeConsole());
|
||||
}
|
||||
|
||||
if (m_hLogFileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ private:
|
|||
STRA m_straFileContent;
|
||||
BOOL m_disposed;
|
||||
BOOL m_fEnableNativeRedirection;
|
||||
BOOL m_fCreatedConsole;
|
||||
SRWLOCK m_srwLock{};
|
||||
std::unique_ptr<StdWrapper> stdoutWrapper;
|
||||
std::unique_ptr<StdWrapper> stderrWrapper;
|
||||
|
|
|
|||
|
|
@ -27,13 +27,18 @@ LoggingHelpers::CreateLoggingProvider(
|
|||
|
||||
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)
|
||||
{
|
||||
auto manager = std::make_unique<FileOutputManager>(fEnableNativeLogging);
|
||||
hr = manager->Initialize(pwzStdOutFileName, pwzApplicationPath);
|
||||
outputManager = std::move(manager);
|
||||
}
|
||||
else if (!GetConsoleWindow())
|
||||
else if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &dummy))
|
||||
{
|
||||
outputManager = std::make_unique<PipeOutputManager>(fEnableNativeLogging);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ PipeOutputManager::PipeOutputManager(bool fEnableNativeLogging) :
|
|||
m_disposed(FALSE),
|
||||
m_fEnableNativeRedirection(fEnableNativeLogging),
|
||||
stdoutWrapper(nullptr),
|
||||
stderrWrapper(nullptr)
|
||||
stderrWrapper(nullptr),
|
||||
m_fCreatedConsole(false)
|
||||
{
|
||||
InitializeSRWLock(&m_srwLock);
|
||||
}
|
||||
|
|
@ -43,6 +44,21 @@ HRESULT PipeOutputManager::Start()
|
|||
HANDLE hStdErrReadPipe;
|
||||
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*/));
|
||||
|
||||
m_hErrReadPipe = hStdErrReadPipe;
|
||||
|
|
@ -92,6 +108,11 @@ HRESULT PipeOutputManager::Stop()
|
|||
|
||||
m_disposed = true;
|
||||
|
||||
if (m_fCreatedConsole)
|
||||
{
|
||||
FreeConsole();
|
||||
}
|
||||
|
||||
// Both pipe wrappers duplicate the pipe writer handle
|
||||
// meaning we are fine to close the handle too.
|
||||
if (m_hErrWritePipe != INVALID_HANDLE_VALUE)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ private:
|
|||
SRWLOCK m_srwLock {};
|
||||
BOOL m_disposed;
|
||||
BOOL m_fEnableNativeRedirection;
|
||||
BOOL m_fCreatedConsole;
|
||||
std::unique_ptr<StdWrapper> stdoutWrapper;
|
||||
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_RANDOM_VALUE"] = randomNumberString;
|
||||
|
||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||
|
||||
var response = await deploymentResult.HttpClient.GetAsync(path);
|
||||
|
||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||
|
||||
StopServer();
|
||||
await AssertFailsToStart(path, deploymentParameters);
|
||||
|
||||
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);
|
||||
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 response = await deploymentResult.HttpClient.GetAsync(path);
|
||||
|
|
@ -63,8 +76,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||
|
||||
StopServer();
|
||||
|
||||
Assert.Contains(TestSink.Writes, context => context.Message.Contains(new string('a', 4096)));
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace IISTestSite
|
||||
{
|
||||
|
|
@ -41,6 +43,14 @@ namespace IISTestSite
|
|||
Console.Error.WriteLine(new string('a', 4096));
|
||||
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