我想在我的代碼中定義一個包含可執行文件的日期的常量。我當然希望自動化這個過程。如何自動將生成日期變爲可見的常量以便我的代碼生成?
我知道我可以使用例如Perl編寫一個預生成腳本來寫出包含日期的.inc
文件。我更喜歡使用更輕量級的解決方案,或許使用環境變量或構建變量。 msbuild是否提供了可以幫助你的變量?有誰知道這個問題的更好的解決方案?
我想在我的代碼中定義一個包含可執行文件的日期的常量。我當然希望自動化這個過程。如何自動將生成日期變爲可見的常量以便我的代碼生成?
我知道我可以使用例如Perl編寫一個預生成腳本來寫出包含日期的.inc
文件。我更喜歡使用更輕量級的解決方案,或許使用環境變量或構建變量。 msbuild是否提供了可以幫助你的變量?有誰知道這個問題的更好的解決方案?
你可以閱讀從可執行的PE header鏈接器時間戳:
uses
ImageHlp;
function LinkerTimeStamp(const FileName: string): TDateTime; overload;
var
LI: TLoadedImage;
begin
Win32Check(MapAndLoad(PChar(FileName), nil, @LI, False, True));
Result := LI.FileHeader.FileHeader.TimeDateStamp/SecsPerDay + UnixDateDelta;
UnMapAndLoad(@LI);
end;
對於當前模塊的加載的圖像,下面似乎工作:
function LinkerTimestamp: TDateTime; overload;
begin
Result := PImageNtHeaders(HInstance + Cardinal(PImageDosHeader(HInstance)^._lfanew))^.FileHeader.TimeDateStamp/SecsPerDay + UnixDateDelta;
end;
早期版本的德爾福沒有正確更新它,但它已經在德爾福2010左右得到修復。對於早期版本,我使用IDE plugin在成功編譯後自動更新它。
注意:該值存儲爲UTC,因此出於顯示目的您可能需要將其轉換爲適當的時區。
非常感謝。我不認爲這是可能的。我很高興現在問我! –
:-)歡迎,我很樂意幫忙! –
太棒了!您可以使用DateUtils例程轉換爲本地時間:'TTimeZone.Local.ToLocalTime()' –
DDevExtensions有一個選項可以將編譯日期和時間包含到versioninfo資源中。我想我沒有向你展示如何提取,從裏面的程序...
更新關於自動化生成:FinalBuilder也有類似的選項。
我使用我自己的版本資源。 DDevExtensions工具是否依賴於您使用內置工具? –
我不知道。你應該直接問安迪,以得到一個體面的答案。他通常很有幫助。 –
如果您使用/擁有JCL,那麼jclPEImage.PeReadLinkerTimeStamp()
可以完成您的工作。舊版本的Delphi沒有設置鏈接器時間戳,但AFAIK新版本(即它似乎與D2010一起工作)。
事實上TCompile不是德爾菲團結。 你可以找到它here, on EDN。 (只是該頁面的副本):
修改單元文件「Project.pas」的非可視組件。該文件包含項目編譯的日期和時間以及內部版本號。在TForm上添加此組件,然後設置項目路徑。這可以通過將插入符號放在ProjectPath屬性字段中,然後按ENTER鍵來完成。
在USES條款中包含「項目」;保存該項目,然後退出 Delphi。下次在Delphi中打開項目時,將創建單元文件 「Project.pas」。然後,每次在Delphi中運行 的程序時,單元文件將更新爲當前日期, 時間和內部版本號。
我使用FinalBuilder來完成我所有的構建,並且很容易添加一個實用程序,它將在編譯之前更新任何源文件,以搜索和修改變量或常量的定義。我確實建立了版本號,日期,以這種方式有意義的任何事情。
此代碼適用於較新的Delphi版本,將時間合併並將其轉換爲本地時間。
function GetExeBuildTime: TDateTime;
var
LI: TLoadedImage;
{$IF CompilerVersion >= 26.0}
m: TMarshaller;
{$IFEND}
timeStamp: Cardinal;
utcTime: TDateTime;
begin
{$IF CompilerVersion >= 26.0} //XE7 requires TMarshaller to convert to PAnsiChar
Win32Check(MapAndLoad(PAnsiChar(m.AsAnsi(ParamStr(0)).ToPointer), nil, @LI, False, True));
{$ELSE}
Win32Check(MapAndLoad(PAnsiChar(AnsiString(ParamStr(0))), nil, @LI, False, True));
{$IFEND}
timeStamp := LI.FileHeader.FileHeader.TimeDateStamp;
UnMapAndLoad(@LI);
utcTime := UnixToDateTime(timeStamp);
Result := TTimeZone.Local.ToLocalTime(utcTime);
end;
任何版本的德爾福,只是windows批量生成之前創建.inc文件。根本不需要IDE。
這裏的腳本:
REM CommandInterpreter: $(COMSPEC)
@echo off
setlocal enabledelayedexpansion
setlocal
rem determine project top level directory from command file name
set PRJDIR=%~dp0
cd %PRJDIR%
set BUILD_DATE_FILE=%PRJDIR%Source\BuildDate.inc
call :GetGurrentDateTime&set BUILD_YEAR=!current_year!&set BUILD_MONTH=!current_month!&set BUILD_DAY=!current_day!&set BUILD_TIME=!current_time!
echo const BUILD_YEAR = %BUILD_YEAR%;> "%BUILD_DATE_FILE%"
:: 3 letter name Apr for April
echo const BUILD_MONTH = '%BUILD_MONTH%';>> "%BUILD_DATE_FILE%"
echo const BUILD_DAY = %BUILD_DAY%;>> "%BUILD_DATE_FILE%"
echo const BUILD_TIME = '%BUILD_TIME%';>> "%BUILD_DATE_FILE%"
goto :EOF
echo Done
exit /b 0
:GetGurrentDateTime
rem GET CURRENT DATE
echo.>"%TEMP%\~.ddf"
makecab /D RptFileName="%TEMP%\~.rpt" /D InfFileName="%TEMP%\~.inf" -f "%TEMP%\~.ddf">nul
for /f "tokens=4,5,6,7" %%a in ('type "%TEMP%\~.rpt"') do (
if not defined current_date (
set "current_date=%%d-%%a-%%b"
set "current_time=%%c"
set "current_year=%%d"
set "current_month=%%a"
set "current_day=%%b"
)
)
在源代碼中只包括BuildDate.inc文件和使用consts BUILD_*
。
我自然會看EXE文件的'修改日期'和/或'創建日期'以標識這個,但不知道這可能是不同於官方建立日期 - 所以我評論而不是回答。 –
也就是說,使用'Application.ExeName'來獲取文件的屬性,讀取必要的日期。 –
@jerry可以修改。我想要建立exe時的日期,作爲一個常量 –