Vielen Dank, Himitsu. Das Ganze ist am Rand meiner Kenntnisse, bzw. eigentlich darüber hinaus. Zudem bin ich mittlerweile im Zweifel, ob mir IThumbnailProvider eigentlich das bringt, was ich brauche, nämlich eine Miniaturansicht des JPG-Inhalts. Diese ganzen Thumbnailsachen scheinen nämlich einen quadratischen Thumbnail zurückzugeben, was etwas anderes ist.
Ich habe jetzt - nicht zuletzt aus didaktischen und auch sportlichen Gründen - intensiv weiter gesucht und ein paar Stellen gefunden, die relativ weit führen, aber eben nie einen funktionierenden Code liefern. Ich habe das Gefühl, wenn ich ein bisschen mehr in diesem Stoff stünde, dann wäre es von diesen Beispielen aus gar nicht so schwer, aber hingekriegt habe ich es einfach nicht.
Natürlich als Erstes die bereits erwähnten
Vorschläge von Remy Lebeau. Nur halt: Wie umsetzen?
Hier hat Postscripter in einem russischen Forum in #9 ein Gerüst angegeben und in #10 offenbar auch fertiggestellt. Leider komme ich an test.rar nicht heran, selbst auf eine Anmeldung hin erfolgte keine Antwort.
Hier gibt es ebenfalls eine Anleitung, die ich aber auch nicht ans Laufen gebracht habe. Die dort angegebene
function GetPreviewHandlerCLSID(const AFileName: string): string;
funktioniert auch nicht. Ein Hinweis darauf, warum nicht, findet sich in der mit Vergnügen zu lesenden
Frage von Ian Boyd, wie man den richtigen IPreviewHandler erzeugt. Der entscheidende Hinweis wird ganz am Schluss von Simon Mourier gegeben ("
There are today some files that don't have a preview handler at all (.txt and all image types like .png, .jpg or the modern .heic, .webp, etc.)."). Tatsächlich habe ich einfach zu Fuß die Registry durchsucht, und in der Tat gab es unter HKEY_CLASSES_ROOT\jpegfile\ShellEx\ den genannten Schlüssel {e357fccd-a995-4576-b01f-234630154e96} mit der
GUID {C7657C4A-9F68-40fa-A4DF-96BC08EB3551} als Wert. Den kannte ich schon von
Microsoft, es handelt sich um CLSID_PhotoThumbnailProvider.
Ich habe mich erstmal an Postscripter gehalten und die beiden Interfaces als Klasse implementiert. Warum man die beiden
Initialize
umbiegen muss -> keine Ahnung, Postscriper selbst schreibt "извращенцы", was "Perverse!" heißt. Ein paar Deklarationen habe ich eingefügt, auch wenn sie in den referenzierten Units enthalten waren, da die Units nicht immer dieselbe Deklaration hatten und auch, um unabhängig zu sein. Die Prozedur läuft auch durch, jedoch hat das Bitmap eine Breite/Länge von 0, obwohl mir das
Handle plausibel aussieht. Allerdings habe ich auch keine Ahnung, womit ich die Aufrufe von
GetThumbnail
und
Initialize_WS
eigentlich füllen soll, das sind doch
API-Aufrufe?! Postscripter hat sie mit
Beep
und
Showmessage('Funktioniert!'
gefüllt; Endgültiges steht wohl im test.rar, das ich ja nicht habe.
Es ist ja klar, dass ich da herumdoktere, ohne mehr als eine Halbahnung zu haben, was ich da eigentlich tue. Wahrscheinlich kann jemand von den alten Hasen da Ordnung ins Chaos bringen.
(Der Versuch,
FPreviewHandler := CreateComObject
statt
TComObjectFactory
zu benutzen und damit
QueryInterface
durchzuführen, scheitert übrigens an "Interface not supported".)
Delphi-Quellcode:
uses
...
ComServ,
Winapi.ActiveX, ComObj,
Winapi.ShlObj,
Winapi.PropSys;
type
{$EXTERNALSYM WTS_ALPHATYPE}
WTS_ALPHATYPE = (
WTSAT_UNKNOWN = 0,
WTSAT_RGB = 1,
WTSAT_ARGB = 2
);
const
{$EXTERNALSYM SID_IThumbnailProvider}
SID_IThumbnailProvider = '
{e357fccd-a995-4576-b01f-234630154e96}';
SID_IInitializeWithStream = '
{b824b49d-22ac-4161-ac8a-9916e8fa3f7f}';
SID_IInitializeWithFile = '
{b7d14566-0509-4cce-a71f-0a554233bd9b}';
type
IThumbnailProvider =
interface(IUnknown)
[SID_IThumbnailProvider]
function GetThumbnail(cx: UINT;
var phbmp: HBITMAP;
var Flags: DWORD): HResult;
stdcall;
end;
IInitializeWithFile =
interface(IUnknown)
[SID_IInitializeWithFile]
function Initialize(pszFilePath: PWideChar; grfMode: DWORD): HRESULT;
stdcall;
end;
IInitializeWithStream =
interface(IUnknown)
[SID_IInitializeWithStream]
function Initialize(
const pstream: IStream; grfMode: DWORD): HRESULT;
stdcall;
end;
TThumbnailProvider =
class(TComObject, IThumbnailProvider, IInitializeWithStream, IInitializeWithFile)
private
protected
function GetThumbnail(cx: UINT;
var phbmp: HBITMAP;
var Flags: DWORD): HResult;
stdcall;
function IInitializeWithFile.Initialize = Initialize_WF;
// извращенцы
function IInitializeWithStream.Initialize = Initialize_WS;
function Initialize_WF(pszFilePath: PWideChar; grfMode: DWORD): HResult;
stdcall;
function Initialize_WS(
const pstream: IStream; grfMode: DWORD): HResult;
stdcall;
end;
type
TForm1 =
class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
function LoadPreviewHandler(
const FileName:
string):HBitmap;
function ErstelleMiniatur(
const FileName:
string; BMPHandel:HBitmap):HBitmap;
function GetPreviewHandlerCLSID(
const AFileName:
string):
string;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
BMP:TBitmap;
begin
BMP := TBitmap.Create(256,256);
Try
BMP.Handle := ErstelleMiniatur('
C:\Temp\7IV06423.JPG',BMP.Handle);
Finally
BMP.Free;
end;
end;
function ErstelleMiniatur(
const FileName:
string; BMPHandle:HBitmap):HBitmap;
var
LPreviewGUID : TGUID;
LInitializeWithFile : IInitializeWithFile;
LInitializeWithStream : IInitializeWithStream;
LInitializeWithItem : IInitializeWithItem;
LIStream : IStream;
LShellItem : IShellItem;
FPreviewHandler : IPreviewHandler;
FFileStream:TFileStream;
TP:IThumbnailProvider;
Alpha:WTS_ALPHATYPE;
Alpha2:Cardinal;
const
CLSID_PhotoThumbnailProvider = '
{C7657C4A-9F68-40fa-A4DF-96BC08EB3551}';
begin
Result := BMPHandle;
LPreviewGUID:= StringToGUID('
{098f2470-bae0-11cd-b579-08002b30bfeb}');
LPreviewGUID:= StringToGUID(SID_IThumbnailProvider);
LPreviewGUID:= StringToGUID(CLSID_PhotoThumbnailProvider);
TComObjectFactory.Create(ComServer, TThumbnailProvider, LPreviewGUID, '
Miniatur', '
Miniatur', ciSingleInstance, tmSingle);
// FPreviewHandler := CreateComObject(LPreviewGUID) As IPreviewHandler;
// if (FPreviewHandler = nil) then
// exit;
TP := TThumbnailProvider.Create;
If TP.QueryInterface(IInitializeWithStream, LInitializeWithStream) = S_OK
then begin
FFileStream := TFileStream.Create(FileName, fmOpenRead
or fmShareDenyNone);
LIStream := TStreamAdapter.Create(FFileStream, soOwned)
as IStream;
LInitializeWithStream.Initialize(LIStream, STGM_READ);
TP.GetThumbnail(256,Result,Alpha2);
Alpha := WTS_ALPHATYPE(Alpha2);
TP.Free;
end;
end;
function TThumbnailProvider.GetThumbnail(cx: UINT;
var phbmp: HBITMAP;
var Flags: DWORD): HResult;
begin
end;
function TThumbnailProvider.Initialize_WF(pszFilePath: PWideChar; grfMode: DWORD): HResult;
begin
end;
function TThumbnailProvider.Initialize_WS(
const pstream: IStream; grfMode: DWORD): HResult;
begin
end;