{*******************************************************} { } { ThdSchFileScan } { } { Copyright (C) 2022 Sunk } { } {*******************************************************} unit ThdSchFileScan; interface uses Define, System.SysUtils, System.Classes, Winapi.Windows, System.SyncObjs, System.Generics.Collections, Winapi.Messages, Tocsg.Thread, Tocsg.Files, Tocsg.Win32, CttSchDefine; const SIGN_SOFTCAMP_DRM: array [0..15] of Byte = ($53, $43, $44, $53, $41, $30, $30, $34, $00, $00, $52, $00, $20, $88, $F1, $53); // SCDSA004 ½ÃÀÛµÊ SIG_DRM: AnsiString = 'ToCSG'; type TThdSchFileScan = class(TTgThread) protected sProcDir_, sProcSchFile_: String; FileScanOpt_: TFileScanOpt; llTotalTgFile_, llProcTgFile_, llFound_, llFoundFile_, llTotalDir_, llTotalFile_: LONGLONG; TgDirList_, ScanExtList_, SvFileList_, SvDirList_, SvScanList_, TestCompList_: TStringList; sWorkDir_: String; dtBegin_: TDateTime; evScanSearchEnd_, evScanSearchBegin_: TNotifyEvent; sMtx_: String; TaskMutex_: TTgMutex; CttSchOpt_: TCttSchOpt; hKvCttSch_: HWND; ProcInfo_: TProcessInformation; dtRecentSch_: TDateTime; qSchEnt_: TQueue; bSendEvent_: Boolean; {$IFDEF _HE_} CttSchProg_: TCttSchProg; dwProgTick_: DWORD; sSchTitle_: String; {$ENDIF} dtScan_: TDateTime; procedure ScanSchFiles; procedure Execute; override; public Constructor Create(sTgDirs: String; aOpt: TFileScanOpt; dtScan: TDateTime; bSendEvent: Boolean = true); Destructor Destroy; override; procedure UpdateProgress(sStatus: String; bForce: Boolean = false; sResult: String = 'none'); procedure SetKvCttSchHandle(h: HWND); function NextSchPath: String; procedure IncFoundCount(nHits: Integer); procedure IncFoundFileCount; procedure IncEncFileCount; property WorkState: TTgThreadState read GetWorkState; property TotalDirCount: LONGLONG read llTotalDir_; property TotalFileCount: LONGLONG read llTotalFile_; property TotalTgFileCount: LONGLONG read llTotalTgFile_; property ProcTgFileCount: LONGLONG read llProcTgFile_; property FoundCount: LONGLONG read llFound_; property FoundFileCount: LONGLONG read llFoundFile_; property ProcDir: String read sProcDir_; property ProcSchFile: String read sProcSchFile_; property BeginDT: TDateTime read dtBegin_; property OnScanSearchBegin: TNotifyEvent write evScanSearchBegin_; property OnScanSearchEnd: TNotifyEvent write evScanSearchEnd_; property KvCttSchWnd: HWND read hKvCttSch_; property IsSendEvent: Boolean read bSendEvent_; property ScanDate: TDateTime read dtScan_; {$IFDEF _HE_} property CttSchProg: TCttSchProg read CttSchProg_; property SchTitle: String read sSchTitle_; {$ENDIF} end; implementation uses {$IFDEF _HE_} ManagerService, GlobalDefine, Condition, {$ENDIF} Tocsg.PCRE, Tocsg.Trace, Tocsg.Exception, Tocsg.Strings, Tocsg.Safe, Tocsg.Path, Tocsg.Process, System.DateUtils, superobject, Tocsg.Json, Tocsg.WinInfo, Tocsg.DateTime; { TThdSchFileScan } Constructor TThdSchFileScan.Create(sTgDirs: String; aOpt: TFileScanOpt; dtScan: TDateTime; bSendEvent: Boolean = true); var i: Integer; ThdDirWatchEnt: TThdDirWatchEnt; begin Inherited Create; bSendEvent_ := bSendEvent; hKvCttSch_ := 0; WorkState_ := tsInit; {$IFDEF _HE_} ZeroMemory(@CttSchProg_, SizeOf(CttSchProg_)); dwProgTick_ := 0; if aOpt.bShowSchTitle then sSchTitle_ := aOpt.sSchTitle else sSchTitle_ := ''; {$ENDIF} if dtScan <> 0 then dtScan_ := dtScan else dtScan_ := Now; TgDirList_ := TStringList.Create; SplitString(sTgDirs, '|', TgDirList_); FileScanOpt_ := aOpt; case FileScanOpt_.CttSchOpt.nWorkPriority of 0 : Priority := tpHighest; 1 : Priority := tpHigher; // 2 : Priority := tpNormal; 3 : Priority := tpLower; 4 : Priority := tpLowest; else Priority := tpNormal; end; llFound_ := 0; llFoundFile_ := 0; llTotalTgFile_ := 0; llProcTgFile_ := 0; llTotalDir_ := 0; llTotalFile_ := 0; sProcSchFile_ := ''; ScanExtList_ := TStringList.Create; ScanExtList_.CaseSensitive := false; SplitString(FileScanOpt_.sScanExt, '|', ScanExtList_); @evScanSearchEnd_ := nil; @evScanSearchBegin_ := nil; SvFileList_ := nil; SvDirList_ := nil; SvScanList_ := nil; if FileScanOpt_.bSaveFileList then SvFileList_ := TStringList.Create; if FileScanOpt_.bSaveDirList then SvDirList_ := TStringList.Create; if FileScanOpt_.bSaveScanList then SvScanList_ := TStringList.Create; TestCompList_ := TStringList.Create; sMtx_ := 'Global\TaskKvCttSch@' + FormatDateTime('yyyymmddhhnnss', Now); TaskMutex_ := TTgMutex.Create(sMtx_); CttSchOpt_ := FileScanOpt_.CttSchOpt; hKvCttSch_ := 0; dtRecentSch_ := 0; qSchEnt_ := TQueue.Create; ZeroMemory(@ProcInfo_, SizeOf(ProcInfo_)); dtBegin_ := Now; StartThread; end; Destructor TThdSchFileScan.Destroy; begin if ProcInfo_.dwProcessId <> 0 then begin TerminateProcessByPid(ProcInfo_.dwProcessId); ProcInfo_.dwProcessId := 0; end; FreeAndNIl(qSchEnt_); FreeAndNil(ScanExtList_); if SvFileList_ <> nil then FreeAndNil(SvFileList_); if SvDirList_ <> nil then FreeAndNil(SvDirList_); if SvScanList_ <> nil then FreeAndNil(SvScanList_); FreeAndNil(TestCompList_); FreeAndNil(TgDirList_); FreeAndNil(TaskMutex_); Inherited; end; procedure TThdSchFileScan.ScanSchFiles; var sTgDir: String; IgrWordPaths: TStringList; i: Integer; llLimitSize: LONGLONG; procedure ExtractFiles(sDir: String); var wfd: TWin32FindData; hSc: THandle; sExt, sPath: String; dtModify: TDateTime; llSize: LONGLONG; begin try if not DirectoryExists(sDir) then exit; sDir := IncludeTrailingPathDelimiter(sDir); if IgrWordPaths.Count > 0 then begin var i: Integer; sPath := UpperCase(sDir); for i := 0 to IgrWordPaths.Count - 1 do begin if Pos(IgrWordPaths[i], sPath) > 0 then exit; end; end; if SvDirList_ <> nil then SvDirList_.Add(sDir); sPath := sDir + '*.*'; hSc := FindFirstFile(PChar(sPath), wfd); if hSc = INVALID_HANDLE_VALUE then exit; try Repeat if GetWorkStop or Terminated then begin SetWorkState(tsStop); exit; end; if (String(wfd.cFileName) <> '.') and (String(wfd.cFileName) <> '..') then begin sPath := sDir + wfd.cFileName; if ((wfd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0) then begin Inc(llTotalDir_); ExtractFiles(sPath); end else begin Inc(llTotalFile_); if SvFileList_ <> nil then SvFileList_.Add(sPath); sExt := GetFileExt(sPath).ToLower; if (sExt <> '$KV') and (ScanExtList_.IndexOf(sExt) <> -1) then begin // if FileScanOpt_.bPartScan and (FileScanOpt_.dtRecent <> 0) then // begin // dtModify := ConvFileTimeToDateTime_Local(wfd.ftLastWriteTime); // if CompareDateTime(FileScanOpt_.dtRecent, dtModify) <> -1 then // continue; // end; llSize := GetFileSizeHiLow(wfd.nFileSizeHigh, wfd.nFileSizeLow); if llSize = 0 then continue; if (llLimitSize > 0) and (llSize >= llLimitSize) then continue; if CheckSign(sPath, @SIGN_SOFTCAMP_DRM[0], 16) then begin // Inc(CttSchProg_.llEncFileCnt); continue; end; if not CheckSign(sPath, @SIG_DRM, Length(SIG_DRM)) then continue; qSchEnt_.Enqueue(sPath); Inc(llTotalTgFile_); if SvScanList_ <> nil then SvScanList_.Add(sPath); end; end; end; Until not FindNextFile(hSc, wfd); finally WinApi.Windows.FindClose(hSc); end; except // .. end; end; begin llLimitSize := LONGLONG(FileScanOpt_.nLimitSizeMB) * 1048576; Guard(IgrWordPaths, TStringList.Create); SplitString(UpperCase(FileScanOpt_.sIgrWordPath), '|', IgrWordPaths); try SetWorkState(tsWorking); for i := 0 to TgDirList_.Count - 1 do begin if GetWorkStop or Terminated then begin SetWorkState(tsStop); exit; end; sProcDir_ := '?:\'; sTgDir := TgDirList_[i]; if not DirectoryExists(sTgDir) then continue; sProcDir_ := sTgDir; // ´ë»ó ÆÄÀÏ ½ºÄµ ExtractFiles(sTgDir); end; except SetWorkState(tsFail); end; end; procedure TThdSchFileScan.SetKvCttSchHandle(h: HWND); begin hKvCttSch_ := h; end; function TThdSchFileScan.NextSchPath: String; begin Lock; try if qSchEnt_.Count > 0 then begin Result := qSchEnt_.Dequeue; sProcSchFile_ := Result; dtRecentSch_ := Now; Inc(llProcTgFile_); end else Result := ''; finally Unlock; end; {$IFDEF _HE_} if gMgSvc.IsNewApi then UpdateProgress('PROGRESS') else {$ENDIF} UpdateProgress('progress'); if Result = '' then begin SetWorkState(tsCompleted); SetWorkStop(true); end end; procedure TThdSchFileScan.IncFoundCount(nHits: Integer); begin Inc(llFound_, nHits); end; procedure TThdSchFileScan.IncFoundFileCount; begin Inc(llFoundFile_); end; procedure TThdSchFileScan.IncEncFileCount; begin {$IFDEF _HE_} Inc(CttSchProg_.llEncFileCnt); {$ENDIF} end; procedure TThdSchFileScan.UpdateProgress(sStatus: String; bForce: Boolean = false; sResult: String = 'none'); begin {$IFDEF _HE_} if CttSchProg_.sScanId <> '' then begin var dwTick: DWORD := GetTickCount; if bForce or ((dwTick - dwProgTick_) > 10000) then begin dwProgTick_ := dwTick; CttSchProg_.llProc := llProcTgFile_; CttSchProg_.llTotal := llTotalTgFile_; CttSchProg_.sResult := sResult; CttSchProg_.sStatus := sStatus; if bSendEvent_ then begin if gMgSvc.IsNewApi then gMgSvc.SendCampnProgInfo(CttSchProg_) else gMgSvc.SendCttSchProgInfo(CttSchProg_); end; end; end; {$ENDIF} end; procedure TThdSchFileScan.Execute; var sComName: String; // sKvCsPath: String; // procedure CreateProcessKV; // var // hProcess: THandle; // O: ISuperObject; // sParam: String; // begin // {$IFDEF _HE_} // if MutexExists(MUTEX_KILL) then // begin // SetWorkStop(true); // exit; // end; // {$ENDIF} // // if not FileExists(sKvCsPath) then // exit; // // try // if ProcInfo_.dwProcessId <> 0 then // TerminateProcessByPid(ProcInfo_.dwProcessId); // ZeroMemory(@ProcInfo_, SizeOf(ProcInfo_)); // hKvCttSch_ := 0; // dtRecentSch_ := 0; // // O := SO; // O.I['CSTT'] := Integer(csttSchMulti); // O.S['Mtx'] := sMtx_; // O.I['Tasker'] := ULONGLONG(Self); // if FileScanOpt_.nLangId <> 0 then // O.I['LangID'] := FileScanOpt_.nLangId; // if FileScanOpt_.sSchPtrns <> '' then // O.S['SchPtrns'] := FileScanOpt_.sSchPtrns; // O.O['Opt'] := TTgJson.ValueToJsonObject(CttSchOpt_); // sParam := GetRunExePathDir + '$KvCttSchOpt.dat'; // if SaveJsonObjToFile(O, sParam) then // begin // ProcInfo_ := ExecuteApp(sKvCsPath, Format('-p "%s"', [sParam]), SW_SHOWNORMAL); // if ProcInfo_.dwProcessId = 0 then // begin // {$IFDEF DEBUG} // ASSERT(false); // {$ELSE} // _Trace('Fail .. CreateProcessKV() .. ExecuteApp()'); // {$ENDIF} // end; // end else // _Trace('Fail .. CreateProcessKV() .. SaveJsonObjToFile()'); // except // on E: Exception do // ETgException.TraceException(Self, E, 'Fail .. CreateProcessKV()'); // end; // end; var nTmSec, nTaskLenMax: Integer; begin if CttSchOpt_.sTaskDir = '' then begin sWorkDir_ := GetRunExePathDir + 'STask\'; CttSchOpt_.sTaskDir := sWorkDir_; end else sWorkDir_ := CttSchOpt_.sTaskDir; DeleteDir(sWorkDir_); if not ForceDirectories(sWorkDir_) then begin _Trace('Fail .. CreateWorkDir()'); SetWorkState(tsFail); exit; end; nTmSec := FileScanOpt_.nSchTimeoutSec; if nTmSec <= 0 then nTmSec := DEF_TIMEOUT_SEC; {$IFDEF _HE_} if gMgSvc.IsNewApi then nTaskLenMax := 32 else nTaskLenMax := 24; CttSchProg_.dtStart := dtBegin_; CttSchProg_.sScanId := FileScanOpt_.sScanId; sComName := GetComName; CttSchProg_.sTaskId := sComName + '\' + FormatDateTime('hhnnss', dtBegin_); if Length(CttSchProg_.sTaskId) > nTaskLenMax then begin SetLength(sComName, Length(sComName) - (Length(CttSchProg_.sTaskId) - nTaskLenMax)); CttSchProg_.sTaskId := sComName + '\' + FormatDateTime('hhnnss', dtBegin_); end; {$ENDIF} if Assigned(evScanSearchBegin_) then evScanSearchBegin_(Self); ScanSchFiles; if SvFileList_ <> nil then SvFileList_.SaveToFile(FileScanOpt_.sSvFilePath, TEncoding.UTF8); if SvDirList_ <> nil then SvDirList_.SaveToFile(FileScanOpt_.sSvDirPath, TEncoding.UTF8); if SvScanList_ <> nil then SvScanList_.SaveToFile(FileScanOpt_.sSvScanPath, TEncoding.UTF8); // sKvCsPath := GetRunExePathDir + EXE_KVCTTSCH; // while not Terminated and not GetWorkStop do // begin // try // if (ProcInfo_.dwProcessId = 0) or // (GetProcessNameByPid(ProcInfo_.dwProcessId) = '') or // ( (dtRecentSch_ > 0) and // (SecondsBetween(dtRecentSch_, Now) > nTmSec) ) then // CreateProcessKV; // // Sleep(1000); // except // on E: Exception do // ETgException.TraceException(Self, E, 'Fail .. Execute()'); // end; // end; // if ProcInfo_.dwProcessId <> 0 then // begin // TerminateProcessByPid(ProcInfo_.dwProcessId); // ProcInfo_.dwProcessId := 0; // end; // DeleteDir(sWorkDir_); if Assigned(evScanSearchEnd_) then evScanSearchEnd_(Self); end; end.