質問

私は現在アプリを表示するビルド番号、タイトルウインドウです。いつも大勢の客でにぎわっていると良以外でも多くのユーザーを知りたい場合に最新ビルドの傾向を強めてください"と申し"ではなく構築1.0.8.4321.

プランの構築がない"アプリ設21/10/2009"です。

どうしたらいいのかと悩んくプを引っ張の日として、テキスト文字列を使用。

ビルドの数、利用

Assembly.GetExecutingAssembly().GetName().Version.ToString()

後を定義するどのようになってしまうのです。

思うにコンパイル日時に変更、ボーナスポイント)。

ポインタのこちらよろしくお願いいたします(言い訳pun適切な場合には、neaterュ...

役に立ちましたか?

解決

Jeff Atwoodたものを考えることでこの問題に 決定の構築日付の方法.

最も信頼性の高い方法が検索のリンカーのタイムスタンプから PEヘッダー 組み込み、実行可能ファイル--一部のC#コードによるスパイヴィジョー)からのコメントをJeffの記事:

public static DateTime GetLinkerTime(this Assembly assembly, TimeZoneInfo target = null)
{
    var filePath = assembly.Location;
    const int c_PeHeaderOffset = 60;
    const int c_LinkerTimestampOffset = 8;

    var buffer = new byte[2048];

    using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        stream.Read(buffer, 0, 2048);

    var offset = BitConverter.ToInt32(buffer, c_PeHeaderOffset);
    var secondsSince1970 = BitConverter.ToInt32(buffer, offset + c_LinkerTimestampOffset);
    var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    var linkTimeUtc = epoch.AddSeconds(secondsSince1970);

    var tz = target ?? TimeZoneInfo.Local;
    var localTime = TimeZoneInfo.ConvertTimeFromUtc(linkTimeUtc, tz);

    return localTime;
}

使用例:

var linkTimeLocal = Assembly.GetExecutingAssembly().GetLinkerTime();

更新:の方法です。純Core1.0、 が停止しました。純核1.1 リリース(ランダムに与え年1900-2020範囲)

他のヒント

以下の内容を追加します事前に構築-イベントのコマンドライン:

echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt"

追加するこのファイルとして資源 現在持っている方は、ログインするとBuildDate'文字列に資源です。

創出さないように 作成方法や利用資源です。当期純.

方法

指摘しているように@c00000fdの コメント.マイクロソフトが変化する。多くの方んの最新バージョンのコンパイラこの変更によりこのアプローチに恵ます。がん"にとことんこだわり行使のものをお勧めします人々で埋め込みの構築日をバイナリを通じてその他必要な場合での重要なトラックの日付のバイナリーそのものです。

これを行うにあなコードを生成する、あるいは最初の段階で構成スクリプトです。が、このALM/Build/DevOpsのツールを多くすべきものが好ましい。

私はこの答えがここに歴史のみを目的としています。

の新しい方

しようと思いましたこと、現在このフレキシビリティの構築。

#region Gets the build date and time (by reading the COFF header)

// http://msdn.microsoft.com/en-us/library/ms680313

struct _IMAGE_FILE_HEADER
{
    public ushort Machine;
    public ushort NumberOfSections;
    public uint TimeDateStamp;
    public uint PointerToSymbolTable;
    public uint NumberOfSymbols;
    public ushort SizeOfOptionalHeader;
    public ushort Characteristics;
};

static DateTime GetBuildDateTime(Assembly assembly)
{
    var path = assembly.GetName().CodeBase;
    if (File.Exists(path))
    {
        var buffer = new byte[Math.Max(Marshal.SizeOf(typeof(_IMAGE_FILE_HEADER)), 4)];
        using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            fileStream.Position = 0x3C;
            fileStream.Read(buffer, 0, 4);
            fileStream.Position = BitConverter.ToUInt32(buffer, 0); // COFF header offset
            fileStream.Read(buffer, 0, 4); // "PE\0\0"
            fileStream.Read(buffer, 0, buffer.Length);
        }
        var pinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        try
        {
            var coffHeader = (_IMAGE_FILE_HEADER)Marshal.PtrToStructure(pinnedBuffer.AddrOfPinnedObject(), typeof(_IMAGE_FILE_HEADER));

            return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1) + new TimeSpan(coffHeader.TimeDateStamp * TimeSpan.TicksPerSecond));
        }
        finally
        {
            pinnedBuffer.Free();
        }
    }
    return new DateTime();
}

