Показать сообщение отдельно
  #1  
Старый 12.03.2017, 15:03
tsa tsa вне форума
Прохожий
 
Регистрация: 12.03.2017
Сообщения: 3
Версия Delphi: Delphi 2010
Репутация: 10
Вопрос Чтение данных Exif файла jpg

Прошу помочь с решением следующей проблемы. Я написал функцию FileSetDateExif, устанавливающую время модификации файла JPG равным времени его создания 'CreateDate', прописанному в Exif. Функция необходима для сведения в один временной ряд уже модифицированных файлов JPG от разных фотоаппаратов.
Выполнение данной функции сопровождается возникновением исключения "Project … raised exception class EExternalException with message ‘External exception c0000002’" при установке времени каждого файла.
Проблему частично решил обрамлением вызова функции конструкцией "try ... except" и установкой опции игнорирования данного сообщения. Однако видимо есть еще иные побочные эффекты упомянутого выше исключения, так как после вызова написанной функции при работе встроенного мною в оболочку моего программного комплекса медиаплеера стали возникать невиданные ранее прерывания от access violation до полного вылета программы.
Работу функции исследовал под Windows 7 x64, Delphi 2010. Путем последовательного комментирования операторов установил, что возникновение исключения при выполнении оператора SetFileTime(hndl,nil,nil,@aFileTime) происходит если ранее выполнялся оператор WicDecoder.GetFrame(0,FrameDecode).
Буду благодарен за любой совет, так как собственная фантазия уже исчерпалась. Также буду благодарен за любое прояснение ситуации по характеристике возникающего исключения.

Ответ на вопрос дан lmikle : "вызывать _release напрямую не рекомендуется... достаточно просто ... присвоить Nil".
Приведенный ниже код исправлен в соответствии с данной рекомендацией и теперь работает безукоризненно.


Код:
unit uHDDCam;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, MMSystem, Math, Mask, ExtCtrls, ComCtrls, Buttons, uChildAis,
  ToolWin, DateUtils, wincodec, ComObj, ValEdit, ActiveX;
.........................................................

var
  fmHDDCam: TfmHDDCam;
  function TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation: PTimeZoneInformation;
   var lpLocalTime, lpUniversalTime: TSystemTime): BOOL; stdcall;
  function SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation: PTimeZoneInformation;
   var lpUniversalTime,lpLocalTime: TSystemTime): BOOL; stdcall;

implementation

uses ....................................................;

  function TzSpecificLocalTimeToSystemTime; external kernel32 name 'TzSpecificLocalTimeToSystemTime';
  function SystemTimeToTzSpecificLocalTime; external kernel32 name 'SystemTimeToTzSpecificLocalTime';

{$R *.dfm}

function FileSetDateExif : Integer;
  var
    WicFactory                    : IWICImagingFactory;
    WicDecoder                    : IWICBitmapDecoder;
    FrameDecode                   : IWICBitmapFrameDecode;
    mdReader                      : IWICMetadataQueryReader;
    Prop                          : TPropVariant;
    hndl                          : THandle;
    NewTime                       : TDateTime;
    tzi                           : TTimeZoneInformation;
    LocalTime,UniversalTime       : TSystemTime;
    aFileTime                     : TFileTime;
begin
  Result:=0;
  hndl:=CreateFile(PChar(LastSelectImageName),GENERIC_READ or GENERIC_WRITE,
   0,nil,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0);
  if hndl=THandle(-1) then Result:=GetLastError {INVALID_HANDLE_VALUE}
  else
  begin
    try
      WicFactory:=CreateComObject(CLSID_WICImagingFactory) as IWICImagingFactory;
      WicFactory.CreateDecoderFromFileHandle(hndl,TGUID(nil^),WICDecodeMetadataCacheOnDemand,WicDecoder);
      WicFactory:=nil;
      {выполнение следующего оператора приводит к ошибке при записи времени файла!!!}
      WicDecoder.GetFrame(0,FrameDecode);
      WicDecoder:=nil;
      if FrameDecode.GetMetadataQueryReader(mdReader)<>S_OK then
      begin
        ShowMessage('Не могу прочесть Exif '+LastSelectImageName);
        System.Exit;
      end;
      FrameDecode:=nil;
      zeroMemory(@Prop,SizeOf(Prop));
      mdReader.GetMetadataByName('/xmp/CreateDate',prop);
      mdReader:=nil;
      s:=String(Prop.pwszVal);
      s:=BackDateToRight(s);
      NewTime:=StrToDateTime(s);
      GetTimeZoneInformation(tzi);
      DateTimeToSystemTime(NewTime,LocalTime);
      {локальное время файла пересчитывается с учетом часового пояса}
      TzSpecificLocalTimeToSystemTime(@tzi,LocalTime,UniversalTime);
      SystemTimeToFileTime(UniversalTime,aFileTime);
      if SetFileTime(hndl,nil,nil,@aFileTime) then System.Exit;
      Result:=GetLastError;
    finally
      FileClose(hndl);
    end; {finally}
  end; {hndl<>THandle(-1)}
end; {FileSetDateExif}
Ответить с цитированием