Прошу помочь с решением следующей проблемы. Я написал функцию 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}