#endregion

古い方法

いったいどの部分を作っているのだ創造番号?Visual StudioまたはC#のコンパイラが実際に自動構築ョン番号のご変更をご希望の場合AssemblyVersion属性など 1.0.*

何が起こることは、構築するような感じでという疑問を表す日年1月から2000年現地時間は、修正するような感じでという疑問を表す秒から深夜現地時間で割った2.

参照会内容 自動構築ョン番号

例えばAssemblyInfo.cs

[assembly: AssemblyVersion("1.0.*")] // important: use wildcard for build and revision numbers!

SampleCode.cs

var version = Assembly.GetEntryAssembly().GetName().Version;
var buildDateTime = new DateTime(2000, 1, 1).Add(new TimeSpan(
TimeSpan.TicksPerDay * version.Build + // days since 1 January 2000
TimeSpan.TicksPerSecond * 2 * version.Revision)); // seconds since midnight, (multiply by 2 to get original)

以下の内容を追加します事前に構築-イベントのコマンドライン:

echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt"

このファイルの追加については、現在持っている方は、ログインするとBuildDate'文字列に資源です。

を挿入する前にファイルを資源として公共のテキストファイル)、アクセスで

string strCompTime = Properties.Resources.BuildDate;

創出さないように 作成方法や利用資源です。当期純.

そのひとつである私を驚かせいた上で使用 T4テキストテンプレート コード。

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System" #>
<#@ output extension=".g.cs" #>
using System;
namespace Foo.Bar
{
    public static partial class Constants
    {
        public static DateTime CompilationTimestampUtc { get { return new DateTime(<# Write(DateTime.UtcNow.Ticks.ToString()); #>L, DateTimeKind.Utc); } }
    }
}

メリット:

  • ロケール非依存
  • できるだけでなく、より多くの時間を作成

連結:

に関する技術の引きの構築日-バージョン情報からのバイトの組立PE、ヘッダー、マイクロソフト社のデフォルトのパラメータの構築を始めVisual Studio15.4.そのインデックスを含む決定的な編集、有効なタイムスタンプを自動的に値を書き込むバージョン番号のものです。タイムスタンプの分野は現在のもので満たされた永続的な価値であるハッシュのものその他のものは表示の構築。

一部の詳細な背景をここに

を優先した場合でも、有効なタイムスタンプの上決定性コンパイル方法はありますのでオーバーライドの新しいデフォルトです。することができるaタグに出ます。csprojファイルの組み立て利益として

  <PropertyGroup>
      ...
      <Deterministic>false</Deterministic>
  </PropertyGroup>

更新:私の推奨をT4テキストテンプレート溶液に記載の他に答えます。私は使用で解決問題を綺麗にな利益を確作成する。一つについてのご注意であるVisual Studioのみの運行で、T4コンパイラが。ttファイルの保存ではなく、構築す。このきく場合を除きます。cs結果をソースから制御まで発生させ、他の開発をチェックアウトしたものです。なresavingています。csファイルです。あのパッケージにnuget(いというAutoT4)T4編成の一部なの。ありませんどうしたらいいのに直面し解決すが、生産の展開が期待するようなものです。

私はC#のピう私の回答の音ゃっ表示の構築日付の日から実行ファイルが最後に書き込:

string w_file = "MyProgram.exe"; 
string w_directory = Directory.GetCurrentDirectory();

DateTime c3 =  File.GetLastWriteTime(System.IO.Path.Combine(w_directory, w_file));
RTB_info.AppendText("Program created at: " + c3.ToString());

私は利用しようとしたファイルです。GetCreationTime方法だって変な結果:の日からのコマンド2012-05-29が、日付窓からExplorerた2012-05-23.索した後、この不一致することを見いだし,そのファイルも作成された2012-05-23とWindows Explorer)がコピーされ、現在のフォルダ2012-05-29とによりファイルです。GetCreationTimeコマンド)しているのに使用しています。GetLastWriteTimeコマンドです。

Zalek

誰でもそのニーズをコンパイル時にWindows8/Windows Phone8:

