Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.168 Beiträge
 
Delphi 12 Athens
 
#2

AW: Erstellungsdatum von BPL auslesen

  Alt 7. Jul 2011, 13:01
So, hier nun noch der Code, mit einer kleinen Änderung, welche notfalls die Datei sucht (gut für DLLs und BPLs), wenn man in seinem Programm deratige Infos anzeigen/prüfen möchte.

@CodLibMods: könnt ihr ja gerne mit dort in der CodeLib anhängen, wenn ihr wollt
http://www.delphipraxis.net/11694-da...date-time.html

Funktioniert mindestens seit Delphi 4 bis Delphi XE (beim 64 Bit XE2 müssen wir dann mal sehn, wie/ob es dort läuft)

Delphi-Quellcode:
// Nico Bendlin and himitsu
function GetImageLinkTimeStamp(Filename: String): TDateTime;
const
  INVALID_SET_FILE_POINTER = DWORD(-1);
  BorlandMagicTimeStamp = $2A425E19; // Delphi 4-6 (and above?) // jupp, mindestens bis XE, wobei es hier nicht mehr nötig ist, da seit D2009/D2010 endlich das Datum im NTHeader einkompiliert wird.
  FileTime1970: TFileTime = (dwLowDateTime:$D53E8000; dwHighDateTime:$019DB1DE);
type
  PImageSectionHeaders = ^TImageSectionHeaders;
  TImageSectionHeaders = array [Word] of TImageSectionHeader;
type
  PImageResourceDirectory = ^TImageResourceDirectory;
  TImageResourceDirectory = packed record
    Characteristics: DWORD;
    TimeDateStamp: DWORD;
    MajorVersion: Word;
    MinorVersion: Word;
    NumberOfNamedEntries: Word;
    NumberOfIdEntries: Word;
  end;
var
  FileHandle: THandle;
  BytesRead: DWORD;
  ImageDosHeader: TImageDosHeader;
  ImageNtHeaders: TImageNtHeaders;
  SectionHeaders: PImageSectionHeaders;
  Section: Word;
  ResDirRVA: DWORD;
  ResDirSize: DWORD;
  ResDirRaw: DWORD;
  ResDirTable: TImageResourceDirectory;
  FileTime: TFileTime;
  SearchFilename: String;
  Schrott: PChar;
begin
  Result := UnixTimeToDateTime(0);
  if GetModuleHandle(PChar(Filename)) <> 0 then begin
    SearchFilename := GetModuleName(GetModuleHandle(PChar(Filename)));
    if (SearchFilename <> '') and FileExists(SearchFilename) then Filename := SearchFilename;
  end;
  if ExtractFilePath(Filename) = 'then begin
    SetLength(SearchFilename, MAX_PATH-1);
    SetLength(SearchFilename, SearchPath(Pointer(ExtractFileDir(Filename)), PChar(ExtractFileName(Filename)), nil, MAX_PATH, PChar(SearchFilename), Schrott));
    if SearchFilename <> 'then Filename := SearchFilename;
  end;
  FileHandle := CreateFile(PChar(Filename), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
  if FileHandle <> INVALID_HANDLE_VALUE then
    try
      // Read MS-DOS header to get the offset of the PE32 header (not required on WinNT based systems - but mostly available)
      if not ReadFile(FileHandle, ImageDosHeader, SizeOf(TImageDosHeader), BytesRead, nil)
          or (BytesRead <> SizeOf(TImageDosHeader)) or (ImageDosHeader.e_magic <> IMAGE_DOS_SIGNATURE) then
        ImageDosHeader._lfanew := 0;
      // Read PE32 header (including optional header)
      if (SetFilePointer(FileHandle, ImageDosHeader._lfanew, nil, FILE_BEGIN) = INVALID_SET_FILE_POINTER)
          or not (ReadFile(FileHandle, ImageNtHeaders, SizeOf(TImageNtHeaders), BytesRead, nil)
          and (BytesRead = SizeOf(TImageNtHeaders))) then
        Exit;
      // Validate PE32 image header
      if ImageNtHeaders.Signature <> IMAGE_NT_SIGNATURE then
        Exit;
      // Seconds since 1970 (UTC)
      Result := UnixTimeToDateTime(ImageNtHeaders.FileHeader.TimeDateStamp);
      // Check for Borland's magic value for the link time stamp (we take the time stamp from the resource directory table)
      if ImageNtHeaders.FileHeader.TimeDateStamp = BorlandMagicTimeStamp then
        with ImageNtHeaders, FileHeader, OptionalHeader do begin
          // Validate Optional header
          if (SizeOfOptionalHeader < IMAGE_SIZEOF_NT_OPTIONAL_HEADER) or (Magic <> IMAGE_NT_OPTIONAL_HDR_MAGIC) then
            Exit;
          // Read section headers
          SectionHeaders := GetMemory(NumberOfSections * SizeOf(TImageSectionHeader));
          if Assigned(SectionHeaders) then
            try
              if (SetFilePointer(FileHandle, SizeOfOptionalHeader - IMAGE_SIZEOF_NT_OPTIONAL_HEADER, nil, FILE_CURRENT) = INVALID_SET_FILE_POINTER)
                  or not ReadFile(FileHandle, SectionHeaders^, NumberOfSections * SizeOf(TImageSectionHeader), BytesRead, nil)
                  and (BytesRead = NumberOfSections * SizeOf(TImageSectionHeader)) then
                Exit;
              // Get RVA and size of the resource directory
              with DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] do begin
                ResDirRVA := VirtualAddress;
                ResDirSize := Size;
              end;
              // Search for section which contains the resource directory
              ResDirRaw := 0;
              for Section := 0 to NumberOfSections - 1 do
              with SectionHeaders[Section] do
                if (VirtualAddress <= ResDirRVA) and (VirtualAddress + SizeOfRawData >= ResDirRVA + ResDirSize) then begin
                  ResDirRaw := PointerToRawData - (VirtualAddress - ResDirRVA);
                  Break;
                end;
              // Resource directory table found?
              if ResDirRaw = 0 then
                Exit;
              // Read resource directory table
              if (SetFilePointer(FileHandle, ResDirRaw, nil, FILE_BEGIN) = INVALID_SET_FILE_POINTER)
                  or not (ReadFile(FileHandle, ResDirTable, SizeOf(TImageResourceDirectory), BytesRead, nil)
                  and (BytesRead = SizeOf(TImageResourceDirectory))) then
                Exit;
              // Convert from DosDateTime to SecondsSince1970
              if DosDateTimeToFileTime(HiWord(ResDirTable.TimeDateStamp), LoWord(ResDirTable.TimeDateStamp), FileTime) then
                // FIXME: Borland's linker uses the local system time of the user who linked the executable image file. (is that information anywhere?)
                Result := UnixTimeToDateTime((ULARGE_INTEGER(FileTime).QuadPart - ULARGE_INTEGER(FileTime1970).QuadPart) div 10000000);
            finally
              FreeMemory(SectionHeaders);
            end;
        end;
    finally
      CloseHandle(FileHandle);
    end;
end;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 7. Jul 2011 um 14:09 Uhr)
  Mit Zitat antworten Zitat