{*******************************************************} { } { RecoverService } { } { Copyright (C) 2022 kku } { } {*******************************************************} unit RecoverService; interface uses System.SysUtils, System.Classes, Vcl.Graphics, Tocsg.Thread, ManagerPattern, Tocsg.Files, System.Generics.Collections; const KVBIN_FILES = 'afsr.dll|aiffsr.dll|asfsr.dll|assr.dll|awsr.dll|bentofio.dll|' + 'bkfsr.dll|bmpsr.dll|bzip2sr.dll|cabsr.dll|cbmap.map|chartbls.ux|' + 'csvsr.dll|dbxsr.dll|dcasr.dll|dcmsr.dll|difsr.dll|dmgsr.dll|' + 'dw4sr.dll|dxlsr.dll|emlsr.dll|emxsr.dll|encasesr.dll|entsr.dll|' + 'epubsr.dll|filter.exe|FilterDotNet.dll|filterfordotnet.dll|' + 'FilterTestDotNet.exe|foliosr.dll|formats.ini|gifsr.dll|' + 'hl7sr.dll|htmsr.dll|hwposr.dll|hwpsr.dll|ichatsr.dll|isosr.dll|' + 'iwsssr.dll|iwwpsr.dll|jpgsr.dll|jtdsr.dll|KeyViewFilter.dll|' + 'kpagrdr.dll|kpcatrdr.dll|kpdwgrdr.dll|kpdxfrdr.dll|kpemfrdr.dll|' + 'kpgflrdr.dll|kpgifrdr.dll|kpifcnvt.dll|kpifutil.dll|kpiwpgrdr.dll|' + 'kpmsordr.dll|kpodfrdr.dll|kpp40rdr.dll|kpp95rdr.dll|kpp97rdr.dll|' + 'kppctrdr.dll|kppicrdr.dll|kppng.dll|kpppxrdr.dll|kpprerdr.dll|' + 'kpprzrdr.dll|kpsdwrdr.dll|kpshwrdr.dll|kpwg2rdr.dll|kpwmfrdr.dll|' + 'kpwpgrdr.dll|kpxfdlrdr.dll|kv.lic|kvdecrypt.dll|kvfilter.dll|' + 'kvgzsr.dll|kvhqxsr.dll|kvhvp.dll|kvlangdetect.dll|kvolefio.dll|' + 'kvoop.exe|kvutil.dll|kvxconfig.ini|kvxpgsa.dll|kvxsssa.dll|' + 'kvxtract.dll|kvxwpsa.dll|kvzeesr.dll|kvzip.dll|kwad.dll|l123sr.dll|' + 'langdetectext.dll|lasr.dll|libpff.dll|license.ini|lzhsr.dll|' + 'macbinsr.dll|mbsr.dll|mbxsr.dll|mdbsr.dll|mhtsr.dll|Microsoft.VC80.CRT.manifest|' + 'mifsr.dll|misr.dll|mp3sr.dll|mpeg4sr.dll|mppsr.dll|msgsr.dll|' + 'msvcm80.dll|msvcp80.dll|msvcr80.dll|msw6sr.dll|mswsr.dll|mw6sr.dll|' + 'mw8sr.dll|mwsr.dll|mwssr.dll|mwxsr.dll|oa2sr.dll|odfsssr.dll|' + 'odfwpsr.dll|olesr.dll|onmsr.dll|oo3sr.dll|pdfsr.dll|pffsr.dll|' + 'pngsr.dll|pstnsr.dll|qpssr.dll|qpwsr.dll|rarsr.dll|riffsr.dll|' + 'rtfsr.dll|skypesr.dll|sosr.dll|sunadsr.dll|swfsr.dll|tarsr.dll|' + 'tifsr.dll|tnefsr.dll|tstxtract.exe|txtcnv.dll|unisr.dll|unzip.dll|' + 'utf8sr.dll|uudsr.dll|vsdsr.dll|wkssr.dll|wosr.dll|wp6sr.dll|' + 'wpmap.dll|wpmsr.dll|xlsbsr.dll|xlssr.dll|xlsxsr.dll|xmlsh.dll|' + 'xmlsr.dll|xpssr.dll|xywsr.dll|yimsr.dll|z7zsr.dll|langdetect.dat|' + 'TB_arabic_mac_ucs2.txt|TB_arabic_ucs2.txt|TB_ascii_ibm_ucs2.txt|' + 'TB_ascii_ucs2.txt|TB_chsimplified_ucs2.txt|TB_chtraditional_chsimplified.txt|' + 'TB_chtraditional_ucs2.txt|TB_cyrillicdos_ucs2.txt|TB_cyrillickoi8_ucs2.txt|' + 'TB_cyrillic_ucs2.txt|TB_easterneuropean_ucs2.txt|TB_greek_ucs2.txt|' + 'TB_hebrew_ucs2.txt|TB_iso8859.txt|TB_korean_ucs2.txt|TB_latin3_ucs2.txt|' + 'TB_latin5_ucs2.txt|TB_latin6_ucs2.txt|TB_latin7_ucs2.txt|TB_latin9_ucs2.txt|' + 'TB_northerneuropean_ucs2.txt|TB_shiftjis_ucs2.txt|TB_thai_ucs2.txt|' + 'TB_turkish_ucs2.txt|TB_ucs2chsimp_ucs2chtrad.txt|TB_ucs2chtrad_ucs2chsimp.txt|' + 'TB_unicode_entities.txt|TB_vietnamese_ucs2.txt|TB_westerneuropean_ucs2.txt|' + 'text_arabic_iso.txt|text_arabic_ucs2.txt|text_arabic_utf8.txt|' + 'text_arabic_win.txt|text_ascii.txt|text_ascii_ucs2.txt|text_ascii_utf8.txt|' + 'text_chsimplified.txt|text_chsimplified_ucs2.txt|text_chsimplified_utf8.txt|' + 'text_chtraditional.txt|text_chtraditional_chsimplified.keyview.txt|' + 'text_chtraditional_inv.txt|text_chtraditional_ucs2.keyview.txt|' + 'text_chtraditional_ucs2.txt|text_chtraditional_utf8.keyview.txt|' + 'text_chtraditional_utf8.txt|text_cyrillic_dos.txt|text_cyrillic_iso.txt|' + 'text_cyrillic_koi8.txt|text_cyrillic_ucs2.txt|text_cyrillic_utf8.txt|' + 'text_cyrillic_win.txt|text_easterneuropean_iso.txt|text_easterneuropean_ucs2.txt|' + 'text_easterneuropean_utf8.txt|text_easterneuropean_win.txt|text_euc.txt|' + 'text_greek_iso.txt|text_greek_ucs2.txt|text_greek_utf8.txt|text_greek_win.txt|' + 'text_hebrew_iso.txt|text_hebrew_ucs2.txt|text_hebrew_utf8.txt|' + 'text_hebrew_win.txt|text_jis.txt|text_jis_1.txt|text_katakana_shiftjis.txt|' + 'text_katakana_ucs2.txt|text_katakana_utf8.txt|text_korean.txt|text_korean_ucs2.txt|' + 'text_korean_utf8.txt|text_maori.ne.txt|text_maori.txt|text_maori_ucs2.txt|' + 'text_maori_utf8.txt|text_northerneuropean_iso.txt|text_northerneuropean_ucs2.txt|' + 'text_northerneuropean_utf8.txt|text_northerneuropean_win.txt|text_shiftjis.txt|' + 'text_shiftjis_ucs2.txt|text_shiftjis_utf8.txt|text_thai.txt|text_thai_ucs2.txt|' + 'text_thai_utf8.txt|text_turkish.txt|text_turkish_ucs2.txt|text_turkish_utf8.txt|' + 'text_utf8_1.keyview.txt|text_utf8_1.txt|text_utf8_1_to_jis.keyview.txt|' + 'text_utf8_1_to_jis.txt|text_vietnamese_ucs2.txt|text_vietnamese_utf8.txt|' + 'text_vietnamese_win.txt|text_westerneuropean.txt|text_westerneuropean_utf8.txt|'; CONF_FILES = 'eCrmHeHelper.dll|eCrmHeHelper.exe|eCrmHeHelper32.dll|eCrmInterCaller.exe|' + 'BSWmcr.exe|Bs1out.dll|Bs1out64.dll|Bs1shl.dll|Bs1uef.dat|Bs1tri.dat'; HEBIN_FILES = 'eCrmHomeEdition.exe|ielib64.dll|KvCttSch.exe|KvCttSchw.exe|libeay32.dll|' + 'libkm64.dll|ptnsch.dat|ssleay32.dll'; LANG_FILES = 'eCrmHomeEdition.409.dat|eCrmHomeEdition.412.dat|eCrmHomeEdition.411.dat|' + 'eCrmHomeEdition.804.dat|eCrmHomeEdition.404.dat'; SLCORE_FILES = 'slcore.exe'; SLCORE_DATA_FILES = 'SLT@|sltgd.dat'; DATA_FILES = 'pdmsa.prop|admsa.prop|cdmsa.prop|csmsa.pro'; // cfmsa.prop 사용하지 않음 DIR_NAMES = 'bin|conf|Data|Language|Resource'; type TRecoverService = class(TTgDirWatchBase) private DataFiles_, DirNames_, KvBinFiles_, HeBinFiles_, ConfFiles_, LangFiles_, SLCoreDatas_, SLCoreFiles_: TStringList; LockFiles_: TList; bIsWorking_: Boolean; bBlockRename_: Boolean; sBlkFRename_, sIgrBlkFRename_: String; bRecovering_: Boolean; procedure OnLockFileNotify(Sender: TObject; const Item: TFileStream; Action: TCollectionNotification); procedure ProcessDirWatchEnt(Sender: TObject; pInfo: PDirWatchEnt); override; procedure LockFiles; procedure UnlockFiles; procedure RecoverAll; procedure RecoverData; public Constructor Create; Destructor Destroy; override; procedure StartService; procedure StopService; property IsWorking: Boolean read bIsWorking_; end; implementation uses Tocsg.Safe, Tocsg.Strings, Tocsg.Path, superobject, Tocsg.Exception, Winapi.Windows, GlobalDefine, AbUnzper, AbArcTyp, ManagerService, ManagerModel, Condition, Tocsg.Packet; { TRecoverService } Constructor TRecoverService.Create; begin Inherited Create(true, false); bIsWorking_ := false; bRecovering_ := false; sBlkFRename_ := ''; sIgrBlkFRename_ := ''; bBlockRename_ := false; KvBinFiles_ := TStringList.Create; KvBinFiles_.CaseSensitive := false; SplitString(KVBIN_FILES, '|', KvBinFiles_); HeBinFiles_ := TStringList.Create; HeBinFiles_.CaseSensitive := false; SplitString(HEBIN_FILES, '|', HeBinFiles_); ConfFiles_ := TStringList.Create; ConfFiles_.CaseSensitive := false; SplitString(CONF_FILES, '|', ConfFiles_); ConfFiles_.Add(EXE_SPL); LangFiles_ := TStringList.Create; LangFiles_.CaseSensitive := false; SplitString(LANG_FILES, '|', LangFiles_); SLCoreFiles_ := TStringList.Create; SLCoreFiles_.CaseSensitive := false; SplitString(SLCORE_FILES, '|', SLCoreFiles_); SLCoreDatas_ := TStringList.Create; SplitString(SLCORE_DATA_FILES, '|', SLCoreDatas_); DirNames_ := TStringList.Create; DirNames_.CaseSensitive := false; SplitString(DIR_NAMES, '|', DirNames_); DataFiles_ := TStringList.Create; DataFiles_.CaseSensitive := false; SplitString(DATA_FILES, '|', DataFiles_); LockFiles_ := TList.Create; LockFiles_.OnNotify := OnLockFileNotify; LockFiles; RecoverAll; SetFilter(FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME or FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WRITE); end; Destructor TRecoverService.Destroy; begin StopService; Inherited; FreeAndNil(LockFiles_); FreeAndNil(DataFiles_); FreeandNil(DirNames_); FreeAndNil(SLCoreDatas_); FreeAndNil(SLCoreFiles_); FreeAndNil(LangFiles_); FreeAndNil(ConfFiles_); FreeAndNil(HeBinFiles_); FreeAndNil(KvBinFiles_); end; procedure TRecoverService.OnLockFileNotify(Sender: TObject; const Item: TFileStream; Action: TCollectionNotification); begin if Action = cnRemoved then Item.Free; end; procedure TRecoverService.LockFiles; function DoLockFile(sPath: String): TFileStream; begin Result := nil; if not FileExists(sPath) then exit; try Result := TFileStream.Create(sPath, fmOpenRead or fmShareDenyWrite); except on E: Exception do ETgException.TraceException(E, Format('Fail .. DoLockFile() .. Path="%s"', [sPath])); end; end; var sCurDir, sResDir: String; fs: TFileStream; i: Integer; begin sCurDir := GetRunExePathDir; sResDir := sCurDir + 'Resource\'; for i := 1 to 5 do begin fs := DoLockFile(sResDir + Format('rst.%.2d', [i])); if fs <> nil then LockFiles_.Add(fs); end; fs := DoLockFile(sCurDir + 'bin\datafiles\unicodetables\text_kjdump.txt'); if fs <> nil then LockFiles_.Add(fs); end; procedure TRecoverService.UnlockFiles; begin LockFiles_.Clear; end; procedure TRecoverService.RecoverAll; procedure ExtrZip(sResPath, sDestDir: String; bIgrErr: Boolean = false); var zip: TAbUnZipper; begin if not ForceDirectories(sDestDir) then exit; try Guard(zip, TAbUnzipper.Create(nil)); zip.FileName := sResPath; zip.ExtractOptions := [eoCreateDirs, eoRestorePath]; zip.BaseDirectory := sDestDir; // zip.OnArchiveProgress := ; // zip.OnNeedPassword := ; zip.ExtractFiles('*.*'); except on E: Exception do ETgException.TraceException(E, Format('Fail .. ExtrZip(), ExtrDir="%s"', [sDestDir])); end; end; procedure CheckAndRecover(sResPath, sPath: String); var zip: TAbUnZipper; nIdx: Integer; sDir, sFName: String; begin try sFName := ExtractFileName(sPath); Guard(zip, TAbUnzipper.Create(nil)); zip.FileName := sResPath; nIdx := zip.FindFile(sFName); if (nIdx <> -1) and (not FileExists(sPath) or (GetFileSize_path(sPath) <> zip.Items[nIdx].UncompressedSize)) then begin _Trace('파일 변경/삭제 감지됨', 2); _Trace('DoRecover .. Path="%s"', [sPath]); try sDir := ExtractFilePath(sPath); if ForceDirectories(sDir) then begin zip.ExtractOptions := [eoCreateDirs, eoRestorePath]; zip.BaseDirectory := sDir; // zip.OnArchiveProgress := ; // zip.OnNeedPassword := ; // zip.ExtractAt(nIdx, sFName); zip.ExtractFiles(sFName); end; except on E: Exception do ETgException.TraceException(E, Format('Fail .. CheckAndRecover(), Path="%s"', [sPath])); end; end; except on E: Exception do ETgException.TraceException(E, 'Fail .. CheckAndRecover()'); end; end; var sResDir, sCurDir, sResPath, sDestPath: String; bDoRecover: Boolean; i: Integer; begin bRecovering_ := true; try sCurDir := GetRunExePathDir; sResDir := sCurDir + 'Resource\'; if not DirectoryExists(sResDir) then exit; bDoRecover := false; sDestPath := sCurDir + 'bin\'; if DirectoryExists(sDestPath) then begin var dwDirCnt: DWORD := 0; var dwFileCnt: DWORD := 0; var llTotalSize: LONGLONG := 0; GetDirInfo(sDestPath, dwDirCnt, dwFileCnt, llTotalSize, true); if (dwDirCnt <> 2) or (dwFileCnt <> 260) or (llTotalSize <> 47648118) then bDoRecover := true; end else bDoRecover := true; if bDoRecover then begin _Trace('파일 변경/삭제 감지됨', 2); _Trace('DoRecover .. Path="%s"', [sDestPath]); ExtrZip(sResDir + 'rst.02', sDestPath); bDoRecover := false; end; sResPath := sCurDir + 'prfwork.dat'; if FileExists(sResDir + 'rst.01') then begin // hebin CopyFile(PChar(sResDir + 'rst.01'), PChar(sResPath), false); sDestPath := sCurDir; CheckAndRecover(sResDir + 'rst.01', sDestPath + 'ssleay32.dll'); CheckAndRecover(sResDir + 'rst.01', sDestPath + 'ptnsch.dat'); CheckAndRecover(sResDir + 'rst.01', sDestPath + 'libkm64.dll'); CheckAndRecover(sResDir + 'rst.01', sDestPath + 'libeay32.dll'); CheckAndRecover(sResDir + 'rst.01', sDestPath + 'KvCttSchw.exe'); CheckAndRecover(sResDir + 'rst.01', sDestPath + 'KvCttSch.exe'); CheckAndRecover(sResDir + 'rst.01', sDestPath + 'ielib64.dll'); CheckAndRecover(sResDir + 'rst.01', GetSystemDir + 'eCrmHeServiced.dll'); end; if FileExists(sResDir + 'rst.03') then begin // conf CopyFile(PChar(sResDir + 'rst.03'), PChar(sResPath), false); sDestPath := sCurDir + 'conf\'; CheckAndRecover(sResDir + 'rst.03', sDestPath + 'eCrmInterCaller.exe'); CheckAndRecover(sResDir + 'rst.03', sDestPath + 'eCrmHeHelper.dll'); CheckAndRecover(sResDir + 'rst.03', sDestPath + 'eCrmHeHelper32.dll'); CheckAndRecover(sResDir + 'rst.03', sDestPath + 'eCrmHeHelperf.dll'); CheckAndRecover(sResDir + 'rst.03', sDestPath + 'eCrmHeHelper32f.dll'); CheckAndRecover(sResDir + 'rst.03', sDestPath + 'eCrmHeHelper.exe'); CheckAndRecover(sResDir + 'rst.03', sDestPath + 'BSWmcr.exe'); CheckAndRecover(sResDir + 'rst.03', sDestPath + 'Bs1out.dll'); CheckAndRecover(sResDir + 'rst.03', sDestPath + 'Bs1out64.dll'); end; if FileExists(sResDir + 'rst.04') then begin CopyFile(PChar(sResDir + 'rst.04'), PChar(sResPath), false); sDestPath := sCurDir + 'Language\'; CheckAndRecover(sResDir + 'rst.04', sDestPath + 'eCrmHomeEdition.412.dat'); CheckAndRecover(sResDir + 'rst.04', sDestPath + 'eCrmHomeEdition.409.dat'); end; if FileExists(sResDir + 'rst.05') then begin CopyFile(PChar(sResDir + 'rst.05'), PChar(sResPath), false); sDestPath := sCurDir; CheckAndRecover(sResDir + 'rst.05', sDestPath + 'slcore.exe'); end; if FileExists(sResDir + 'rst.06') and not FileExists(sCurDir + DIR_CONF + EXE_SPL) then begin CopyFile(PChar(sResDir + 'rst.06'), PChar(sCurDir + DIR_CONF + EXE_SPL), false); _Trace('파일 변경/삭제 감지됨', 2); _Trace('DoRecover .. Path="%s"', [sCurDir + DIR_CONF + EXE_SPL]); end; finally if FileExists(sResPath) then DeleteFile(PChar(sResPath)); bRecovering_ := false; Processor_.Clear; end; end; procedure TRecoverService.RecoverData; var sConfDir: String; CompModel: TCompanyModel; begin try sConfDir := GetRunExePathDir + 'conf\'; if ForceDirectories(sConfDir) then begin if not FileExists(sConfDir + DAT_COMPANY) then begin Guard(CompModel, TCompanyModel.Create); CompModel.CustomerType := CUSTOMER_TYPE; CompModel.CustomerSubType := CUSTOMER_SUB_TYPE; CompModel.SvrDestList.AddStrings(gMgSvc.ServerUrlList); CompModel.Save(sConfDir + DAT_COMPANY); end; if not FileExists(sConfDir + DAT_AGENT) then begin _Trace('DoRecoverData .. File="%s"', [DAT_AGENT]); gMgSvc.AgentModel.Save; end; if gMgSvc.IsNewApi then begin // todo : 정책 데이터 복구 추가 23_0810 08:40:35 kku if gMgSvc.PrefModel.Loaded then gMgSvc.PrefModel.Save; if gMgSvc.SleepPolicy.Loaded then gMgSvc.SleepPolicy.Save; if gMgSvc.VulPolicy.Loaded then gMgSvc.VulPolicy.Save; if gMgSvc.OffPolicy.Loaded then gMgSvc.OffPolicy.Save; if gMgSvc.ExpPolicy.Loaded then gMgSvc.ExpPolicy.Save; end else if not FileExists(sConfDir + DAT_PREF) then begin _Trace('DoRecoverData .. File="%s"', [DAT_PREF]); gMgSvc.PrefModel.Save; end; if not FileExists(sConfDir + DAT_CTTSCH) then begin _Trace('DoRecoverData .. File="%s"', [DAT_CTTSCH]); gMgSvc.MgCttSch.Save; end; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. RecoverData()'); end; end; procedure TRecoverService.StartService; var dwLogicalDrv: DWORD; i: Integer; sDrive: String; begin if not bIsWorking_ then begin AddDirWatch(GetRunExePathDir); // AddDirWatch(GetProgramFilesDir + DIR_HE); bIsWorking_ := true; Processor_.StartThread; end; end; procedure TRecoverService.StopService; begin if bIsWorking_ then begin bIsWorking_ := false; Processor_.Clear; Processor_.PauseThread; try ClearDirWatch; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. StopService()'); end; end; end; procedure TRecoverService.ProcessDirWatchEnt(Sender: TObject; pInfo: PDirWatchEnt); procedure RecoverFile(sPath: String); var sCurDir, sResName: String; zip: TAbUnZipper; begin try sCurDir := GetRunExePathDir; sPath := StringReplace(sPath, sCurDir, '', [rfReplaceAll, rfIgnoreCase]); sResName := GetRunExePathDir + 'Resource\' + sResName; if not FileExists(sResName) then exit; Guard(zip, TAbUnZipper.Create(nil)); zip.FileName := sResName; zip.ExtractOptions := [eoCreateDirs, eoRestorePath]; // zip.BaseDirectory := sDestDir; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. RecoverFile()'); end; end; var sExt, sDir, sFName, sIgCheck, sDestPath: String; i: Integer; begin try if bRecovering_ then exit; sDir := ExtractFilePath(pInfo.sPath); sFName := ExtractFileName(pInfo.sPath); sExt := GetFileExt(sFName); case pInfo.dwAction of 1 : ; // Add 2 : // Delete begin if (KvBinFiles_.IndexOf(sFName) <> -1) or (HeBinFiles_.IndexOf(sFName) <> -1) or (ConfFiles_.IndexOf(sFName) <> -1) or (LangFiles_.IndexOf(sFName) <> -1) or (SLCoreFiles_.IndexOf(sFName) <> -1) or (DirNames_.IndexOf(sFName) <> -1) then begin RecoverAll; end; if DataFiles_.IndexOf(sFName) <> -1 then RecoverData; // if (gClient <> nil) and gClient.Connected then // begin // for i := 0 to SLCoreDatas_.Count - 1 do // begin // if Pos(SLCoreDatas_[i], sFName) = 1 then // begin // gClient.SendPacket(TTgPacket.Create(SLC_REQUEST_SAVEDATA)); // break; // end; // end; // end; end; 3 : // Modify begin if (KvBinFiles_.IndexOf(sFName) <> -1) or (HeBinFiles_.IndexOf(sFName) <> -1) or (ConfFiles_.IndexOf(sFName) <> -1) or (LangFiles_.IndexOf(sFName) <> -1) or (SLCoreFiles_.IndexOf(sFName) <> -1) or (DirNames_.IndexOf(sFName) <> -1) then begin RecoverAll; end; end; 4 : // Rename begin if sIgrBlkFRename_ = sFName then begin sIgrBlkFRename_ := ''; exit; end; if (KvBinFiles_.IndexOf(sFName) <> -1) or (HeBinFiles_.IndexOf(sFName) <> -1) or (ConfFiles_.IndexOf(sFName) <> -1) or (LangFiles_.IndexOf(sFName) <> -1) or (SLCoreFiles_.IndexOf(sFName) <> -1) or (DirNames_.IndexOf(sFName) <> -1) then begin sBlkFRename_ := sFName; bBlockRename_ := true; end; end; 5 : begin // 이름 변경 복구 체크 if sBlkFRename_ <> '' then begin if bBlockRename_ then begin sIgrBlkFRename_ := sFName; bBlockRename_ := false; if MoveFile_wait(pInfo.sPath, sDir + sBlkFRename_, 5) then begin sFName := sBlkFRename_; pInfo.sPath := sDir + sFName; end; end; sBlkFRename_ := ''; end; end; // else exit; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. ProcessDirWatchEntry()') end; end; end.