    public static async Task<DateTimeOffset?> RetrieveLinkerTimestamp(Assembly assembly)
    {
        var pkg = Windows.ApplicationModel.Package.Current;
        if (null == pkg)
        {
            return null;
        }

        var assemblyFile = await pkg.InstalledLocation.GetFileAsync(assembly.ManifestModule.Name);
        if (null == assemblyFile)
        {
            return null;
        }

        using (var stream = await assemblyFile.OpenSequentialReadAsync())
        {
            using (var reader = new DataReader(stream))
            {
                const int PeHeaderOffset = 60;
                const int LinkerTimestampOffset = 8;

                //read first 2048 bytes from the assembly file.
                byte[] b = new byte[2048];
                await reader.LoadAsync((uint)b.Length);
                reader.ReadBytes(b);
                reader.DetachStream();

                //get the pe header offset
                int i = System.BitConverter.ToInt32(b, PeHeaderOffset);

                //read the linker timestamp from the PE header
                int secondsSince1970 = System.BitConverter.ToInt32(b, i + LinkerTimestampOffset);

                var dt = new DateTimeOffset(1970, 1, 1, 0, 0, 0, DateTimeOffset.Now.Offset) + DateTimeOffset.Now.Offset;
                return dt.AddSeconds(secondsSince1970);
            }
        }
    }

誰でもそのニーズをコンパイル時にはWindows Phone7:

    public static async Task<DateTimeOffset?> RetrieveLinkerTimestampAsync(Assembly assembly)
    {
        const int PeHeaderOffset = 60;
        const int LinkerTimestampOffset = 8;            
        byte[] b = new byte[2048];

        try
        {
            var rs = Application.GetResourceStream(new Uri(assembly.ManifestModule.Name, UriKind.Relative));
            using (var s = rs.Stream)
            {
                var asyncResult = s.BeginRead(b, 0, b.Length, null, null);
                int bytesRead = await Task.Factory.FromAsync<int>(asyncResult, s.EndRead);
            }
        }
        catch (System.IO.IOException)
        {
            return null;
        }

        int i = System.BitConverter.ToInt32(b, PeHeaderOffset);
        int secondsSince1970 = System.BitConverter.ToInt32(b, i + LinkerTimestampOffset);
        var dt = new DateTimeOffset(1970, 1, 1, 0, 0, 0, DateTimeOffset.Now.Offset) + DateTimeOffset.Now.Offset;
        dt = dt.AddSeconds(secondsSince1970);
        return dt;
    }

注意:すべての場合まで、サンドボックスがありますので,そこでしっかけを手に入れることができるコンパイル時間のアセンブリでの展開とアプリです。(これは動作しませんなどから、GAC).

上記の方法で調整のためのアセンブリ 既にロードプロセスの のファイルのイメージメモリに対して再読んでから保管):

using System;
using System.Runtime.InteropServices;
using Assembly = System.Reflection.Assembly;

static class Utils
{
    public static DateTime GetLinkerDateTime(this Assembly assembly, TimeZoneInfo tzi = null)
    {
        // Constants related to the Windows PE file format.
        const int PE_HEADER_OFFSET = 60;
        const int LINKER_TIMESTAMP_OFFSET = 8;

        // Discover the base memory address where our assembly is loaded
        var entryModule = assembly.ManifestModule;
        var hMod = Marshal.GetHINSTANCE(entryModule);
        if (hMod == IntPtr.Zero - 1) throw new Exception("Failed to get HINSTANCE.");

        // Read the linker timestamp
        var offset = Marshal.ReadInt32(hMod, PE_HEADER_OFFSET);
        var secondsSince1970 = Marshal.ReadInt32(hMod, offset + LINKER_TIMESTAMP_OFFSET);

        // Convert the timestamp to a DateTime
        var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        var linkTimeUtc = epoch.AddSeconds(secondsSince1970);
        var dt = TimeZoneInfo.ConvertTimeFromUtc(linkTimeUtc, tzi ?? TimeZoneInfo.Local);
        return dt;
    }
}

オプションに触れられていないこちらのサイトのサービスを自分のデータAssemblyInfo.csは、"AssemblyInformationalVersion"が適してカップルのプロジェクトまたこのようなものとしてビルドステップ(しん完全には満足していた再現しましたか).

あの記の対象にcodeproject: http://www.codeproject.com/KB/dotnet/Customizing_csproj_files.aspx

ます。ネコアプロジェクトでは、わたしに適応したPostlagerkarteの回答を更新議会著作権分野の構築。

