{*******************************************************} { } { RecoverService } { } { Copyright (C) 2022 kku } { } {*******************************************************} // 문서 열람하면 감지하는 용도로 사용하려고 했는데, // 최근 열었던 문서를 닫고 바로 열때는 감지하지 못하는 문제가 있다. // 그래서 사용안함. // 그래도 나중에 비슷한 기능 구현을 위해 뼈대 남겨놓음 25_1106 10:32:24 kku unit ProcessRecentDoc; interface uses System.SysUtils, System.Classes, Winapi.Windows, Vcl.Graphics, Tocsg.Thread, ManagerPattern, Tocsg.Files, System.Generics.Collections; const DEF_DOC_EXTS = 'TXT|LOG|DOC|WPS|PDF|XLS|PPT|HWP|DOCX|DOTX|XLSX|XLTX|PPTX|POTX'; type TRecentDocWatch = class(TTgDirWatchBase) private bIsWorking_: Boolean; sDocExts_, sLastOpenFile_: String; ullLastTick_: ULONGLONG; DocExtList_: TStringList; procedure UpdateTargetExts(sExts: String); procedure ProcessDirWatchEnt(Sender: TObject; pInfo: PDirWatchEnt); override; 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, GlobalDefine, AbUnzper, AbArcTyp, ManagerService, ManagerModel, Condition, Tocsg.Packet, Tocsg.Shell, Tocsg.Process, Tocsg.Driver; { TRecentDocWatch } Constructor TRecentDocWatch.Create; begin Inherited Create(true, false); ullLastTick_ := 0; sLastOpenFile_ := ''; DocExtList_ := TStringList.Create; DocExtList_.CaseSensitive := false; // sDocExts_ := DEF_DOC_EXTS; // SplitString(sDocExts_, '|', DocExtList_, false, true); bIsWorking_ := false; 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 TRecentDocWatch.Destroy; begin StopService; Inherited; FreeAndNil(DocExtList_); end; procedure TRecentDocWatch.UpdateTargetExts(sExts: String); begin if (sExts <> '') and (sExts <> sDocExts_) then begin sDocExts_ := sExts; SplitString(sDocExts_, '|', DocExtList_, false, true); end; end; procedure TRecentDocWatch.StartService; var sDir, sUserDir: String; DList: TStringList; i: Integer; begin if not bIsWorking_ then begin sDir := GetWindowsDir; if sDir = '' then begin _Trace('Fail .. Not found windowsDir', 1); exit; end; sUserDir := UpperCase(sDir[1]) + ':\Users\'; Guard(DList, TStringList.Create); ExtrDirFromDir(sUserDir, DList); for i := 0 to DList.Count - 1 do begin AddDirWatch(sUserDir + DList[i] + '\AppData\Roaming\Microsoft\Windows\Recent\', true); end; bIsWorking_ := true; Processor_.StartThread; end; end; procedure TRecentDocWatch.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 TRecentDocWatch.ProcessDirWatchEnt(Sender: TObject; pInfo: PDirWatchEnt); var sExt, sDocPath, sFName, sPName: String; i: Integer; PO: TPrefModel; MonKind: TFileMonKind; LogInfo: TLogInfo; DriveInfo: TDriveInfo; begin try case pInfo.dwAction of 1, 3 : // Add, Modify begin sDocPath := ''; sExt := GetFileExt(pInfo.sPath).ToUpper; if sExt = 'AUTOMATICDESTINATIONS-MS' then sDocPath := GetLastOpenFileFromJumpListAuto(pInfo.sPath); if sDocPath = '' then begin if sExt <> 'LNK' then exit; sDocPath := GetTargetExeFromLink(pInfo.sPath); if sDocPath = '' then exit; end; // 간혹 사용자 폴더가 이상하게(?) 표시되는 경우가 있다.. 보정 24_0514 10:09:24 kku if (sDocPath <> '') and (Pos('windows\system32\config\systemprofile', sDocPath.ToLower) > 0) then begin _Trace('Replace path = "%s"', [sDocPath], 3); sFName := ExtractFileName(sDocPath); sDocPath := StringReplace(sDocPath, 'windows\system32\config\systemprofile', Format('Users\%s', [sFName]), [rfReplaceAll, rfIgnoreCase]); _Trace('Replace Path done = "%s"', [sDocPath], 3); end; // _Trace('Found RecentFile = "%s"', [sDocPath], 3); if not FileExists(sDocPath) then exit; if sDocPath <> sLastOpenFile_ then begin sLastOpenFile_ := sDocPath; ullLastTick_ := GetTickCount64; end else if (GetTickCount64 - ullLastTick_) < 1200 then // 1.2초간 중복 감지 걸름 25_1216 14:53:17 kku exit; sExt := GetFileExt(sDocPath); sPName := GetProcessNameFromWndHandle(GetForegroundWindow); if sExt.ToUpper.Contains('DOC') and (CompareText('winword.exe', sPName) <> 0) then begin // 워드는 종료할때도 점프리스트가 업데이트 된다... 25_1216 15:02:57 kku // sLastOpenFile_ := ''; // ullLastTick_ := 0; exit; end; _Trace('파일 열람 감지 .. PName=%s, Path=%s', [sPName, sDocPath], 5); PO := gMgSvc.ModePolicy; MonKind := PO.FileMon.Kind; if sDocExts_ <> PO.FileMon.sExts then UpdateTargetExts(PO.FileMon.sExts); case MonKind of fmkNone : exit; fmkAll : ; fmkIncExt : begin if DocExtList_.IndexOf(sExt) = -1 then exit; end; fmkIgrExt : begin if DocExtList_.IndexOf(sExt) <> -1 then exit; end; end; if PO.FileMon.OnlyUSB then begin GetDriveDetail(ExtractFileDrive(sDocPath), @DriveInfo); if Pos('USB', UpperCase(DriveInfo.sSerial)) <> 1 then exit; end; ZeroMemory(@LogInfo, SizeOf(LogInfo)); LogInfo.sCode := LOGCODE_PREVENT_FILEMONITOR; if PO.FileMon.OnlyUSB then begin LogInfo.sDevName := DriveInfo.sFriendlyName; LogInfo.sDevSerial := DriveInfo.sSerial; LogInfo.sDevClassId := DriveInfo.sClassGuid; end; LogInfo.sSummary := Format('[Open] %s', [sDocPath]); LogInfo.sAppName := sPName; LogInfo.sPath := sDocPath; if gMgSvc.IsNewApi then gMgSvc.SendEventLogEx(@LogInfo, false); if gMgSvc.ModePolicy.FileMon.IsNoti then gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILECHANGE, LogInfo.sSummary); end; 2 : ; // Delete // 3 : ; // Modify 4 : ; // Rename 5 : ; // New name end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. ProcessDirWatchEntry()') end; end; end.