I have a C# 4 application which launches another one to execute some Python code. The Python code can be executed with no problems (checked on PythonWin).
In my app I see that the exit code is -2146234327. I've been Googling and couldn't figure out what does it mean.
Any ideas?
Thanks
-2146234327 is HRESULT code, typically looked for in hex. See Interpreting HRESULTS returned from .NET/CLR: 0x8013XXXX:
HOST_E_EXITPROCESS_TIMEOUT 0x80131029 Process exited due to
Timeout escalation.
I’ve written a workaround based on the fact that this is a warning rather than an error.
I have included the following in the DOS Batch file that runs Analyse and Index Rebuild processes for ArcGIS
set myRC=%ERRORLEVEL%
echo %myRC%
set Constant=-2146234327
echo %Constant%
if %myRC% EQU %Constant% set ERRORLEVEL=0
echo %ERRORLEVEL%
Line 1 sets a variable to the value returned from the call command e.g. call D:\Python27\ArcGIS10.2\python.exe D:\Analyze\Analyze.py >> D:\Analyze\Log\output.txt
Line 2 echoes the value returned
Line 3 sets a constant variable
Line 4 echoes this out
Line 5 compares the value returned from the CALL command against the constant and sets the ERRORLEVEL variable to zero if they match
Line 6 echoes out the return Code.
Found this information elsewhere that may shed a little more light on the issue:
https://github.com/ucd-cws/arcpy_metadata/issues/13
Related
During development of a console app I noticed that I'm unable to pipe its output into itself in PowerShell.
I created a small repro (source below) that works like this:
PS> .\but-why.exe print # continuously prints a random number every 500 ms
1746112985
1700785785
331650882
...
PS> .\but-why.exe read # echoes stdin
foo # this was typed
read 'foo'
bar # this too
read 'bar'
PS> "foo","bar" | .\but-why.exe read
read 'foo'
read 'bar'
But when I try to feed the output of print into read nothing happens:
PS> .\but-why.exe print | .\but-why.exe read
Same when I redirect all outputs to the success stream:
PS> .\but-why.exe print *>&1 | .\but-why.exe read
However, when I use CMD everything works as expected:
CMD> but-why.exe print | but-why.exe read
read '317394436'
read '1828759797'
read '767777814'
...
Through debugging I found that the second instance .\but-why.exe read never seems to be started.
Maybe it's my rather old PS version?
PS> $host.Version
Major Minor Build Revision
----- ----- ----- --------
5 1 19041 610
Source of the console app (net5.0):
using System;
using System.Threading;
switch (args[0]) {
case "print": Print(); break;
case "read": Read(); break;
}
void Print() {
var rng = new Random();
while (true) {
Console.WriteLine(rng.Next());
Thread.Sleep(500);
}
}
void Read() {
string? text;
while ((text = Console.ReadLine()) != null) {
Console.WriteLine($"read '{text}'");
}
}
You're seeing a design limitation in Windows PowerShell that has since been fixed in the cross-platform PowerShell [Core] 7+ edition:
When Windows PowerShell pipes data to an external program (which is then invariably text), it unexpectedly does not exhibit the usual streaming behavior.
That is, instead of passing the originating command's lines (stringified objects) on as they're being produced, Windows PowerShell tries to collect them all in memory first, before piping them to the external program.
In your case, because the first program never stops producing output, the Windows PowerShell engine never stops waiting for all output to be collected and therefore effectively hangs (until it eventually runs out of memory) - the target program is never even launched, because that only happens after collecting the output has finished.
Workarounds:
If feasible, switch to PowerShell [Core] 7+, where this limitation has been removed.
In Windows PowerShell, invoke your pipeline via cmd.exe, which does exhibit the expected streaming behavior, as you've observed.
# Workaround via cmd.exe
cmd /c '.\but-why.exe print | .\but-why.exe read'
I have a C# solution in Visual Studio 2017. I also have a batch script called foobar.bat that contains the following code:
echo foobar : error 1: This is a test error.
My goal is to get only the test error message above to appear in Visual Studio's Error List when I build a particular project and for the build to stop when it appears. So I put [path to script]\foobar.bat in the project's post-build event command line and then build. Now I'm getting two error messages in the Visual Studio Error List:
The command "[path to script]\foobar.bat" exited with code -1.
This is a test error.
In this case, seeing that first error message that just prints out the contents of my post-build event isn't helpful. I want to suppress this initial error so that only my custom error messages show up in the Error List (or at least change it to say something more useful).
Here's what I've tried:
Adding 2>nul to the end of my batch script has no effect.
Adding 1>nul to the end of my batch script suppresses both errors, which isn't what I want.
Adding &set errorlevel=0 to the end of my batch script has no effect.
Adding the line exit 0 to the end of my batch script has no effect.
Adding the following to the end of my .csproj file (per this article) suppresses the first error, but makes it so the build no longer fails:
<Target
Name="PostBuildEvent"
Condition="'$(PostBuildEvent)'!=''"
DependsOnTargets="$(PostBuildEventDependsOn)">
<Exec WorkingDirectory="$(OutDir)" Command="$(PostBuildEvent)" IgnoreExitCode="true" />
</Target>
The last option almost gets me what I want. However, in spite of there being an error message, the Error List doesn't pop up and the build does not fail. It appears as though anything that would cause the initial error message to not appear will also cause the build to no longer fail. Is that the case? Or is there some way I can get the build to fail without showing that initial error message?
What you can do is use an exec and an error task together.
You need to edit the .csproj file and add these tasks after your the Target PostBuildEvent from your last bullet point above.
This solution works by getting the ExitCode and Output of your exec task and using them to trigger the error task which will then stop the build and log the message.
The Exec task needs three parameters:
IgnoreStandardErrorWarningFormat and IgnoreExitCode prevent the error from being logged at this step
ConsoleToMsBuild parameter is required to get the output (spelled ConsoleToMSBuild in VS 2017).
So the tasks look like this:
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="$(PostBuildEvent)" IgnoreStandardErrorWarningFormat="true" IgnoreExitCode="true" ConsoleToMsBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="OutputMessage" />
<Output TaskParameter="ExitCode" PropertyName="ExitCode" />
</Exec>
<Error Text="$(OutputMessage)" Condition="$(ExitCode) == 10" />
<!-- <Error Text="(optional text) : $(OutputMessage)" Condition="$(ExitCode) == 11" />
<Error Text="(optional text) : $(OutputMessage)" Condition="$(ExitCode) == 12" /> -->
</Target>
And edit the file foobar.bat:
echo foobar : error 1: This is a test error.
exit /b 10 <-- /b parameter needed if used in a .bat file
The important part is the exit that will set the code we want to use afterwards.
You can have more than one Error task do to more conditional logging or just use the output as is.
Re: Adding &set errorlevel=0 to the end of my batch script has no effect.
To ignore the exitcode from a single command use || not & or &&. e.g.
Robocopy || set errorlevel=0
This says only if RoboCopy exits with errorlevel != 0, set errorlevel=0
What does “&&” do in this batch file?]1 explains this and more
Historical Notes
The single ampersand e.g.
(prog1 arg1 arg2) & (cmd2 arg1 arg2 arg3)
runs both commands. It was not very useful in DOS. In Unix, it runs both commands at the same time (2 processes), waiting until both finished. Since DOS did not support multiple-processes the '&' was just syntactic sugar for running sequentially.
The single pipe prog1 | prog2 suffered the same limitations in DOS. In Unix after prog1 writes a modest amount on stdout, it is available to prog2 on its stdin.
In DOS this was shorthand for
prog1 > tmpFile
prog2 < tmpFile
In many cases this worked well enough. In the simple case of write1Meg | head, (or more)
DOS had to run to completion before, head could exit after reading the 1st 10 lines.
What does & do?
Unix also supports & at the end of the command-line
prog1 &
This starts prog1 and returns control to the console quickly.
&& and || only make sense when you know that an exit code of 0 is treated like 'true' and non-zero as 'false'. Also short-circuit evaluation is done, so the second command after checking the exit code of the first.
prog1 && prog2
After prog1 exits, prog2 runs only if exitcode == 0
prog1 || prog2
After prog1 exits prog2 runs only if exitcode != 0
Trying to validate a Logstash config file. When running the following line from a Windows command line:
C:> C:\Logstash\bin\logstash -t -f C:\Logstash\config\my.config
I can then check the result using
echo %errorlevel%
which returns 1 in case of a syntax error. Now I want to do this programatically in C#, so:
using System.Diagnostics;
var logstashProcess = Process.Start(#"C:\Logstash\bin\logstash", #"-t -f C:\Logstash\config\my.config");
logstashProcess.WaitForExit();
return logstashProcess.ExitCode == 0;
The problem is that it always returns true (exit code is zero) - even when the config file is totally messed up.
My guess: since C:\Logstash\bin\logstash is a shell script, the zero I get is the shell itself running successfully - not the Logstash process (which is executed from within that script using jruby). Any idea on how to get the real return value? Will a batch file work? (I prefer not to add an extra script to the party at this point)
How do I passt following parameters to my batch file?
custom.bat mode="test" logs="true"
I tried to double the " but nothing helped.
custom.bat "mode="test"" "logs="true""
And, in custom.bat you remove the unneeded quotes
#echo off
set "arg1=%~1"
set "arg2=%~2"
echo [%arg1%] [%arg2%]
You may use CALL command to launch a new batch-file. After executing the last line of the "called file", the control will return back to the "calling file".
You may set the parameters to the "called .bat fie" by using either a simple string or a variable.
eg.
CALL MyScript.bat "1234"
or
SET _MyVar="1234"
CALL MyScript.bat %_MyVar%
As a precaution, you may use SETLOCAL & ENDLOCAL to keep separation between variables of same-name among different files.
What I'm trying to achieve is a self-compiled c# file without toxic output.I'm trying to achieve this with Console.MoveBufferArea method but looks does not work.
Eg. - save the code below with .bat extension :
// 2>nul||#goto :batch
/*
:batch
#echo off
setlocal
:: find csc.exe
set "frm=%SystemRoot%\Microsoft.NET\Framework\"
for /f "tokens=* delims=" %%v in ('dir /b /a:d /o:-n "%SystemRoot%\Microsoft.NET\Framework\v*"') do (
set netver=%%v
goto :break_loop
)
:break_loop
set csc=%frm%%netver%\csc.exe
:: csc.exe found
%csc% /nologo /out:"%~n0.exe" "%~dpsfnx0"
%~n0.exe
endlocal
exit /b 0
*/
public class Hello
{
public static void Main() {
ClearC();
System.Console.WriteLine("Hello, C# World!");
}
private static void ClearC() {
System.Console.MoveBufferArea(
0,0,
System.Console.BufferWidth,System.Console.BufferHeight-1,
0,0
);
}
}
the output will be:
C:\>// 2>nul ||
Hello, C# World!
What want is to rid of the // 2>nul || .Is it possible? Is there something wrong in my logic (the ClearC method)?Do I need PInvoke?
If you want to do it in the C#, then changing your ClearC function to the following seems to work:
public static void ClearC() {
System.Console.CursorTop = System.Console.CursorTop - 1;
System.Console.Write(new string(' ', System.Console.BufferWidth));
System.Console.CursorTop = System.Console.CursorTop - 1;
}
Essentially, move the Cursor up a line (to the line that should contain your prompt), blank the entire line, then move up another line (which should move you to the blank line between commands). Future output will then take place from here.
The obvious downside to this is that you need to wait for the C# code to be compiled and executed, before the // 2>nul || is removed. If you want it to be faster, you'll need to find a console/batch file based solution. The other thing to keep in mind is that is assumes that the prompt is a single line. If it's a really long prompt that spans two lines, then you'll get a bit of a mess, so it may be better to clear two lines, depending on how you're planning on using this.
If you want to go the whole hog and start reading the console buffer to determine how long the prompt is, then you might want to have a look at this question. Whilst the article link in the answer is broken, the code download still seems to work.
If you want to go down the batchfile based approach, then you might want to have a look at this question.