{*******************************************************} { } { ManagerFixedDisk } { } { Copyright (C) 2023 kku } { } {*******************************************************} unit ManagerFixedDisk; interface uses Tocsg.Obj, System.SysUtils, Tocsg.Disk, System.Classes, Tocsg.Driver, Winapi.Windows, System.Generics.Collections; type TDetectDiskType = (ddtAdd, ddtRemove); PDetectDisk = ^TDetectDisk; TDetectDisk = record DType: TDetectDiskType; DInfo: TDriveInfo; end; TDetectDiskList = class(TList) protected procedure Notify(const Item: PDetectDisk; Action: TCollectionNotification); override; end; TDriveInfoList = class(TList) protected procedure Notify(const Item: PDriveInfo; Action: TCollectionNotification); override; public function GetDriveInfo(sFriName, sSrial: String; llSize: LONGLONG): PDriveInfo; function GetDriveInfo_Def(sSrial, sClassGuid: String): PDriveInfo; end; TManagerFixedDisk = class(TTgObject) private DrvList_: TDriveInfoList; public Constructor Create; Destructor Destroy; override; function DetectChangeDisk: TDetectDiskList; procedure Save; procedure Load; end; implementation uses Tocsg.Exception, Tocsg.Safe, superobject, Tocsg.Json, Tocsg.Path, GlobalDefine; { TDetectDiskList } procedure TDetectDiskList.Notify(const Item: PDetectDisk; Action: TCollectionNotification); begin if Action = cnRemoved then Dispose(Item); end; { TDriveInfoList } procedure TDriveInfoList.Notify(const Item: PDriveInfo; Action: TCollectionNotification); begin if Action = cnRemoved then Dispose(Item); end; // OS 업데이트등의 이유로 sFriName, llSize가 빈값으로 잡히는 경우가 있다... 25_0319 14:12:28 kku // 이전 디스크 목록을 비교하기 위해서는 적합하지 않음 // 이걸로 다시 사용 25_0826 14:58:41 kku function TDriveInfoList.GetDriveInfo(sFriName, sSrial: String; llSize: LONGLONG): PDriveInfo; var i: Integer; begin Result := nil; for i := 0 to Count - 1 do begin if (CompareText(Items[i].sFriendlyName, sFriName) = 0) and (CompareText(Items[i].sSerial, sSrial) = 0) and (Items[i].llSize = llSize) then begin Result := Items[i]; exit; end; end; end; // 같은 제조사에서 나온 디스크는 sSrial, sClassGuid 값이 같다... // 이걸로 사용할 수 없음. 25_0826 14:57:58 kku function TDriveInfoList.GetDriveInfo_Def(sSrial, sClassGuid: String): PDriveInfo; var i: Integer; begin Result := nil; for i := 0 to Count - 1 do begin if (CompareText(Items[i].sSerial, sSrial) = 0) and (CompareText(Items[i].sClassGuid, sClassGuid) = 0) then begin Result := Items[i]; exit; end; end; end; { TManagerFixedDisk } Constructor TManagerFixedDisk.Create; begin Inherited Create; DrvList_ := TDriveInfoList.Create; Load; end; Destructor TManagerFixedDisk.Destroy; begin if DrvList_ <> nil then FreeAndNil(DrvList_); Inherited; end; function TManagerFixedDisk.DetectChangeDisk: TDetectDiskList; var DrvLtList: TDevPathLetterList; ChkList: TDriveInfoList; pEnt, pChkEnt: PDriveInfo; pDtEnt: PDetectDisk; i: Integer; bFirst, bUpdate: Boolean; sDrive: String; begin try bUpdate := false; bFirst := DrvList_.Count = 0; Result := TDetectDiskList.Create; Guard(DrvLtList, TDevPathLetterList.Create); if GetDrivesDevPathLetterList(DrvLtList) = 0 then begin // _Trace('Fail .. DetectChangeDisk() .. 1', 9); exit; end; ChkList := TDriveInfoList.Create; for i := 0 to DrvLtList.Count - 1 do begin New(pEnt); sDrive := DrvLtList[i].cLetter + ':\'; GetDriveDetail(sDrive, pEnt, true); if not bFirst and (pEnt.sFriendlyName = '') then begin // 업데이트, 윈도우 시작 직후 등 장치 정보를 제대로 가져오지 못하는 경우가 있다. // 장치 이름이 없고 기존 정보에 시리얼등이 있을 경우 걸러준다 25_0826 15:09:10 kku pChkEnt := DrvList_.GetDriveInfo_Def(pEnt.sSerial, pEnt.sClassGuid); if (pChkEnt <> nil) and (pChkEnt.sFriendlyName <> '') then begin _Trace('Fail .. DetectChangeDisk() .. Empty FriName ... Serial=%s', [pEnt.sSerial], 1); Dispose(pEnt); FreeAndNil(ChkList); exit; end; end; if Pos('USB', UpperCase(pEnt.sSerial)) = 1 then // 이동식 제외 begin Dispose(pEnt); continue; end; ChkList.Add(pEnt); end; // 추가된 디스크 확인 for i := 0 to ChkList.Count - 1 do begin if not bFirst and (DrvList_.GetDriveInfo(ChkList[i].sFriendlyName, ChkList[i].sSerial, ChkList[i].llSize) = nil) then begin New(pDtEnt); pDtEnt.DType := ddtAdd; pDtEnt.DInfo := ChkList[i]^; Result.Add(pDtEnt); bUpdate := true; _Trace('고정 디스크 추가 : Drive=%s, Name=%s', [pDtEnt.DInfo.sDrive, pDtEnt.DInfo.sFriendlyName], 3); end; end; // 제거된 디스크 확인 for i := 0 to DrvList_.Count - 1 do begin if not bFirst and (ChkList.GetDriveInfo(DrvList_[i].sFriendlyName, DrvList_[i].sSerial, DrvList_[i].llSize) = nil) then begin New(pDtEnt); pDtEnt.DType := ddtRemove; pDtEnt.DInfo := DrvList_[i]^; Result.Add(pDtEnt); bUpdate := true; _Trace('고정 디스크 제거 : Drive=%s, Name=%s', [pDtEnt.DInfo.sDrive, pDtEnt.DInfo.sFriendlyName], 3); end; end; if bUpdate then begin if DrvList_ <> nil then FreeAndNil(DrvList_); DrvList_ := ChkList; Save; _Trace('고정 디스크 정보 저장', 3); end else FreeAndNil(ChkList); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. DetectChangeDisk()'); end; end; procedure TManagerFixedDisk.Save; var O, OA: ISuperObject; i: Integer; begin try OA := TSuperObject.Create(stArray); for i := 0 to DrvList_.Count - 1 do OA.AsArray.Add(TTgJson.ValueToJsonObject(DrvList_[i]^)); O := SO; O.O['List'] := OA; SaveJsonObjToEncFile(O, GetRunExePathDir + DIR_CONF + DAT_FIXDISK, PASS_STRENC); // SaveJsonObjToFile(O, 'C:\diskInfo.json') except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. Save()'); end; end; procedure TManagerFixedDisk.Load; var sPath: String; O: ISuperObject; i: Integer; pEnt: PDriveInfo; begin try DrvList_.Clear; sPath := GetRunExePathDir + DIR_CONF + DAT_FIXDISK; if not FileExists(sPath) then exit; if not LoadJsonObjFromEncFile(O, sPath, PASS_STRENC) then exit; if (O.O['List'] = nil) or (O.O['List'].DataType <> stArray) then exit; for i := 0 to O.A['List'].Length - 1 do begin New(pEnt); pEnt^ := TTgJson.GetDataAsType(O.A['List'].O[i]); DrvList_.Add(pEnt); end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. Load()'); end; end; end.