291 lines
11 KiB
Plaintext
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.
|