BSOne.SFC/Tocsg.Module/ChangeExtIcon/BS1ExtIconAip.pas

291 lines
11 KiB
Plaintext

{*******************************************************}
{ }
{ BS1ExtIconAip }
{ }
{ Copyright (C) 2025 kku }
{ }
{*******************************************************}
unit BS1ExtIconAip;
interface
uses
Winapi.Windows, Winapi.ActiveX, System.Win.ComServ, System.Win.ComObj, Winapi.ShlObj,
System.SysUtils;
const
EXTICON_GUID = '{05F4DC17-689D-467F-AA36-08F52942D30A}';
type
TBS1ExtIconAip = class(TComObject, IExtractIcon, IPersistFile)
private
FFilePath: String; // 파일 경로
FIconPath: String; // 아이콘 경로
FIconIndex: Integer; // 아이콘 인덱스
public
Constructor Create;
// IExtractIcon 메서드
{
출처 : https://blog.codingcat.kr/116
GetIconLocation(...)
uFlags
쉘 익스텐션의 작동을 바꿀 수 있는 옵션들입니다. GIL_ASYNC는 아이콘 추출 작업이 오래 걸릴 것인지 물어보기 위해 전달되는 플래그(flag)로, 만일 오래 걸린다면 쉘 익스텐션은 Windows 탐색기에게 아이콘 추출 작업을 백 그라운드에서 수행해 줄 것을 요청할 수 있습니다. 이렇게 하면 Windows 탐색기 창 자체가 버벅거리는 일이 없습니다.
다른 플래그(flag)인 GIL_FORSHELL 및 GIL_OPENICON은 네임스페이스 확장에서 의미 있습니다. 우리가 작업할 프로젝트에서는 실행 시간이 오래 걸리는 코드가 없으므로, 이러한 플래그(flag)들을 고려하지 않아도 됩니다.
szIconFile, cchMax
szIconFile은 쉘(shell)이 제공하는 버퍼로서 우리는 사용하고자 하는 아이콘이 포함된 파일의 이름을 이 곳에 보관하면 됩니다. cchMax는 쉘(shell)이 제공한 버퍼의 크기로서, 단위는 문자 수 입니다.
piIndex
우리가 사용하고자 하는 아이콘이 szIconFile에서 몇 번째 인덱스에 해당하는지를 지정할 정수에 대한 포인터입니다(번역자 주: 이것도 쉘(shell)이 제공하는 변수를 가리키는 유효한 포인터입니다).
pwFlags
쉘(shell)이 제공한 UINT형 변수를 가리키는 유효한 포인터로서, 반환하는 플래그(flag)에 따라 Windows 탐색기의 작동을 우리가 변경할 수 있습니다. 이 곳에 들어갈 수 있는 플래그의 종류에 대하여는 잠시 후 설명하겠습니다.
GetIconLocation 메소드는 szIconFile과 piIndex 매개 변수(parameter)에 내용을 채운 다음 S_OK를 반환합니다. 우리가 커스텀 아이콘을 제공하지 않기로 결정하였다면 S_FALSE를 반환합니다. 이 때 Windows 탐색기는 일반적인 아이콘(알 수 없는 파일)으로 표시해 줄 것입니다.
pwFlags를 통해 반환할 수 있는 플래그(flag)들에는 다음과 같은 종류가 있습니다.
GIL_DONTCACHE
Windows 탐색기가 szIconFile/piIndex로 지정된 파일이 최근에 사용되었는지 여부를 확인하기 위해 캐시를 검색하는 것을 못하게 합니다. 그 결과 IExtractIcon::Extract 메소드가 항상 호출됩니다. ‘두 번째 아이콘 추출 방법’에서 이 플래그에 대해 많은 이야기를 하겠습니다.
GIL_NOTFILENAME
MSDN에 따르면 GetIconLocation이 값을 반환할 때 이 플래그가 있으면 Windows 탐색기가 szIconFile/piIndex를 무시한다고 합니다. 명백하기도 이 플래그(flag)는 쉘 익스텐션이 어떻게 Windows 탐색기로 하여금 IExtractIcon::Extract를 호출하게 만드는지를 보여주는 플래그임이 확실한데, 실제로는 GetIconLocation이 값을 반환할 때 이 플래그는 Windows 탐색기의 작동에 아무 영향을 미치지 못합니다. 이와 관련해서는 나중에 설명하겠습니다.
GIL_SIMULATEDOC
이 플래그(flag)는 Windows 탐색기가 쉘 익스텐션에서 반환된 아이콘을 가져가서, “한 쪽 귀퉁이가 접힌 종이” 모양의 아이콘과 합친 다음에, 그 합성된 아이콘을 해당 파일에 적용해서 보여주라는 의미를 갖습니다. 필자는 잠시 후 이 플래그의 결과를 보여드리겠습니다.
}
function GetIconLocation(uFlags: UINT; szIconFile: PChar; cchMax: UINT;
out piIndex: Integer; out pwFlags: UINT): HResult; stdcall;
function Extract(pszFile: PWideChar; nIconIndex: UINT;
out phiconLarge, phiconSmall: HICON; nIconSize: UINT): HResult; stdcall;
// IPersistFile 메서드
function GetClassID(out classID: TCLSID): HResult; stdcall;
function IsDirty: HResult; stdcall;
function Load(pszFileName: PWideChar; dwMode: Longint): HResult; stdcall;
function Save(pszFileName: PWideChar; fRemember: BOOL): HResult; stdcall;
function SaveCompleted(pszFileName: PWideChar): HResult; stdcall;
function GetCurFile(out pszFileName: PWideChar): HResult; stdcall;
end;
TBS1ExtIconAipFac = class(TComObjectFactory)
public
procedure UpdateRegistry(bRegister: Boolean); override;
end;
implementation
uses
System.Win.Registry, Tocsg.AIP,
Tocsg.Registry,
Vcl.Graphics,
Tocsg.Path;
const
CLASS_BS1ExtIconAip: TGUID = EXTICON_GUID;
//var
// _bInit: Boolean = false;
{ TBS1ExtIconAip }
Constructor TBS1ExtIconAip.Create;
begin
inherited Create;
FIconPath := 'C:\taskToCSG\eCrmHE\Images\22_0530 favicon\favicon_HE_보안.ico';
FIconIndex := 0; // 기본 아이콘 인덱스
end;
(*
.pptx 핸들러 등록하고 싶을 경우
1. HKEY_CLASSES_ROOT\.pptx 가 있는지 찾는데 (보통 MS 파일은 있다)
2. HKEY_CLASSES_ROOT\.pptx 기본 값 확인 (PowerPoint.Show.12)
2. HKEY_CLASSES_ROOT\PowerPoint.Show.12\ShellEx\IconHandler 키에 {05F4DC17-689D-467F-AA36-08F52942D30A} 값을 등록해준다.
3. dll을 등록
4. dll 해제 시 ShellEx\IconHandler 키 복구 또는 삭제
PDF의 경우
HKEY_CLASSES_ROOT\Acrobat.Document.DC\Shellex\IconHandler
이게 우선처리됨...
*)
// IExtractIcon.GetIconLocation
function TBS1ExtIconAip.GetIconLocation(uFlags: UINT; szIconFile: PChar; cchMax: UINT;
out piIndex: Integer; out pwFlags: UINT): HResult;
var
sExt, sTempDir: String;
bIsEnc: Boolean;
begin
// 특정 조건에 따라 아이콘 경로 변경
// if SameText(ExtractFileExt(FFilePath), '.special') then
// begin
// FIconPath := 'C:\Path\To\SpecialIcon.ico';
// FIconIndex := 0;
// end
// else
// begin
// FIconPath := 'C:\Path\To\DefaultIcon.ico';
// FIconIndex := 0;
// end;
// if not _bInit then
// begin
// CoInitialize(nil);
// _bInit := true;
// SetRegValueString(HKEY_CURRENT_USER, 'Software\eCrmHomeEdition', 'BLog0-CoInitialize', FFilePath, true);
// end;
SetRegValueString(HKEY_CURRENT_USER, 'Software\eCrmHomeEdition', 'BLog1', FFilePath, true);
bIsEnc := false;
sExt := GetFileExt(FFilePath).ToUpper;
sTempDir := 'C:\ProgramData\HE\';
if not FFilePath.ToUpper.StartsWith(sTempDir.ToUpper) then
begin
if sExt = 'PDF' then
begin
SetRegValueString(HKEY_CURRENT_USER, 'Software\eCrmHomeEdition', 'BLog2', FFilePath, true);
bIsEnc := IsAipEncrytedPDF(FFilePath);
if bIsEnc then
SetRegValueString(HKEY_CURRENT_USER, 'Software\eCrmHomeEdition', 'BLog3', 'PDF Enc', true)
else
SetRegValueString(HKEY_CURRENT_USER, 'Software\eCrmHomeEdition', 'BLog3', 'PDF Nor', true);
end else
if (sExt = 'DOC') or (sExt = 'XLS') or (sExt = 'PPT') or
(sExt = 'DOT') or (sExt = 'PPS') or (sExt = 'POT') then
begin
bIsEnc := IsAipEncrytedOldOfficeDoc(FFilePath, sTempDir, STGM_READ);
if not bIsEnc then
bIsEnc := IsAipEncrytedOfficeDoc(FFilePath, sTempDir, STGM_READ);
end else
if (sExt = 'DOCX') or (sExt = 'XLSX') or (sExt = 'PPTX') or
(sExt = 'DOCM') or (sExt = 'DOTX') or (sExt = 'XLSM') or
(sExt = 'XLSB') then
begin
bIsEnc := IsAipEncrytedOfficeDoc(FFilePath, sTempDir, STGM_READ);
end;
end;
SetRegValueString(HKEY_CURRENT_USER, 'Software\eCrmHomeEdition', 'BLog4', FFilePath, true);
if bIsEnc then
begin
FIconPath := 'C:\taskToCSG\eCrmHE\Images\22_0530 favicon\favicon_HE_보안.ico';
piIndex := FIconIndex;
end else
begin
// FIconPath := 'C:\taskToCSG\eCrmHE\Images\22_0530 favicon\favicon_HE_수면.ico';
if sExt = 'PPTX' then
begin
FIconPath := 'C:\Program Files (x86)\Microsoft Office\Root\VFS\Windows\Installer\{90160000-000F-0000-0000-0000000FF1CE}\pptico.exe';
piIndex := 10;
end else
if sExt = 'PDF' then
begin
// FIConPath := 'C:\Program Files (x86)\UPDF\defaulticon.ico';
// FIconPath := 'C:\taskToCSG\eCrmHE\Images\22_0530 favicon\favicon_HE_수면.ico';
FIconPath := 'C:\WINDOWS\Installer\{AC76BA86-1042-1033-7760-BC15014EA700}\_PDFFile.ico';
piIndex := 0;
end;
end;
// SetRegValueString(HKEY_CURRENT_USER, 'Software\eCrmHomeEdition', 'BLog2', '', true);
// 아이콘 경로와 인덱스 반환
StrPLCopy(szIconFile, FIconPath, Length(FIconPath));
// SetRegValueString(HKEY_CURRENT_USER, 'Software\eCrmHomeEdition', 'B1', szIconFile, true);
// SetRegValueString(HKEY_CURRENT_USER, 'Software\eCrmHomeEdition', 'B2', FIconPath, true);
pwFlags := 0; // GIL_PERINSTANCE; // 파일별로 고유 아이콘 제공
Result := S_OK;
// else
// Result := S_FALSE;
end;
// IExtractIcon.Extract
function TBS1ExtIconAip.Extract(pszFile: PWideChar; nIconIndex: UINT;
out phiconLarge, phiconSmall: HICON; nIconSize: UINT): HResult;
var
ic: TIcon;
begin
// 지정된 아이콘 로드
// ic := TIcon.Create;
// ic.LoadFromFile(FIconPath);
// phiconLarge := ic.Handle; // LoadImage(HInstance, PWideChar(FIconPath), FIconIndex);
// phiconSmall := ic.Handle; // ExtractIcon(HInstance, PWideChar(FIconPath), FIconIndex);
//// ic.Free;
//
// if (phiconLarge <> 0) and (phiconSmall <> 0) then
// Result := S_OK
// else
Result := S_FALSE;
end;
// IPersistFile.GetClassID
function TBS1ExtIconAip.GetClassID(out classID: TCLSID): HResult;
begin
classID := CLASS_BS1ExtIconAip;
Result := S_OK;
end;
// IPersistFile.IsDirty
function TBS1ExtIconAip.IsDirty: HResult;
begin
Result := S_FALSE; // 항상 깨끗한 상태
end;
// IPersistFile.Load
function TBS1ExtIconAip.Load(pszFileName: PWideChar; dwMode: Longint): HResult;
begin
FFilePath := pszFileName; // 파일 경로 저장
Result := S_OK;
end;
// IPersistFile.Save
function TBS1ExtIconAip.Save(pszFileName: PWideChar; fRemember: BOOL): HResult;
begin
Result := E_NOTIMPL; // 저장은 구현하지 않음
end;
// IPersistFile.SaveCompleted
function TBS1ExtIconAip.SaveCompleted(pszFileName: PWideChar): HResult;
begin
Result := E_NOTIMPL;
end;
// IPersistFile.GetCurFile
function TBS1ExtIconAip.GetCurFile(out pszFileName: PWideChar): HResult;
begin
Result := E_NOTIMPL;
end;
{ TBS1ExtIconAipFac }
procedure TBS1ExtIconAipFac.UpdateRegistry(bRegister: Boolean);
begin
if bRegister then
begin
inherited UpdateRegistry(bRegister);
SetRegValueString(HKEY_LOCAL_MACHINE,
'SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved', EXTICON_GUID, 'BSOne ExtIcon', true);
end else begin
DelRegValue(HKEY_LOCAL_MACHINE,
'SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved', EXTICON_GUID);
inherited UpdateRegistry(bRegister);
end;
end;
initialization
// COM 객체 등록
TBS1ExtIconAipFac.Create(ComServer, TBS1ExtIconAip, CLASS_BS1ExtIconAip,
'BS1ExtIconAip', 'BSOne-ExtIcon', ciMultiInstance, tmApartment);
end.