Here is my attempt to copy my application executable to another folder changing it's name:
IF $(ConfigurationName) == Release (
SET DESTINATION=$(ProjectDir)Output\Distribution
IF NOT EXIST "%DESTINATION%" ( MD "%DESTINATION%" )
XCOPY /Q /Y "$(TargetPath)" "%DESTINATION%"
RENAME "%DESTINATION%\$(TargetFileName)" "$(TargetName).Plain$(TargetExt)"
)
I've tried everything to make it work, but it always throw error code 255 or 1, it depends. Running that code with a plain batch file works like a charm!
You need to enable delayed expansion, using the SETLOCAL EnableDelayedExpansion command. Do it at the top of the post-build event. After that, you can access your variable by using not %VARIABLE_NAME%, but !VARIABLE_NAME! (use an exclamation symbol on either side of the variable name, not the percentage symbol which you would use in a regular batch file).
So, for example
SETLOCAL EnableDelayedExpansion
IF $(ConfigurationName) == Release (
SET DESTINATION=$(ProjectDir)Output\Distribution
echo My destination dir is !DESTINATION!
)
This will output something like
My destination dir is D:\Work\Projects\PBExample\Output\Distribution.
Since the Post-build event command line actually runs as a batch file you need to escape characters like % by doubling them to %%:
https://stackoverflow.com/a/13552702/74585
Related
I created an c# wpf application that accepts command line parameters. If I open cmd and call the application with multiple parameters, the parameters are passed in correctly.
But if I do that same thing but from a batch file it passes the parameters as one parameter combined together rather then multiple parameters. I had the application output the parameters and it looks like all the spaces (which is what separates each command line parameter) were changed to a weird á character.
is there something special I need to do to get the parameters passed correctly?
I have tried resaving the file with ASCII encoding but that didn't change anything.
I also tried adding this line to the batch file
chcp 1253>NUL
that changed it so the á wasn't there but it still had it was one parameter.
seems like the spaces are just not getting passed as a space.
here is what my batch file line looks like, each parameter is separated by a space.
start /wait C:\MyTestApp.exe /SILENT /BOOLAGREEMENT=TRUE /BOOLGAOPTIN=TRUE
--UPDATE--Adding steps to reproduce...
this is just generic code similar to what I did just condensed
create c# wpf app.
in App.xaml.cs override OnStartup
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
this.ShutdownMode = System.Windows.ShutdownMode.OnMainWindowClose;
bool shutdownapp = false;
MessageBox.Show(string.Join(",", e.Args));
}
build exe.
now launch cmd and cd to the location of the exe.
MyTestApp.exe /param1=test1 /param2=test2
you should get a message box that says
/param1=test1,param2=test2
now create a batch file that has something like this...then run it
test.bat
#echo off
start /wait c:\MyTestApp.exe /param1=test1 /param2=test2
this time the message box should have this...
/param1=test1/param2=test2
Start sees all of that as a CMD to Start.
Is there a reason you actually need to use start? generally, there isn't and you can just call the executable directly.
eg TestMyApp.cmd
#(
SETLOCAL
ECHO OFF
)
REM Call your Command here with all arguments:
"C:\MyTestApp.exe" /SILENT /BOOLAGREEMENT=TRUE /BOOLGAOPTIN=TRUE
If you sincerely require Start.
Then you should be aware that it treats all of that command as a single string, by nature, which is what you're running into, so you should be calling a new CMD instance explicitly instead in that case:
START "" /WAIT CMD /C ""C:\MyTestApp.exe" /SILENT /BOOLAGREEMENT=TRUE /BOOLGAOPTIN=TRUE"
But that is a lot of extra work to go through if not needed.
Alternatively, you can also just run a CMD instance directly:
CMD /C ""C:\MyTestApp.exe" /SILENT /BOOLAGREEMENT=TRUE /BOOLGAOPTIN=TRUE"
Or Use CALL:
CALL "C:\MyTestApp.exe" /SILENT /BOOLAGREEMENT=TRUE /BOOLGAOPTIN=TRUE
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)
I've created a console app (using Visual Studio 2010) which can read command arguments.
When I debug, I parse some test parameters which are set in Project-> [project name] Properties... -> Debug -> Command line arguments:
It reads:
"parametername1|parametervalue1" "parametername2|parametervalue2" "parametername3|parametervalue3"
I used the following code to read the parameters:
for (Int16 argumentsCount = 0; argumentsCount < args.Length; argumentsCount++)
{
String[] parameterItem = args[argumentsCount].Split('|');
String parameterName = parameterItem[0].ToString();
String parameterValue = parameterItem[1].ToString();
/*code continues*/
}
When I run in debug mode the app it works just fine and all parameters are read.
I then published the app to a server and ensured it was installed with the correct permissions (for the purposes of demonstration lets say it's on C:\MyApp and the Complied code resides in MyApp.application
I then created a batch script that executes the app. The *.BAT contains the following command:
"C:\MyApp\MyApp.application" "parametername1|parametervalue1" "parametername2|parametervalue2" "parametername3|parametervalue3"
This kind of works as the application executes when I run the batch... However... none of my parameters are being received by my app. I know this because I recompiled and published with some code to read how many parameters are being received with:
Console.Write("Arguments " + args.Length.ToString());
and that shows Arguments: 0
Can someone please tell me how to write my batch script to run the app and parse my parameters/command line arguments.
ETA: Nevermind. Your problem is .application instead of a .exe. Look in your file associations what happens with .application compared to .exe:
> assoc .application
.application=Application.Manifest
> ftype Application.Manifest
Application.Manifest=rundll32.exe dfshim.dll,ShOpenVerbApplication %1
> assoc .exe
.exe=exefile
> ftype exefile
exefile="%1" %*
You see the difference in what is passed there? Namely that normal executables get command-line arguments (the %*). So I guess you should use an executable instead of an executable manifest or whatever .application actually is (I've never seen it in the wild, honestly).
With a fairly minimal test program
class Args {
static void Main(string[] args) {
for (int i = 0; i < args.Length; i++) {
System.Console.WriteLine("[{0}]=<{1}>", i, args[i]);
}
}
}
it works fine for me. The following batch file:
#"args.exe" "parametername1|parametervalue1" "parametername2|parametervalue2" "parametername3|parametervalue3"
yields the following output:
[0]=<parametername1|parametervalue1>
[1]=<parametername2|parametervalue2>
[2]=<parametername3|parametervalue3>
So I guess there is something wrong in the code you didn't show us. Maybe you're not actually using the command-line arguments in your C# application but instead reference a different string[] there?
The pipe character | has a special meaning in batch files. I would suggest using a different character to make things easier. Otherwise you have to use a Escape Character to use the pipe character. It would probably look like this:
"C:\MyApp\MyApp.application" "parametername1^|parametervalue1" "parametername2^|parametervalue2" "parametername3^|parametervalue3"
note the caret ^ before the pipe |.
I have a gem, roundhouse, which is an application compiled with .NET (C#). Runs on Windows and it should run in a 32 bit process.
To set up my gemspec, I set:
Gem::Specification.new do |s|
s.platform = 'mswin32'
s.name = 'roundhouse'
s.version = version
s.files = Dir['lib/**/*'] + Dir['bin/**/*']
s.bindir = 'bin'
s.executables << 'rh.exe'
When I install the gem, I should be able to type rh.exe from the command line at any path and it should run correctly.
In practice, I'm not seeing this work correctly. This is what I'm getting back:
Window has this for the header: 16 bit MS-DOS Subsystem
C:\WINDOWS\system32\cmd.exe - rh.exe
The NTVDM CPU has encountered an illegal instruction.
CS:xxxx IP:xxxx OP:xx xx xx xx xx Choose 'Close' to terminate the application.
Here is a picture of the issue (link to TwitPic): Error
If I go to the directory where the item was installed, I can run it and it works great. It's just something in the registration of the command to run from anywhere.
I did quite a bit of searching before asking and came up with nothing. It could be that I don't know what I should be searching for. So let me ask the question, is there a way to register an executable with gems for windows executable applications (built with .NET) and have them register properly with the command line? If so, how is that done?
UPDATE:
I found that gems creates a shim in the C:\Ruby\bin directory that points back to the other file. So there is a rh.exe file that is really just a text file. This is its contents:
#!C:/Ruby/bin/ruby.exe
#
# This file was generated by RubyGems.
#
# The application 'roundhouse' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0"
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
version = $1
ARGV.shift
end
gem 'roundhouse', version
load Gem.bin_path('roundhouse', 'rh.exe', version)
if you're distributing it with the file "rh.exe"
then you'll want to create a file
bin/rh
s.executables << 'bin/rh'
then when it's installed gems will create an "rh.bat" file which runs ruby "bin/rh" essentially (as you've seen).
So within bin/rh put something like
result = system(File.dirname(__FILE__) + "/rh.exe" ARGV.join(' '))
exit 1 unless result
result = system(File.dirname(__FILE__) + "/rh.exe " + ARGV.join(' '))
exit 1 unless result
So the endresult should maybe look like? note the space after 'rh.exe'