BSOne.SFC/Tocsg.Module/JumpListAnal/ProcessJumpList.pas

406 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{*******************************************************}
{ }
{ ProcessJumpList }
{ }
{ Copyright (C) 2025 kku }
{ }
{*******************************************************}
unit ProcessJumpList;
interface
uses
Tocsg.Obj, System.Classes, System.SysUtils, Winapi.Windows,
System.Generics.Collections;
type
PJmpEnt = ^TJmpEnt;
TJmpEnt = record
sName: String;
dwType: DWORD;
llSize: LONGLONG;
Stream: TStream;
end;
TJmpEntList = class(TList<PJmpEnt>)
protected
procedure Notify(const Item: PJmpEnt; Action: TCollectionNotification); override;
end;
TJmpDestInfo = packed record
dwVersion: DWORD;
arrUnknown: array [0..27] of Byte;
end;
TJmpDestH = packed record
sCheckSum: array [0..7] of AnsiChar; // 가리키고 있는 Stream의 Check Sum 값이 저장되어 있다.
VolDroidId, // Volume Droid ID
FileDroidId, // File Droid ID
BrhVolDroidId, // Birth volume Droid ID
BrhFileDroidId: TGUID; // Birth file Droid ID
sHostName: array [0..15] of AnsiChar; // 해당 Stream이 생성 된 컴퓨터 이름이 저장 된다.
end;
PJmpDestM78 = ^TJmpDestM78; // Windows 7, 8 용 중간 데이터
TJmpDestM78 = packed record
llSeq: LONGLONG; // 가리키고 있는 Stream의 이름이 저장 된다.
fCount: Single; // Stream의 접근 횟수를 부동소수점으로 표현한 값을 저장하고 있다.
ftLastAccess: TFileTime; // Stream의 마지막 수정 시간을 저장하고 있다.
end;
PJmpDestM10 = ^TJmpDestM10; // Windows 10 용 중간 데이터
TJmpDestM10 = packed record
dwSeq: DWORD;
llUnDefined: LONGLONG; // In all test 0x00 0x00 0x00 0x00
ftLastAccess: TFileTime; // Stream의 마지막 수정 시간을 저장하고 있다.
end;
TJmpDestT78 = packed record // Windows 7, 8 용 끝 데이터
dwPin: DWORD;
wUniStrLen: WORD;
end;
TJmpDestT10 = packed record // Windows 10 용 끝 데이터
dwPin: DWORD;
dwUnDefined1: DWORD; // In all tests, 0xFF 0xFF 0xFF 0xFF
dwCount: DWORD;
llUnDefined2: LONGLONG; // In all test 0x00 0x00 0x00 0x00
wUniStrLen: WORD;
end;
// 윈도우 7지원을 위해 밑에 정보를 나눔
TJmpDestHeader = packed record
sHostName: String;
llSeq: LONGLONG; // 가리키고 있는 Stream의 이름이 저장 된다.
fCount: Single; // Stream의 접근 횟수를 부동소수점으로 표현한 값을 저장하고 있다.
ftLastAccess: TFileTime; // Stream의 마지막 수정 시간을 저장하고 있다.
end;
PJmpDestEnt = ^TJmpDestEnt;
TJmpDestEnt = record
Header: TJmpDestHeader;
sData: String;
end;
TJmpDestEntList = class(TList<PJmpDestEnt>)
protected
procedure Notify(const Item: PJmpDestEnt; Action: TCollectionNotification); override;
end;
// 사용하지 않음. 만들다 말음 25_1216 14:21:17 kku
// GetLastOpenFileFromJumpListAuto() 이거만 사용
TJumpListAuto = class(TTgObject)
private
JmpEntList_: TJmpEntList;
JmpDestEntList_: TJmpDestEntList;
public
Constructor Create;
Destructor Destroy; override;
procedure LoadFromFile(sPath: String);
property JmpEntList: TJmpEntList read JmpEntList_;
property JmpDestEntList: TJmpDestEntList read JmpDestEntList_;
end;
// 점프리스트 파일에서 마지막 열어본 파일 경로 가져오기 25_1216 14:21:47 kku
// Tocsg.Files.pas에 추가함
function GetLastOpenFileFromJumpListAuto(const sJmpAutoPath: String): String;
implementation
uses
EM.GSStorage, Tocsg.Path, Tocsg.Safe, Tocsg.Exception;
const
LinkSig: array [0..11] of Byte = ($4C, $00, $00, $00, $01, $14,
$02, $00, $00, $00, $00, $00);
EndFileSig: array [0..3] of Byte = ($AB, $FB, $BF, $BA);
{ TJmpEntList }
procedure TJmpEntList.Notify(const Item: PJmpEnt; Action: TCollectionNotification);
begin
case Action of
cnAdded: ;
cnRemoved:
begin
if Item.Stream <> nil then
Item.Stream.Free;
Dispose(Item);
end;
cnExtracted: ;
end;
end;
{ TJmpDestEntList }
procedure TJmpDestEntList.Notify(const Item: PJmpDestEnt; Action: TCollectionNotification);
begin
case Action of
cnAdded: ;
cnRemoved: Dispose(Item);
cnExtracted: ;
end;
end;
{ TJumpListAuto }
Constructor TJumpListAuto.Create;
begin
Inherited Create;
JmpEntList_ := TJmpEntList.Create;
JmpDestEntList_ := TJmpDestEntList.Create;
end;
Destructor TJumpListAuto.Destroy;
begin
FreeAndNil(JmpDestEntList_);
FreeAndNil(JmpEntList_);
Inherited;
end;
function CreateJmpEnt(sName: String; dwType: DWORD): PJmpEnt;
begin
New(Result);
ZeroMemory(Result, SizeOf(TJmpEnt));
Result.Stream := TMemoryStream.Create;
Result.sName := sName;
Result.dwType := dwType;
end;
// 점프리스트에서 최근 열어본 파일 알아오기 위해 만듬
// 점프리스트에서 마지막으로 열어본 파일 가져오는데까지만 만들다 말음... 25_1216 14:20:38 kku
// GetLastOpenFileFromJumpListAuto()
procedure TJumpListAuto.LoadFromFile(sPath: String);
var
sExt: String;
dtCreate, dtModify, dtAccess: TDateTime;
llSize: LONGLONG;
stg: TGSStorage;
stgRoot: TGSStorageCursor;
enum: TGSStorageEnum;
i: Integer;
pEnt: PJmpEnt;
// LF: TParserLinkFile;
DestInfo: TJmpDestInfo;
DestH: TJmpDestH;
DestM: array [0..19] of Byte;
DestT78: TJmpDestT78;
DestT10: TJmpDestT10;
pDestE: PJmpDestEnt;
sTemp: array of Char;
wUniStrLen: WORD;
begin
try
JmpEntList_.Clear;
JmpDestEntList_.Clear;
if FileExists(sPath) then
begin
sExt := GetFileExt(sPath).ToUpper;
if sExt <> 'AUTOMATICDESTINATIONS-MS' then
exit;
Guard(stg, TGSStorage.Create);
if stg.OpenFile(sPath, false, stgRoot) <> S_OK then
exit;
if stgRoot.Enumerate(enum) <> S_OK then
exit;
try
for i := 0 to enum.Count - 1 do
begin
pEnt := CreateJmpEnt(enum.ElementEnum[i].pwcsName, enum.ElementEnum[i].dwType);
try
stgRoot.ReadStream(pEnt.sName, pEnt.Stream);
except
FreeAndNil(pEnt.Stream);
Dispose(pEnt);
continue;
end;
pEnt.llSize := pEnt.Stream.Size;
JmpEntList_.Add(pEnt);
pEnt.Stream.Position := 0;
if CompareText('DestList', pEnt.sName) = 0 then
begin
if pEnt.Stream.Read(DestInfo, SizeOf(DestInfo)) <> SizeOf(DestInfo) then
exit;
while pEnt.Stream.Size > pEnt.Stream.Position do
begin
if pEnt.Stream.Read(DestH, SizeOf(DestH)) <> SizeOf(DestH) then
break;
if pEnt.Stream.Read(DestM, 20) <> 20 then
break;
New(pDestE);
ZeroMemory(pDestE, SizeOf(TJmpDestEnt));
pDestE.Header.sHostName := AnsiString(DestH.sHostName);
// if PJmpDestM10(@DestM[0]).llUnDefined = 0 then
if DestInfo.dwVersion >= 4 then // Windows 7은 1, 10은 4로 보이는데...
begin
// Windows 10
pDestE.Header.llSeq := PJmpDestM10(@DestM[0]).dwSeq;
pDestE.Header.ftLastAccess := PJmpDestM10(@DestM[0]).ftLastAccess;
if pEnt.Stream.Read(DestT10, SizeOf(DestT10)) <> SizeOf(DestT10) then
break;
pDestE.Header.fCount := DestT10.dwCount;
wUniStrLen := DestT10.wUniStrLen;
end else begin
// Windows 7, 8
pDestE.Header.llSeq := PJmpDestM78(@DestM[0]).llSeq;
pDestE.Header.fCount := PJmpDestM78(@DestM[0]).fCount;
pDestE.Header.ftLastAccess := PJmpDestM78(@DestM[0]).ftLastAccess;
if pEnt.Stream.Read(DestT78, SizeOf(DestT78)) <> SizeOf(DestT78) then
break;
// if DestT78.dwPin <> $FFFFFFFF then
// break;
wUniStrLen := DestT78.wUniStrLen;
end;
if (wUniStrLen > 0) and (wUniStrLen <> WORD(-1)) then
begin
SetLength(sTemp, wUniStrLen + 1);
pEnt.Stream.Read(sTemp[0], wUniStrLen * 2);
sTemp[wUniStrLen] := #0;
pDestE.sData := PChar(@sTemp[0]);
if DestInfo.dwVersion > 1 then
pEnt.Stream.Position := pEnt.Stream.Position + 4;
end;
JmpDestEntList_.Add(pDestE);
end;
end else begin
// Guard(LF, TParserLinkFile.Create);
// LF.LoadFromStream(pEnt.Stream);
// LF.
end;
end;
finally
stgRoot.FreeMemAfterEnum(enum);
end;
end;
except
on E: Exception do
ETgException.TraceException(Self, E, 'Fail .. LoadFromFile()');
end;
end;
function GetLastOpenFileFromJumpListAuto(const sJmpAutoPath: String): String;
var
ms: TMemoryStream;
stg: TGSStorage;
stgRoot: TGSStorageCursor;
enum: TGSStorageEnum;
i: Integer;
DestInfo: TJmpDestInfo;
DestH: TJmpDestH;
DestM: array [0..19] of Byte;
DestT78: TJmpDestT78;
DestT10: TJmpDestT10;
sTemp: array of Char;
wUniStrLen: WORD;
begin
Result := '';
try
if FileExists(sJmpAutoPath) then
begin
if GetFileExt(sJmpAutoPath).ToUpper <> 'AUTOMATICDESTINATIONS-MS' then
exit;
Guard(stg, TGSStorage.Create);
if stg.OpenFile(sJmpAutoPath, false, stgRoot) <> S_OK then
exit;
if stgRoot.Enumerate(enum) <> S_OK then
exit;
try
for i := 0 to enum.Count - 1 do
begin
if CompareText('DestList', enum.ElementEnum[i].pwcsName) <> 0 then
continue;
Guard(ms, TMemoryStream.Create);
try
stgRoot.ReadStream(enum.ElementEnum[i].pwcsName, ms);
except
exit;
end;
if ms.Read(DestInfo, SizeOf(DestInfo)) <> SizeOf(DestInfo) then
exit;
while ms.Size > ms.Position do
begin
if ms.Read(DestH, SizeOf(DestH)) <> SizeOf(DestH) then
break;
if ms.Read(DestM, 20) <> 20 then
break;
if DestInfo.dwVersion >= 4 then // Windows 7은 1, 10은 4로 보이는데...
begin
// Windows 10
// Header.llSeq := PJmpDestM10(@DestM[0]).dwSeq;
// Header.ftLastAccess := PJmpDestM10(@DestM[0]).ftLastAccess;
if ms.Read(DestT10, SizeOf(DestT10)) <> SizeOf(DestT10) then
break;
// Header.fCount := DestT10.dwCount;
wUniStrLen := DestT10.wUniStrLen;
end else begin
// Windows 7, 8
// Header.llSeq := PJmpDestM78(@DestM[0]).llSeq;
// Header.fCount := PJmpDestM78(@DestM[0]).fCount;
// Header.ftLastAccess := PJmpDestM78(@DestM[0]).ftLastAccess;
if ms.Read(DestT78, SizeOf(DestT78)) <> SizeOf(DestT78) then
break;
// if DestT78.dwPin <> $FFFFFFFF then
// break;
wUniStrLen := DestT78.wUniStrLen;
end;
if (wUniStrLen > 0) and (wUniStrLen <> WORD(-1)) then
begin
SetLength(sTemp, wUniStrLen + 1);
ms.Read(sTemp[0], wUniStrLen * 2);
sTemp[wUniStrLen] := #0;
Result := PChar(@sTemp[0]);
if DestInfo.dwVersion > 1 then
ms.Position := ms.Position + 4;
exit;
end;
end;
end;
finally
stgRoot.FreeMemAfterEnum(enum);
end;
end;
except
on E: Exception do
ETgException.TraceException(E, 'Fail .. GetRecentOpenFileFromJumpListAuto()');
end;
end;
end.