を直接編集csproj

以下の直接添加できるの PropertyGroup のcsproj:

<Copyright>Copyright © $([System.DateTime]::UtcNow.Year) Travis Troyer ($([System.DateTime]::UtcNow.ToString("s")))</Copyright>

代替:Visual Studioプロジェクト特性

又はペーストの内部表現は著作権の分野のパッケージのプロジェクト特性Visual Studio:

Copyright © $([System.DateTime]::UtcNow.Year) Travis Troyer ($([System.DateTime]::UtcNow.ToString("s")))

このとき少し混乱し、Visual Studioの評価の表現は、現在表示されている値の窓も更新のプロジェクトファイルを適切にコンプライアンス-

液-広由ンをクリックします。ます。道具

すぐに <Copyright> 要素の上へ Directory.Build.props ファイルをソリューションルートで自動的に付加されるすべてのプロジェクト内のディレクトリを想定し、各プロジェクトについては、独自の著作権の値です。

<Project>
 <PropertyGroup>
   <Copyright>Copyright © $([System.DateTime]::UtcNow.Year) Travis Troyer ($([System.DateTime]::UtcNow.ToString("s")))</Copyright>
 </PropertyGroup>
</Project>

ディレクトリです。ます。小道具: カスタマイズの構築

出力

例を表現する著作権のようになります:

Copyright © 2018 Travis Troyer (2018-05-30T14:46:23)

検索

示できる著作権についての情報ファイルからの物件は、Windows、またはブ実行時:

var version = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location);

Console.WriteLine(version.LegalCopyright);

多くの回答をこちらがように感じて追加する事ができます自分で簡単の性能比較する資源に関連するソリューション)クロスプラットフォーム(Netコアのすぎ)回避の第3者ツールです。だけで追加しますmsbuild対象にcsproj.

<Target Name="Date" BeforeTargets="CoreCompile">
    <WriteLinesToFile File="$(IntermediateOutputPath)gen.cs" Lines="static partial class Builtin { public static long CompileTime = $([System.DateTime]::UtcNow.Ticks) %3B }" Overwrite="true" />
    <ItemGroup>
        <Compile Include="$(IntermediateOutputPath)gen.cs" />
    </ItemGroup>
</Target>

とを今回も実施しました。 Builtin.CompileTime または new DateTime(Builtin.CompileTime, DateTimeKind.Utc) 請求-お問い合わせはこちらすることができてうれしいです。

簡単に、ios、androidとmac用にc#なっていただいております。きを無視してはならない追加の部分クラスのプロジェクトもできます。

2018年の上解決しない動作しなくなったりしないするのに用いられております。純ます。

私のプロジェクトのフォローアップが簡単に作れますネコ2.0ます。

以下のエントリを追加す。csprojのPropertyGroup:

    <Today>$([System.DateTime]::Now)</Today>

この定義 PropertyFunction アクセスでき事前のビルドコマンド.

ご予約の構築のようになります

echo $(today) > $(ProjectDir)BuildTimeStamp.txt

プロパティを設定しBuildTimeStamp.txt 組み込みます。

今までのタイムスタンプのようなこ

public static class BuildTimeStamp
    {
        public static string GetTimestamp()
        {
            var assembly = Assembly.GetEntryAssembly(); 

            var stream = assembly.GetManifestResourceStream("NamespaceGoesHere.BuildTimeStamp.txt");

            using (var reader = new StreamReader(stream))
            {
                return reader.ReadToEnd();
            }
        }
    }

いユニバーサル溶液としてのNETStandardプロジェクトプラットフォーム(iOS、Android、Windows.) そこで、私は自動的に生成するCSのファイルを介してPowerShellスクリプトこちらはPowerShellスクリプト:

param($outputFile="BuildDate.cs")

$buildDate = Get-Date -date (Get-Date).ToUniversalTime() -Format o
$class = 
"using System;
using System.Globalization;

