mirror of https://github.com/winsw/winsw
commit
80295db8d7
|
@ -5,7 +5,7 @@ Why?
|
|||
----
|
||||
Now, I think the first question that people would ask is, why another, when there's [Java Service Wrapper project](http://wrapper.tanukisoftware.org/doc/english/download.jsp) already available. The main reason for writing my own was the license — Java Service Wrapper project is in GPL (so that they can sell their commercial version in a different license), and that made it difficult for [Jenkins](http://jenkins-ci.org/) (which is under the MIT license) to use it.
|
||||
|
||||
Functionality-wise, there's really not much that's worth noting; the problem of wrapping a process as a Windows service is so well defined that there aren't really any room for substantial innovation. You basically write a configuration file specifying how you'd like your process to be launched, and we provide programmatic means to install/uninstall/start/stop services. Another notable different is that winsw can host any executable, whereas Java Service Wrapper can only host Java apps. Whether you like this or not depends on your taste, so I wouldn't claim mine is better. It's just different.
|
||||
Functionality-wise, there's really not much that's worth noting; the problem of wrapping a process as a Windows service is so well defined that there aren't really any room for substantial innovation. You basically write a configuration file specifying how you'd like your process to be launched, and we provide programmatic means to install/uninstall/start/stop services. Another notable difference is that winsw can host any executable, whereas Java Service Wrapper can only host Java apps. Whether you like this or not depends on your taste, so I wouldn't claim mine is better. It's just different.
|
||||
|
||||
As the name implies, this is for Windows only. Unix systems have their own conventions for daemons, so a good behaving Unix daemon should just be using launchd/upstart/SMF/etc, instead of custom service wrapper.
|
||||
|
||||
|
@ -49,7 +49,7 @@ Your renamed `winsw.exe` accepts the following commands:
|
|||
|
||||
Error reporting
|
||||
---------------
|
||||
Winsw uses WMI underneath, and as such it uses its error code as the exit code. See <a href="http://msdn.microsoft.com/en-us/library/aa389390(VS.85).aspx">MSDN article</a> for the complete list of exit code.
|
||||
Winsw uses WMI underneath, and as such it uses its error code as the exit code. See the MSDN article [Create method of the Win32_Service class] for the complete list of exit code.
|
||||
|
||||
When winsw is running as a service, more detailed error information is reported to the Windows event log.
|
||||
|
||||
|
@ -72,11 +72,9 @@ The `<download>` element in the configuration file also provides an useful build
|
|||
Restarting service from itself
|
||||
------------------------------
|
||||
To support self-restarting services, winsw exposes `WINSW_EXECUTABLE` environment variable into the forked process, which refers to the full path of `winsw.exe` that's managing the service.
|
||||
To restart the service from within, execute `%WINSW_EXECUTABLE% restart!`. Note that you are invoking `restart!` command, not `restart` command. This hidden command is a flavor of the `restart` operation,
|
||||
where winsw creates another winsw process in a separate process group, and restarts the service from there.
|
||||
To restart the service from within, execute `%WINSW_EXECUTABLE% restart!`. Note that you are invoking `restart!` command, not `restart` command. This hidden command is a flavor of the `restart` operation, where winsw creates another winsw process in a separate process group, and restarts the service from there.
|
||||
|
||||
This additional indirection is necessary because Windows Service Control Manager (SCM) will kill child processes recursively when it stops a service. SCM doesn't provide the restart operation
|
||||
as an atomic operation either, so winsw implements restart by a sequence of stop and start. The 2nd winsw process in a separate process group ensures that winsw can survive this massacre to
|
||||
This additional indirection is necessary because Windows Service Control Manager (SCM) will kill child processes recursively when it stops a service. SCM doesn't provide the restart operation as an atomic operation either, so winsw implements restart by a sequence of stop and start. The 2nd winsw process in a separate process group ensures that winsw can survive this massacre to
|
||||
execute the start call.
|
||||
|
||||
|
||||
|
@ -88,7 +86,7 @@ Winsw supports several different ways to capture stdout and stderr from the proc
|
|||
The `<logpath>` element specifies the directory in which the log files are created. If this element is absent, it'll default to the same directory where the configuration file resides.
|
||||
|
||||
### Append mode (default)
|
||||
In this mode, `myapp.out.log` nad `myapp.err.log` (where `myapp` is the base name of the executable and the configuration file) are created and outputs are simply appended to these files. Note that the file can get quite big.
|
||||
In this mode, `myapp.out.log` and `myapp.err.log` (where `myapp` is the base name of the executable and the configuration file) are created and outputs are simply appended to these files. Note that the file can get quite big.
|
||||
|
||||
<log mode="append"/>
|
||||
|
||||
|
@ -157,7 +155,7 @@ Configuration XML files can include environment variable expansions of the form
|
|||
|
||||
Configuration File Syntax
|
||||
-------------------------
|
||||
The behaviour of the service is controlled by the XML configuration file. The root element of this XML file must be `<service>`, and it supports the following child element.
|
||||
The behavior of the service is controlled by the XML configuration file. The root element of this XML file must be `<service>`, and it supports the following child element.
|
||||
|
||||
### id
|
||||
Specifies the ID that Windows uses internally to identify the service. This has to be unique among all the services installed in a system, and (while I haven't verified this) this must consist entirely out of alpha-numeric characters.
|
||||
|
@ -196,7 +194,7 @@ This element specifies the arguments to be passed to the executable. Winsw will
|
|||
For backward compatibility, `<arguments>` element can be used instead to specify the whole command line in a single element.
|
||||
|
||||
### stopargument/stopexecutable
|
||||
When the service is requested to stop, winsw simply calls <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms686714(v=vs.85).aspx">TerminateProcess</a> API to kill the service instantly. However, if `<stopargument>` elements are present, winsw will instead launch another process of `<executable>` (or `<stopexecutable>` if that's specified) with the `<stopargument>` arguments, and expects that to initiate the graceful shutdown of the service process.
|
||||
When the service is requested to stop, winsw simply calls [TerminateProcess] API to kill the service instantly. However, if `<stopargument>` elements are present, winsw will instead launch another process of `<executable>` (or `<stopexecutable>` if that's specified) with the `<stopargument>` arguments, and expects that to initiate the graceful shutdown of the service process.
|
||||
|
||||
Winsw will then wait for the two processes to exit on its own, before reporting back to Windows that the service has terminated.
|
||||
|
||||
|
@ -212,7 +210,7 @@ When you use the `<stopargument>`, you must use `<startargument>` instead of `<a
|
|||
Note that the name of the element is `startargument` and not `startarguments`. As such, to specify multiple arguments, you'll specify multiple elements.
|
||||
|
||||
### stoptimeout
|
||||
When the service is requested to stop, winsw first attempts to <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms683155(v=vs.85).aspx">send Ctrl+C signal to the process</a>, then wait for up to 15 seconds for the process to exit by itself gracefully. A process failing to do that (or if the process does not have a console), then winsw resorts to calling <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms686714(v=vs.85).aspx">TerminateProcess</a> API to kill the service instantly.
|
||||
When the service is requested to stop, winsw first attempts to [send Ctrl+C signal to the process], then wait for up to 15 seconds for the process to exit by itself gracefully. A process failing to do that (or if the process does not have a console), then winsw resorts to calling [TerminateProcess] API to kill the service instantly.
|
||||
|
||||
This optional element allows you to change this "15 seconds" value, so that you can control how long winsw gives the service to shut itself down. See `<onfailure>` below for how to specify time duration:
|
||||
|
||||
|
@ -243,11 +241,6 @@ This is another useful building block for developing a self-updating service.
|
|||
### log
|
||||
See the "Logging" section above for more details.
|
||||
|
||||
### workingdirectory
|
||||
This optional element sets the current directory of the process launched by winsw.
|
||||
|
||||
<workingdirectory>%SystemDrive%\</workingdirectory>
|
||||
|
||||
### onfailure
|
||||
This optional repeatable element controls the behaviour when the process launched by winsw fails (i.e., exits with non-zero exit code).
|
||||
|
||||
|
@ -284,7 +277,7 @@ It is possible to specify the useraccount (and password) that the service will r
|
|||
<allowservicelogon>true</allowservicelogon>
|
||||
</serviceaccount>
|
||||
|
||||
The <allowservicelogon> is optional. If set to true, will automatically set the "Allow Log On As A Service" right to the listed account.
|
||||
The `<allowservicelogon>` is optional. If set to true, will automatically set the "Allow Log On As A Service" right to the listed account.
|
||||
|
||||
### Working directory
|
||||
Some services need to run with a working directory specified. To do this, specify a `<workingdirectory>` element like this:
|
||||
|
@ -297,10 +290,10 @@ Possible values are `idle`, `belownormal`, `normal`, `abovenormal`, `high`, `rea
|
|||
|
||||
<priority>idle</priority>
|
||||
|
||||
Specifying a priority higher than normal has unintended consequences. See <a href="http://msdn.microsoft.com/en-us/library/system.diagnostics.processpriorityclass(v=vs.110).aspx">MSDN discussion</a> for details. This feature is intended primarily to launch a process in a lower priority so as not to interfere with the computer's interactive usage.
|
||||
Specifying a priority higher than normal has unintended consequences. See the MSDN article [ProcessPriorityClass Enumeration] for details. This feature is intended primarily to launch a process in a lower priority so as not to interfere with the computer's interactive usage.
|
||||
|
||||
###stopparentprocessfirst
|
||||
Optionally specify the order of service shutdown. If true, the parent process is shutdown first. This is useful when the main process is a console, which can respond to Ctrol+C command and will gracefully shutdown child processes
|
||||
Optionally specify the order of service shutdown. If true, the parent process is shutdown first. This is useful when the main process is a console, which can respond to Ctrl+C command and will gracefully shutdown child processes
|
||||
```
|
||||
<stopparentprocessfirst>true</stopparentprocessfirst>
|
||||
```
|
||||
|
@ -330,3 +323,7 @@ Developer info
|
|||
[winsw-1.17]: https://github.com/kohsuke/winsw/milestones/winsw-1.17
|
||||
[winsw-1.17-beta.2]: https://github.com/kohsuke/winsw/releases/tag/1.17-beta.2
|
||||
[WinSW-2.0]: https://github.com/kohsuke/winsw/milestones/winsw-2.0
|
||||
[TerminateProcess]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686714(v=vs.85).aspx "TerminateProcess function"
|
||||
[Create method of the Win32_Service class]: http://msdn.microsoft.com/en-us/library/aa389390(VS.85).aspx
|
||||
[send Ctrl+C signal to the process]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683155(v=vs.85).aspx "GenerateConsoleCtrlEvent function"
|
||||
[ProcessPriorityClass Enumeration]: http://msdn.microsoft.com/en-us/library/system.diagnostics.processpriorityclass(v=vs.110).aspx
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash -ex
|
||||
export "PATH=$PATH:/cygdrive/c/Program Files/Windows Kits/8.1/bin/x86"
|
||||
for f in Release Debug;
|
||||
do
|
||||
signtool sign /f winsw_cert.pfx /t http://timestamp.verisign.com/scripts/timestamp.dll bin/$f/winsw.exe
|
||||
signtool verify /v /pa bin/$f/winsw.exe
|
||||
done
|
||||
echo success
|
|
@ -28,5 +28,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.17.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.17.0.0")]
|
||||
[assembly: AssemblyVersion("1.19.1.0")]
|
||||
[assembly: AssemblyFileVersion("1.19.1.0")]
|
||||
|
|
|
@ -1,71 +1,57 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.sun.winsw</groupId>
|
||||
<artifactId>winsw</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.17</version>
|
||||
<name>Windows service wrapper</name>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>maven.jenkins-ci.org</id>
|
||||
<url>http://maven.jenkins-ci.org:8081/content/repositories/releases</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- fake out maven and install the binary artifact -->
|
||||
<plugin>
|
||||
<groupId>org.jvnet.maven-antrun-extended-plugin</groupId>
|
||||
<artifactId>maven-antrun-extended-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<attachArtifact file="bin/Release/winsw.exe" type="exe" classifier="bin" />
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<extensions>
|
||||
<extension>
|
||||
<groupId>org.jvnet.wagon-svn</groupId>
|
||||
<artifactId>wagon-svn</artifactId>
|
||||
<version>1.9</version>
|
||||
</extension>
|
||||
</extensions>
|
||||
</build>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The MIT license</name>
|
||||
<url>http://www.opensource.org/licenses/mit-license.php</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>maven2-repository.dev.java.net</id>
|
||||
<name>Java.net Repository for Maven</name>
|
||||
<url>http://download.java.net/maven/2/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>maven2-repository.dev.java.net</id>
|
||||
<name>Java.net Repository for Maven</name>
|
||||
<url>http://download.java.net/maven/2/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</project>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.sun.winsw</groupId>
|
||||
<artifactId>winsw</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.19.2-SNAPSHOT</version>
|
||||
<name>Windows service wrapper</name>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>maven.jenkins-ci.org</id>
|
||||
<url>https://repo.jenkins-ci.org/releases/</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:ssh://github.com/kohsuke/winsw.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/kohsuke/winsw.git</developerConnection>
|
||||
<url>https://github.com/kohsuke/winsw</url>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</plugin>
|
||||
<!-- fake out maven and install the binary artifact -->
|
||||
<plugin>
|
||||
<groupId>org.jvnet.maven-antrun-extended-plugin</groupId>
|
||||
<artifactId>maven-antrun-extended-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<attachArtifact file="bin/Release/winsw.exe" type="exe" classifier="bin" />
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The MIT license</name>
|
||||
<url>http://www.opensource.org/licenses/mit-license.php</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
</project>
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace winsw
|
|||
dom.Load(BasePath + ".xml");
|
||||
|
||||
// register the base directory as environment variable so that future expansions can refer to this.
|
||||
Environment.SetEnvironmentVariable("BASE", p);
|
||||
Environment.SetEnvironmentVariable("BASE", d.FullName);
|
||||
// ditto for ID
|
||||
Environment.SetEnvironmentVariable("SERVICE_ID", Id);
|
||||
Environment.SetEnvironmentVariable("WINSW_EXECUTABLE", ExecutablePath);
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.21022</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{0DE77F55-ADE5-43C1-999A-0BC81153B039}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>winsw</RootNamespace>
|
||||
<AssemblyName>winsw</AssemblyName>
|
||||
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<StartupObject>
|
||||
</StartupObject>
|
||||
<SignManifests>false</SignManifests>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>winsw_cert.pfx</AssemblyOriginatorKeyFile>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.ServiceProcess" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Advapi32.cs" />
|
||||
<Compile Include="Download.cs" />
|
||||
<Compile Include="DynamicProxy.cs" />
|
||||
<Compile Include="Kernel32.cs" />
|
||||
<Compile Include="LogAppenders.cs" />
|
||||
<Compile Include="Main.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="PeriodicRollingCalendar.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ServiceDescriptor.cs" />
|
||||
<Compile Include="SigIntHelper.cs" />
|
||||
<Compile Include="Wmi.cs" />
|
||||
<Compile Include="WmiSchema.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="manifest.xml" />
|
||||
<Content Include="pom.xml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="winsw.xml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="winsw_cert.pfx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue