CEF4Delphi/source/uCEFOLEDragAndDrop.pas
salvadordf ca8bc9dff4 Added cef4delphi.chm help file
Added the PDS file to extract the HTML Help files using PasDoc
Added more XML documentation
Fixed some XML errors.
Removed the license copy from the pas units.
Updated the LICENSE.md file
2023-08-09 19:38:57 +02:00

687 lines
20 KiB
ObjectPascal

unit uCEFOLEDragAndDrop;
{$IFDEF FPC}
{$MODE OBJFPC}{$H+}
{$ENDIF}
{$I cef.inc}
{$IFNDEF FPC}{$IFNDEF DELPHI12_UP}
// Workaround for "Internal error" in old Delphi versions caused by uint64 handling
{$R-}
{$ENDIF}{$ENDIF}
interface
uses
{$IFDEF DELPHI16_UP}
{$IFDEF MSWINDOWS}WinApi.Windows, WinApi.ShlObj, WinApi.ActiveX,{$ENDIF} System.Classes, System.Math;
{$ELSE}
{$IFDEF MSWINDOWS}Windows, ShlObj, ActiveX,{$ENDIF} Classes, Math;
{$ENDIF}
const
CUSTOM_ARRAY_LENGTH = 25;
type
TOLEMediumArray = array [0..pred(CUSTOM_ARRAY_LENGTH)] of TStgMedium;
TOLEFormatArray = array [0..pred(CUSTOM_ARRAY_LENGTH)] of TFormatEtc;
TOLEDragAndDropMgr = class
protected
function GetStorageForBytes(var aMedium : TStgMedium; const aData : pointer; aLength : NativeUInt) : boolean;
function GetStorageForString(var aMedium : TStgMedium; const aData : WideString) : boolean; overload;
function GetStorageForString(var aMedium : TStgMedium; const aData : AnsiString) : boolean; overload;
function GetStorageForFileDescriptor(var aMedium : TStgMedium; const aFileName : string) : boolean;
public
function DragEnter(const DataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT; virtual;
function DragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT; virtual;
function DragLeave: HRESULT; virtual;
function Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT; virtual;
end;
TOLEEnumFormatEtc = class(TInterfacedObject, IEnumFormatEtc)
protected
FIndex : integer;
FNumFormats : integer;
FFormatArray : TOLEFormatArray;
procedure CopyFromFormatArray(const aSrcFormatArray : TOLEFormatArray);
procedure CopyFormatEtc(var aDstFormatEtc : TFormatEtc; const aSrcFormatEtc : TFormatEtc);
public
constructor Create; overload;
constructor Create(const aFormatArray : TOLEFormatArray; aNumFormats : integer; aIndex : integer = 0); overload;
destructor Destroy; override;
// IEnumFormatEtc
{$IFNDEF FPC}
function Next(Celt: LongInt; out Rgelt; pCeltFetched: pLongInt): HRESULT; stdcall;
function Skip(Celt: Longint): HRESULT; stdcall;
{$ELSE}
function Next(Celt: ULONG; out Rgelt: FormatEtc; pceltFetched: PULONG = nil): HRESULT; stdcall;
function Skip(Celt: ULONG): HRESULT; stdcall;
{$ENDIF}
function Reset: HRESULT; stdcall;
function Clone(out Enum: IEnumFormatEtc): HRESULT; stdcall;
end;
TOLEDropSource = class(TInterfacedObject, IDropSource)
public
// IDropSource
{$IFNDEF FPC}
function QueryContinueDrag(fEscapePressed: bool; grfKeyState: LongInt): HRESULT; stdcall;
function GiveFeedback(dwEffect: LongInt): HRESULT; stdcall;
{$ELSE}
function QueryContinueDrag(fEscapePressed: BOOL; grfKeyState: DWORD): HRESULT; stdcall;
function GiveFeedback(dwEffect: DWORD): HRESULT; stdcall;
{$ENDIF}
end;
TOLEDataObject = class(TInterfacedObject, IDataObject)
protected
FNumFormats : integer;
FFormatArray : TOLEFormatArray;
FMediumArray : TOLEMediumArray;
FAsync : boolean;
FInOperation : boolean;
function LookupFormatEtc(const aFormatEtc : TFormatEtc) : integer;
function DupGlobalMem(hMem : HGLOBAL) : HGLOBAL;
public
constructor Create(const aFormatArray : TOLEFormatArray; const aMediumArray : TOLEMediumArray; aNumFormats : integer); reintroduce;
// IDataObject
function GetData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium):HRESULT; stdcall;
function GetDataHere(const FormatEtc: TFormatEtc; out Medium: TStgMedium):HRESULT; stdcall;
function QueryGetData(const FormatEtc: TFormatEtc): HRESULT; stdcall;
function GetCanonicalFormatEtc(const FormatEtc: TFormatEtc; out FormatEtcout: TFormatEtc): HRESULT; stdcall;
{$IFNDEF FPC}
function SetData(const FormatEtc: TFormatEtc; var Medium: TStgMedium; fRelease: Bool): HRESULT; stdcall;
function EnumFormatEtc(dwDirection: LongInt; out aEnumFormatEtc: IEnumFormatEtc): HRESULT; stdcall;
function dAdvise(const FormatEtc: TFormatEtc; advf: LongInt; const advsink: IAdviseSink; out dwConnection: LongInt): HRESULT; stdcall;
function dUnadvise(dwConnection: LongInt): HRESULT; stdcall;
{$ELSE}
function SetData(const pformatetc: FORMATETC; {$IFDEF FPC_VER_320}var{$ELSE}const{$ENDIF} medium: STGMEDIUM; FRelease: BOOL): HRESULT; stdcall;
function EnumFormatEtc(dwDirection: DWORD; out aEnumFormatEtc: IENUMFORMATETC): HRESULT; stdcall;
function DAdvise(const formatetc: FORMATETC; advf: DWORD; const AdvSink: IAdviseSink; out dwConnection: DWORD): HRESULT; stdcall;
function DUnadvise(dwconnection: DWORD): HRESULT; stdcall;
{$ENDIF}
function EnumdAdvise(out EnumAdvise: IEnumStatData): HRESULT; stdcall;
end;
TOLEDropTarget = class(TInterfacedObject, IDropTarget)
protected
FManager : TOLEDragAndDropMgr;
public
constructor Create(const aManager : TOLEDragAndDropMgr); reintroduce;
// IDropTarget
{$IFNDEF FPC}
function DragEnter(const DataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT; stdcall;
function DragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT; stdcall;
function Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT; stdcall;
{$ELSE}
function DragEnter(const dataObj: IDataObject; grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HRESULT; stdcall;
function DragOver(grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HRESULT; stdcall;
function Drop(const dataObj: IDataObject; grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HRESULT; stdcall;
{$ENDIF}
function DragLeave: HRESULT; stdcall;
end;
implementation
// *****************************************************
// *************** TOLEDragAndDropMgr ******************
// *****************************************************
function TOLEDragAndDropMgr.GetStorageForBytes(var aMedium : TStgMedium; const aData : pointer; aLength : NativeUInt) : boolean;
var
TempHandle : HGLOBAL;
TempPointer : pointer;
begin
Result := False;
if (aData <> nil) then
begin
TempHandle := GlobalAlloc(GHND, aLength);
if (TempHandle <> 0) then
begin
TempPointer := GlobalLock(TempHandle);
if (TempPointer <> nil) then
begin
Move(aData^, TempPointer^, aLength);
aMedium.hGlobal := TempHandle;
aMedium.tymed := TYMED_HGLOBAL;
{$IFNDEF FPC}
aMedium.unkForRelease := nil;
{$ELSE}
aMedium.PUnkForRelease := nil;
{$ENDIF}
GlobalUnlock(TempHandle);
Result := True;
end
else
GlobalFree(TempHandle);
end;
end;
end;
function TOLEDragAndDropMgr.GetStorageForString(var aMedium : TStgMedium; const aData : WideString) : boolean;
var
TempPointer : pointer;
begin
Result := False;
if (length(aData) > 0) then
begin
TempPointer := @aData[1];
Result := GetStorageForBytes(aMedium, TempPointer, length(aData) * SizeOf(WideChar));
end;
end;
function TOLEDragAndDropMgr.GetStorageForString(var aMedium : TStgMedium; const aData : AnsiString) : boolean;
var
TempPointer : pointer;
begin
Result := False;
if (length(aData) > 0) then
begin
TempPointer := @aData[1];
Result := GetStorageForBytes(aMedium, TempPointer, length(aData) * SizeOf(AnsiChar));
end;
end;
function TOLEDragAndDropMgr.GetStorageForFileDescriptor(var aMedium : TStgMedium; const aFileName : string) : boolean;
{$IFDEF FPC}
const
FD_LINKUI = $8000;
{$ENDIF}
var
TempHandle : HGLOBAL;
TempDescriptor : TFileGroupDescriptor;
TempPointer : pointer;
i, j : integer;
TempString : string;
begin
Result := False;
if (length(aFileName) > 0) then
begin
TempHandle := GlobalAlloc(GHND, sizeof(TFileGroupDescriptor));
if (TempHandle <> 0) then
begin
TempPointer := GlobalLock(TempHandle);
if (TempPointer <> nil) then
begin
TempDescriptor := TFileGroupDescriptor(TempPointer^);
TempDescriptor.cItems := 1;
TempDescriptor.fgd[0].dwFlags := FD_LINKUI;
TempString := aFileName + #0;
i := 1;
j := length(TempString);
while (i <= j) do
begin
TempDescriptor.fgd[0].cFileName[pred(i)] := TempString[i];
inc(i);
end;
aMedium.tymed := TYMED_HGLOBAL;
aMedium.hGlobal := TempHandle;
{$IFNDEF FPC}
aMedium.unkForRelease := nil;
{$ELSE}
aMedium.PUnkForRelease := nil;
{$ENDIF}
GlobalUnlock(TempHandle);
Result := True;
end
else
GlobalFree(TempHandle);
end;
end;
end;
function TOLEDragAndDropMgr.DragEnter(const DataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT;
begin
Result := S_OK;
dwEffect := DROPEFFECT_NONE;
end;
function TOLEDragAndDropMgr.DragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT;
begin
Result := S_OK;
dwEffect := DROPEFFECT_NONE;
end;
function TOLEDragAndDropMgr.DragLeave: HRESULT;
begin
Result := S_OK;
end;
function TOLEDragAndDropMgr.Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT;
begin
Result := S_OK;
dwEffect := DROPEFFECT_NONE;
end;
// *****************************************************
// **************** TOLEEnumFormatEtc ******************
// *****************************************************
constructor TOLEEnumFormatEtc.Create;
begin
inherited Create;
FIndex := 0;
FNumFormats := 0;
end;
constructor TOLEEnumFormatEtc.Create(const aFormatArray : TOLEFormatArray; aNumFormats, aIndex : integer);
begin
inherited Create;
FIndex := aIndex;
FNumFormats := min(aNumFormats, CUSTOM_ARRAY_LENGTH);
CopyFromFormatArray(aFormatArray);
end;
destructor TOLEEnumFormatEtc.Destroy;
var
i : integer;
begin
i := 0;
while (i < FNumFormats) do
begin
if (FFormatArray[i].ptd <> nil) then CoTaskMemFree(FFormatArray[i].ptd);
inc(i);
end;
inherited Destroy;
end;
procedure TOLEEnumFormatEtc.CopyFromFormatArray(const aSrcFormatArray : TOLEFormatArray);
var
i : integer;
begin
i := 0;
while (i < FNumFormats) do
begin
CopyFormatEtc(FFormatArray[i], aSrcFormatArray[i]);
inc(i);
end;
end;
procedure TOLEEnumFormatEtc.CopyFormatEtc(var aDstFormatEtc : TFormatEtc; const aSrcFormatEtc : TFormatEtc);
var
Size: Integer;
begin
aDstFormatEtc.cfFormat := aSrcFormatEtc.cfFormat;
aDstFormatEtc.dwAspect := aSrcFormatEtc.dwAspect;
aDstFormatEtc.lindex := aSrcFormatEtc.lindex;
aDstFormatEtc.tymed := aSrcFormatEtc.tymed;
if (aSrcFormatEtc.ptd = nil) then
aDstFormatEtc.ptd := nil
else
begin
Size := Max(aSrcFormatEtc.ptd^.tdSize, SizeOf(DVTARGETDEVICE));
aDstFormatEtc.ptd := CoTaskMemAlloc(Size);
Move(aSrcFormatEtc.ptd^, aDstFormatEtc.ptd^, Size);
end;
end;
function TOLEEnumFormatEtc.Next
{$IFNDEF FPC}
(Celt: LongInt; out Rgelt; pCeltFetched: pLongInt): HRESULT; stdcall;
{$ELSE}
(Celt: ULONG; out Rgelt: FormatEtc; pceltFetched: PULONG): HRESULT; stdcall;
{$ENDIF}
var
i : integer;
TempArray : ^TOLEFormatArray;
begin
i := 0;
TempArray := @Rgelt;
while (i < Celt) and (FIndex < FNumFormats) do
begin
CopyFormatEtc(TempArray^[i], FFormatArray[FIndex]);
inc(i);
inc(FIndex);
end;
if (pCeltFetched <> nil) then pCeltFetched^ := i;
if (i = Celt) then
Result := S_OK
else
Result := S_FALSE;
end;
function TOLEEnumFormatEtc.Skip
{$IFNDEF FPC}
(Celt: Longint): HRESULT; stdcall;
{$ELSE}
(Celt: ULONG): HRESULT; stdcall;
{$ENDIF}
begin
FIndex := FIndex + Celt;
if (FIndex <= FNumFormats) then
Result := S_OK
else
Result := S_FALSE;
end;
function TOLEEnumFormatEtc.Reset: HRESULT; stdcall;
begin
FIndex := 0;
Result := S_OK;
end;
function TOLEEnumFormatEtc.Clone(out Enum: IEnumFormatEtc): HRESULT; stdcall;
begin
Enum := TOLEEnumFormatEtc.Create(FFormatArray, FNumFormats, FIndex);
Result := S_OK;
end;
// *****************************************************
// ****************** TOLEDropTarget *******************
// *****************************************************
constructor TOLEDropTarget.Create(const aManager : TOLEDragAndDropMgr);
begin
inherited Create;
FManager := aManager;
end;
function TOLEDropTarget.DragEnter
{$IFNDEF FPC}
(const DataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT; stdcall;
{$ELSE}
(const dataObj: IDataObject; grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HRESULT; stdcall;
{$ENDIF}
begin
Result := FManager.DragEnter(DataObj, grfKeyState, pt, Longint(dwEffect));
end;
function TOLEDropTarget.DragOver
{$IFNDEF FPC}
(grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT; stdcall;
{$ELSE}
(grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HRESULT; stdcall;
{$ENDIF}
begin
Result := FManager.DragOver(grfKeyState, pt, Longint(dwEffect));
end;
function TOLEDropTarget.DragLeave: HRESULT; stdcall;
begin
Result := FManager.DragLeave;
end;
function TOLEDropTarget.Drop
{$IFNDEF FPC}
(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HRESULT; stdcall;
{$ELSE}
(const dataObj: IDataObject; grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HRESULT; stdcall;
{$ENDIF}
begin
Result := FManager.Drop(dataObj, grfKeyState, pt, Longint(dwEffect));
end;
// *****************************************************
// ****************** TOLEDropSource *******************
// *****************************************************
function TOLEDropSource.QueryContinueDrag
{$IFNDEF FPC}
(fEscapePressed: bool; grfKeyState: LongInt): HRESULT; stdcall;
{$ELSE}
(fEscapePressed: BOOL; grfKeyState: DWORD): HRESULT; stdcall;
{$ENDIF}
begin
if fEscapePressed then
Result := DRAGDROP_S_CANCEL
else
if ((grfKeyState and MK_LBUTTON) = 0) then
Result := DRAGDROP_S_DROP
else
Result := S_OK;
end;
function TOLEDropSource.GiveFeedback
{$IFNDEF FPC}
(dwEffect: LongInt): HRESULT; stdcall;
{$ELSE}
(dwEffect: DWORD): HRESULT; stdcall;
{$ENDIF}
begin
Result := DRAGDROP_S_USEDEFAULTCURSORS;
end;
// *****************************************************
// ****************** TOLEDataObject *******************
// *****************************************************
constructor TOLEDataObject.Create(const aFormatArray : TOLEFormatArray;
const aMediumArray : TOLEMediumArray;
aNumFormats : integer);
var
i : integer;
begin
inherited Create;
FAsync := False;
FInOperation := False;
FNumFormats := min(aNumFormats, CUSTOM_ARRAY_LENGTH);
i := 0;
while (i < FNumFormats) do
begin
FFormatArray[i].cfFormat := aFormatArray[i].cfFormat;
FFormatArray[i].ptd := aFormatArray[i].ptd;
FFormatArray[i].dwAspect := aFormatArray[i].dwAspect;
FFormatArray[i].lindex := aFormatArray[i].lindex;
FFormatArray[i].tymed := aFormatArray[i].tymed;
FMediumArray[i] := aMediumArray[i];
inc(i);
end;
end;
function TOLEDataObject.LookupFormatEtc(const aFormatEtc : TFormatEtc) : integer;
var
i : integer;
begin
Result := -1;
i := 0;
while (i < FNumFormats) do
if ((FFormatArray[i].tymed and aFormatEtc.tymed) <> 0) and
(FFormatArray[i].cfFormat = aFormatEtc.cfFormat) and
(FFormatArray[i].dwAspect = aFormatEtc.dwAspect) then
begin
Result := i;
exit;
end
else
inc(i);
end;
function TOLEDataObject.DupGlobalMem(hMem : HGLOBAL) : HGLOBAL;
var
TempLen : cardinal;
TempHandle : HGLOBAL;
TempSrc : Pointer;
TempDst : Pointer;
begin
Result := 0;
TempSrc := GlobalLock(hMem);
if (TempSrc <> nil) then
begin
TempLen := GlobalSize(hMem);
TempHandle := GlobalAlloc(GHND, TempLen);
if (TempHandle <> 0) then
begin
TempDst := GlobalLock(TempHandle);
if (TempDst <> nil) then
begin
Move(TempSrc^, TempDst^, TempLen);
Result := TempHandle;
GlobalUnlock(TempHandle);
end
else
GlobalFree(TempHandle);
end;
GlobalUnlock(hMem);
end;
end;
function TOLEDataObject.GetData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium):HRESULT; stdcall;
var
i : integer;
begin
i := LookupFormatEtc(FormatEtcIn);
if (i < 0) or ((FFormatArray[i].tymed and TYMED_HGLOBAL) = 0) then
begin
Medium.tymed := TYMED_NULL;
{$IFNDEF FPC}
Medium.unkForRelease := nil;
{$ELSE}
Medium.PUnkForRelease := nil;
{$ENDIF}
Medium.hGlobal := 0;
Result := DV_E_FORMATETC;
end
else
begin
Medium.tymed := FFormatArray[i].tymed;
{$IFNDEF FPC}
Medium.unkForRelease := nil;
{$ELSE}
Medium.PUnkForRelease := nil;
{$ENDIF}
Medium.hGlobal := DupGlobalMem(FMediumArray[i].hGlobal);
Result := S_OK;
end;
end;
function TOLEDataObject.GetDataHere(const FormatEtc: TFormatEtc; out Medium: TStgMedium):HRESULT; stdcall;
begin
Result := DV_E_FORMATETC;
end;
function TOLEDataObject.QueryGetData(const FormatEtc: TFormatEtc): HRESULT; stdcall;
begin
if (LookupFormatEtc(FormatEtc) < 0) then
Result := DV_E_FORMATETC
else
Result := S_OK;
end;
function TOLEDataObject.GetCanonicalFormatEtc(const FormatEtc: TFormatEtc; out FormatEtcout: TFormatEtc): HRESULT; stdcall;
begin
FormatEtcout.cfFormat := 0;
FormatEtcout.dwAspect := DVASPECT_CONTENT;
FormatEtcout.lindex := -1;
FormatEtcout.tymed := TYMED_NULL;
FormatEtcout.ptd := nil;
Result := E_NOTIMPL;
end;
function TOLEDataObject.SetData
{$IFNDEF FPC}
(const FormatEtc: TFormatEtc; var Medium: TStgMedium; fRelease: Bool): HRESULT; stdcall;
{$ELSE}
(const pformatetc: FORMATETC; {$IFDEF FPC_VER_320}var{$ELSE}const{$ENDIF} medium: STGMEDIUM; FRelease: BOOL): HRESULT; stdcall;
{$ENDIF}
begin
Result := E_NOTIMPL;
end;
function TOLEDataObject.EnumFormatEtc
{$IFNDEF FPC}
(dwDirection: LongInt; out aEnumFormatEtc: IEnumFormatEtc): HRESULT; stdcall;
{$ELSE}
(dwDirection: DWORD; out aEnumFormatEtc: IENUMFORMATETC): HRESULT; stdcall;
{$ENDIF}
begin
if (dwDirection = DATADIR_GET) then
begin
aEnumFormatEtc := TOLEEnumFormatEtc.Create(FFormatArray, FNumFormats);
Result := S_OK;
end
else
begin
aEnumFormatEtc := nil;
if (dwDirection = DATADIR_SET) then
Result := E_NOTIMPL
else
Result := E_INVALIDARG;
end;
end;
function TOLEDataObject.dAdvise
{$IFNDEF FPC}
(const FormatEtc: TFormatEtc; advf: LongInt; const advsink: IAdviseSink; out dwConnection: LongInt): HRESULT; stdcall;
{$ELSE}
(const formatetc: FORMATETC; advf: DWORD; const AdvSink: IAdviseSink; out dwConnection: DWORD): HRESULT; stdcall;
{$ENDIF}
begin
Result := OLE_E_ADVISENOTSUPPORTED;
end;
function TOLEDataObject.dUnadvise
{$IFNDEF FPC}
(dwConnection: LongInt): HRESULT; stdcall;
{$ELSE}
(dwconnection: DWORD): HRESULT; stdcall;
{$ENDIF}
begin
Result := OLE_E_ADVISENOTSUPPORTED;
end;
function TOLEDataObject.EnumdAdvise(out EnumAdvise: IEnumStatData): HRESULT; stdcall;
begin
Result := OLE_E_ADVISENOTSUPPORTED;
end;
end.