namespace MyNamespace
{
    public static class BuildDate
    {
        public const string BuildDateString = `"$buildDate`";
        public static readonly DateTime BuildDateUtc = DateTime.Parse(BuildDateString, null, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
    }
}"

Set-Content -Path $outputFile -Value $class

保存のPowerScriptファイルとしてGenBuildDate.ps1に追加します。最後に、以下の行を追加のご予約の場を構築-イベント

powershell -File $(ProjectDir)GenBuildDate.ps1 -outputFile $(ProjectDir)BuildDate.cs

確BuildDate.csが含まれています。作品のようにシャン任意のOS!

かい:

File.GetCreationTime(GetType().Assembly.Location)

利用できるこのプロジェクト: https://github.com/dwcullop/BuildInfo

Itを活用しT4の自動化を構築日付時刻です。複数のバージョンが存在す(支店)を含めることはGitのハッシュは、現在貸出支店、さまざまな職種でさまざまなこういうことも得意なんですね。

情報開示私はモジュールです。

を使用できるプロジェクトポスト構築-イベントを書くテキストファイルのターゲットディレクトリは、現在のdatetime.きのことを指し、値する。ちょっとhackyができます。

くなったものかもしれな 構築Incrementer 役になっています。

別のウー向けのアプローチが使用MSBuildインラインでタスクの代わりにビルド時に入る文字列が返される財産のアプリです。このアプローチに成功し、アプリはXamarin.形Xamarin.Android、Xamarin.iOSます。

編集:

簡易移動してすべてのロジックの SetBuildDate.targets ファイルを使用 Regex の代わりに単純な文字列置き換えるようにファイルによって変わりますので各構築く"をリセット".

のMSBuildインラインでタスク定義の中に保存されたSetBuildDate.対象ファイルのXamarin.形プロジェクトのためにこの例):

<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' ToolsVersion="12.0">

  <UsingTask TaskName="SetBuildDate" TaskFactory="CodeTaskFactory" 
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
    <ParameterGroup>
      <FilePath ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Code Type="Fragment" Language="cs"><![CDATA[

        DateTime now = DateTime.UtcNow;
        string buildDate = now.ToString("F");
        string replacement = string.Format("BuildDate => \"{0}\"", buildDate);
        string pattern = @"BuildDate => ""([^""]*)""";
        string content = File.ReadAllText(FilePath);
        System.Text.RegularExpressions.Regex rgx = new System.Text.RegularExpressions.Regex(pattern);
        content = rgx.Replace(content, replacement);
        File.WriteAllText(FilePath, content);
        File.SetLastWriteTimeUtc(FilePath, now);

   ]]></Code>
    </Task>
  </UsingTask>

</Project>

メソッドを呼び出して、上記インラインでタスクをXamarin.形csprojファイルを対象BeforeBuild:

  <!-- 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.  -->
  <Import Project="SetBuildDate.targets" />
  <Target Name="BeforeBuild">
    <SetBuildDate FilePath="$(MSBuildProjectDirectory)\BuildMetadata.cs" />
  </Target>

FilePath 物件設定 BuildMetadata.cs ファイルのXamarin.形プロジェクトを含む単純なクラスの文字列プロパティ BuildDate, の構築に時間を置き換え:

public class BuildMetadata
{
    public static string BuildDate => "This can be any arbitrary string";
}

このファイルの追加 BuildMetadata.cs プロジェクト.ではないかということは毎の構築が可能にする方法を繰り返しビルドを繰り返し替える必要はありません。場合は省略されていてもソースを制御してから行ってください。

小型の"新しい"答えJhon.

を構築する必要がある道を利用するのではなく、コードベース文字列がASP.NET/MVC

    var codeBase = assembly.GetName().CodeBase;
    UriBuilder uri = new UriBuilder(codeBase);
    string path = Uri.UnescapeDataString(uri.Path);

き起追加ステップの構築プロセスに書き込みは日付のスタンプファイルで表示されます。

プロジェクトのプロパティタブの構築イベントのタブがあります。あるオプションを実行する前又は後のbuildコマンドです。

使用したAbdurrahimた。しかし、ただ奇妙な時間形式のもの略称で、日の一部として構築日例:日12/24/2017 13:21:05.43.いかに日だったの除去に使用部分文字列.

を追加した後に、 echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt"前作のイベントだったの

string strBuildDate = YourNamespace.Properties.Resources.BuildDate;
string strTrimBuildDate = strBuildDate.Substring(4).Remove(10);

の良いニュースはこちらではうまくいった。

このwindowsアプリを使えばできますの応用実行ファイルパス:新しいシステム。IO.FileInfo(願います。ExecutablePath).LastWriteTime.ToString("yyyy.MMになります。dd")

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top