BSOne.SFC/eCrmHE/EXE_eCrmHomeEdition/Manager/ManagerFixedDisk.pas

278 lines
7.2 KiB
Plaintext

{*******************************************************}
{ }
{ 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<PDetectDisk>)
protected
procedure Notify(const Item: PDetectDisk; Action: TCollectionNotification); override;
end;
TDriveInfoList = class(TList<PDriveInfo>)
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<TDriveInfo>(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<TDriveInfo>(O.A['List'].O[i]);
DrvList_.Add(pEnt);
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. Load()');
end;
end;
end.