UPD: Support more formats in drag&drop operations in Windows.

FIX: Correctly handle specified transport medium type in Windows (HGLOBAL only).
This commit is contained in:
cobines 2009-04-19 11:27:24 +00:00
commit a8ee99d0fa
2 changed files with 533 additions and 203 deletions

View file

@ -5,7 +5,7 @@ unit uClipboard;
interface
uses
Classes, SysUtils;
Classes, SysUtils, LCLType;
type TClipboardOperation = ( ClipboardCopy, ClipboardCut );
@ -14,32 +14,24 @@ uses
function PasteFromClipboard(out ClipboardOp: TClipboardOperation;
out filenames:TStringList):Boolean;
{$IF DEFINED(UNIX)}
function URIDecode(encodedUri: String): String;
function URIEncode(path: String): String;
function ExtractFilenames(uriList: String): TStringList;
const
// General MIME
uriListMime = 'text/uri-list';
textPlainMime = 'text/plain';
fileScheme = 'file:'; // for URI
{$ENDIF}
uriListMime = 'text/uri-list';
textPlainMime = 'text/plain';
implementation
fileScheme = 'file:'; // for URI
uses
{$IFDEF MSWINDOWS}
Windows, ActiveX, uOleDragDrop, fMain,
{$ELSE IFDEF UNIX}
LCLIntf, LCLType,
{$ENDIF}
Clipbrd;
const
{$IFDEF MSWINDOWS}
CFSTR_PREFERREDDROPEFFECT = 'Preferred DropEffect';
CFSTR_PREFERRED_DROPEFFECT = 'Preferred DropEffect';
CFSTR_FILENAME = 'FileName';
CFSTR_FILENAMEW = 'FileNameW';
CFSTR_UNIFORM_RESOURCE_LOCATOR = 'UniformResourceLocator';
CFSTR_UNIFORM_RESOURCE_LOCATORW = 'UniformResourceLocatorW';
{$ELSE IFDEF UNIX}
@ -54,7 +46,57 @@ const
{$ENDIF}
{$IFDEF UNIX}
var
{$IFDEF MSWINDOWS}
CFU_PREFERRED_DROPEFFECT,
CFU_FILENAME,
CFU_FILENAMEW,
CFU_UNIFORM_RESOURCE_LOCATOR,
CFU_UNIFORM_RESOURCE_LOCATORW,
{$ELSE IFDEF UNIX}
CFU_KDE_CUT_SELECTION,
CFU_GNOME_COPIED_FILES,
{$ENDIF}
CFU_TEXT_PLAIN,
CFU_URI_LIST: TClipboardFormat;
implementation
uses
{$IFDEF MSWINDOWS}
Windows, Win32Proc, ActiveX, uOleDragDrop, fMain;
{$ELSE IFDEF UNIX}
LCLIntf, Clipbrd;
{$ENDIF}
procedure RegisterUserFormats;
begin
{$IF DEFINED(MSWINDOWS)}
CFU_PREFERRED_DROPEFFECT := RegisterClipboardFormat(CFSTR_PREFERRED_DROPEFFECT);
CFU_FILENAME := RegisterClipboardFormat(CFSTR_FILENAME);
CFU_FILENAMEW := RegisterClipboardFormat(CFSTR_FILENAMEW);
CFU_UNIFORM_RESOURCE_LOCATOR := RegisterClipboardFormat(CFSTR_UNIFORM_RESOURCE_LOCATOR);
CFU_UNIFORM_RESOURCE_LOCATORW := RegisterClipboardFormat(CFSTR_UNIFORM_RESOURCE_LOCATORW);
{$ELSEIF DEFINED(UNIX)}
CFU_GNOME_COPIED_FILES := RegisterClipboardFormat(gnomeClipboardMime);
CFU_KDE_CUT_SELECTION := RegisterClipboardFormat(kdeClipboardMime);
{$ENDIF}
CFU_TEXT_PLAIN := RegisterClipboardFormat(textPlainMime);
CFU_URI_LIST := RegisterClipboardFormat(uriListMime);
end;
{ Changes all '%XX' to bytes (XX is a hex number). }
function URIDecode(encodedUri: String): String;
@ -212,6 +254,8 @@ begin
end;
end;
{$IFDEF UNIX}
function GetClipboardFormatAsString(formatId: TClipboardFormat): String;
var
PBuffer: PChar;
@ -261,7 +305,6 @@ var
i: Integer;
hGlobalBuffer: HGLOBAL;
pBuffer: LPVOID;
CF_EFFECT: UINT;
PreferredEffect: DWORD = DROPEFFECT_COPY;
const
@ -270,7 +313,6 @@ const
{$IFDEF UNIX}
var
formatId: Integer;
i: Integer;
s: String;
uriList: String;
@ -285,12 +327,6 @@ begin
{$IFDEF MSWINDOWS}
{ First, try to acquire preferred effect (move, copy) handle. }
CF_EFFECT := RegisterClipboardFormat(PChar(CFSTR_PREFERREDDROPEFFECT));
if CF_EFFECT = 0 then Exit;
if OpenClipboard(frmMain.Handle) = False then Exit;
// Empty clipboard, freeing handles to data inside it.
@ -299,50 +335,53 @@ begin
{ Now, set preferred effect. }
if ClipboardOp = ClipboardCopy then
PreferredEffect := DROPEFFECT_COPY
else if ClipboardOp = ClipboardCut then
PreferredEffect := DROPEFFECT_MOVE;
hGlobalBuffer := GlobalAlloc(GMEM_MOVEABLE, SizeOf(DWORD));
if hGlobalBuffer = 0 then
if CFU_PREFERRED_DROPEFFECT <> 0 then
begin
CloseClipboard;
Exit;
end;
if ClipboardOp = ClipboardCopy then
PreferredEffect := DROPEFFECT_COPY
else if ClipboardOp = ClipboardCut then
PreferredEffect := DROPEFFECT_MOVE;
pBuffer := GlobalLock(hGlobalBuffer);
if pBuffer <> nil then
begin
CopyMemory(pBuffer, PDWORD(@PreferredEffect), SizeOf(DWORD));
GlobalUnlock(hGlobalBuffer);
if SetClipboardData(CF_EFFECT, hGlobalBuffer) = 0 then
hGlobalBuffer := GlobalAlloc(GMEM_MOVEABLE, SizeOf(DWORD));
if hGlobalBuffer = 0 then
begin
// Failed.
CloseClipboard;
Exit;
end;
pBuffer := GlobalLock(hGlobalBuffer);
if pBuffer <> nil then
begin
CopyMemory(pBuffer, PDWORD(@PreferredEffect), SizeOf(DWORD));
GlobalUnlock(hGlobalBuffer);
if SetClipboardData(CFU_PREFERRED_DROPEFFECT, hGlobalBuffer) = 0 then
begin
// Failed.
GlobalFree(hGlobalBuffer);
CloseClipboard;
Exit;
end
// else SetClipboardData succeeded,
// so hGlobalBuffer is now owned by the operating system.
end
else
begin
// Could not lock allocated memory, so free it.
GlobalFree(hGlobalBuffer);
CloseClipboard;
Exit;
end
// else SetClipboardData succeeded,
// so hGlobalBuffer is now owned by the operating system.
end
else
begin
// Could not lock allocated memory, so free it.
GlobalFree(hGlobalBuffer);
CloseClipboard;
Exit;
end;
end;
{ Now, set clipboard data in CF_HDROP format. }
DragDropInfo := TDragDropInfo.Create(DummyPoint, True);
DragDropInfo := TDragDropInfo.Create(DummyPoint, True, PreferredEffect);
for i := 0 to filenames.Count - 1 do
DragDropInfo.Add(filenames[i]);
hGlobalBuffer := DragDropInfo.CreateHDrop;
hGlobalBuffer := DragDropInfo.CreateHDrop(Win32Proc.UnicodeEnabledOS);
if SetClipboardData(CF_HDROP, hGlobalBuffer) = 0 then
GlobalFree(hGlobalBuffer);
@ -375,8 +414,7 @@ begin
Clipboard.Clear;
{ Gnome }
formatId := RegisterClipboardFormat(gnomeClipboardMime);
if formatId <> 0 then
if CFU_GNOME_COPIED_FILES <> 0 then
begin
case ClipboardOp of
ClipboardCopy:
@ -393,13 +431,12 @@ begin
if s <> '' then
begin
s := s + LineEnding + uriList;
Clipboard.AddFormat(formatId, s[1], Length(s));
Clipboard.AddFormat(CFU_GNOME_COPIED_FILES, s[1], Length(s));
end;
end;
{ KDE }
formatId := RegisterClipboardFormat(kdeClipboardMime);
if formatId <> 0 then
if CFU_KDE_CUT_SELECTION <> 0 then
begin
case ClipboardOp of
ClipboardCopy:
@ -414,7 +451,7 @@ begin
end;
if s <> '' then
Clipboard.AddFormat(formatId, s[1], Length(s));
Clipboard.AddFormat(CFU_KDE_CUT_SELECTION, s[1], Length(s));
end;
// Common to all, plain text.
@ -422,9 +459,8 @@ begin
plainList[1], Length(plainList));
// Send also as URI-list.
formatId := RegisterClipboardFormat(uriListMime);
if formatId <> 0 then
Clipboard.AddFormat(formatId, uriList[1], Length(uriList));
if CFU_URI_LIST <> 0 then
Clipboard.AddFormat(CFU_URI_LIST, uriList[1], Length(uriList));
Clipboard.Close;
@ -453,7 +489,6 @@ var
i: Integer;
szFilename: array [0..MAX_PATH] of char;
bWideStrings: boolean;
CF_EFFECT: UINT;
PreferredEffect: DWORD;
{$ELSE IF DEFINED(UNIX)}
var
@ -473,13 +508,9 @@ begin
if OpenClipboard(0) = False then Exit;
{ First, try to acquire preferred effect (move, copy) handle. }
CF_EFFECT := RegisterClipboardFormat(PChar(CFSTR_PREFERREDDROPEFFECT));
if CF_EFFECT <> 0 then
if CFU_PREFERRED_DROPEFFECT <> 0 then
begin
hGlobalBuffer := GetClipboardData(CF_EFFECT);
hGlobalBuffer := GetClipboardData(CFU_PREFERRED_DROPEFFECT);
if hGlobalBuffer <> 0 then
begin
pBuffer := GlobalLock(hGlobalBuffer);
@ -515,7 +546,7 @@ begin
if bWideStrings then
filenames.Add(UTF8Encode(szFileName))
else
filenames.Add(szFilename);
filenames.Add(AnsiToUtf8(szFilename));
end;
@ -631,5 +662,10 @@ begin
{$ENDIF}
end;
initialization
RegisterUserFormats;
end.

View file

@ -22,11 +22,6 @@ uses
Windows, ActiveX, Classes, Controls, uDragDropEx;
type
{ TFormatList -- ìàññèâ çàïèñåé TFormatEtc }
PFormatList = ^TFormatList;
TFormatList = array[0..1] of TFormatEtc;
{ IEnumFormatEtc }
@ -34,15 +29,11 @@ type
private
FFormatList: PFormatList;
FFormatCount: Integer;
FIndex: Integer;
public
constructor Create(FormatList: PFormatList; FormatCount, Index: Integer);
constructor Create(Index: Integer = 0);
function Next(celt: LongWord; out elt: FormatEtc;
pceltFetched: pULong): HResult; stdcall;
@ -67,15 +58,26 @@ type
FFileList: TStringList;
FPreferredWinDropEffect: DWORD;
function CreateFileNames(bUnicode: Boolean): HGlobal;
function CreateURIs(bUnicode: Boolean): HGlobal;
function CreatePreferredDropEffect(WinDropEffect: DWORD): HGlobal;
function MakeHGlobal(ptr: Pointer; Size: LongWord): HGlobal;
public
constructor Create(ADropPoint: TPoint; AInClient: boolean);
constructor Create(ADropPoint: TPoint; AInClient: boolean;
PreferredWinDropEffect: DWORD);
destructor Destroy; override;
procedure Add(const s: string);
function CreateHDrop: HGlobal;
function CreateHDrop(bUnicode: Boolean): HGlobal;
function MakeDataInFormat(const formatEtc: TFormatEtc): HGlobal;
property InClientArea: boolean Read FInClientArea;
@ -136,6 +138,7 @@ type
end;
{ THDropDataObject - îáúåêò äàííûõ ñ
èíôîðìàöèåé î ïåðåòàñêèâàåìûõ ôàéëàõ }
@ -148,7 +151,8 @@ type
public
constructor Create(ADropPoint: TPoint; AInClient: boolean);
constructor Create(ADropPoint: TPoint; AInClient: boolean;
PreferredWinDropEffect: DWORD);
destructor Destroy; override;
@ -225,20 +229,72 @@ type
implementation
uses
SysUtils, ShellAPI, ShlObj, LCLIntf;
SysUtils, ShellAPI, ShlObj, LCLIntf, Win32Proc, uClipboard;
var
// Supported formats by the source.
DataFormats: TList = nil; // of TFormatEtc
procedure InitDataFormats;
procedure AddFormat(FormatId: Word);
var
FormatEtc: PFormatEtc;
begin
if FormatId > 0 then
begin
New(FormatEtc);
if Assigned(FormatEtc) then
begin
DataFormats.Add(FormatEtc);
with FormatEtc^ do
begin
CfFormat := FormatId;
Ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := -1;
tymed := TYMED_HGLOBAL;
end;
end;
end;
end;
begin
DataFormats := TList.Create;
AddFormat(CF_HDROP);
AddFormat(CFU_PREFERRED_DROPEFFECT);
AddFormat(CFU_FILENAME);
AddFormat(CFU_FILENAMEW);
AddFormat(CFU_UNIFORM_RESOURCE_LOCATOR);
AddFormat(CFU_UNIFORM_RESOURCE_LOCATORW);
end;
procedure DestroyDataFormats;
var
i : Integer;
begin
if Assigned(DataFormats) then
begin
for i := 0 to DataFormats.Count - 1 do
if Assigned(DataFormats.Items[i]) then
Dispose(PFormatEtc(DataFormats.Items[i]));
FreeAndNil(DataFormats);
end;
end;
{ TEnumFormatEtc }
constructor TEnumFormatEtc.Create(FormatList: PFormatList; FormatCount, Index: Integer);
constructor TEnumFormatEtc.Create(Index: Integer);
begin
inherited Create;
FFormatList := FormatList;
FFormatCount := FormatCount;
FIndex := Index;
end;
@ -264,19 +320,24 @@ var
i: Integer;
eltout: TFormatList absolute elt;
eltout: PFormatEtc;
begin
// Support returning only 1 format at a time.
if celt > 1 then celt := 1;
eltout := @elt;
i := 0;
while (i < celt) and (FIndex < FFormatCount) do
while (i < celt) and (FIndex < DataFormats.Count) do
begin
eltout[i] := FFormatList[FIndex];
(eltout + i)^ := PFormatEtc(DataFormats.Items[FIndex])^;
Inc(FIndex);
@ -318,7 +379,7 @@ function TEnumFormatEtc.Skip(celt: LongWord): HResult;
begin
if (celt <= FFormatCount - FIndex) then
if (celt <= DataFormats.Count - FIndex) then
begin
@ -331,7 +392,7 @@ begin
begin
FIndex := FFormatCount;
FIndex := DataFormats.Count;
Result := S_FALSE;
@ -359,7 +420,7 @@ function TEnumFormatEtc.Clone(out enum: IEnumFormatEtc): HResult;
begin
enum := TEnumFormatEtc.Create(FFormatList, FFormatCount, FIndex);
enum := TEnumFormatEtc.Create(FIndex);
Result := S_OK;
@ -368,7 +429,8 @@ end;
{ TDragDropInfo }
constructor TDragDropInfo.Create(ADropPoint: TPoint; AInClient: boolean);
constructor TDragDropInfo.Create(ADropPoint: TPoint; AInClient: boolean;
PreferredWinDropEffect: DWORD);
begin
@ -380,6 +442,8 @@ begin
FInClientArea := AInClient;
FPreferredWinDropEffect := PreferredWinDropEffect;
end;
destructor TDragDropInfo.Destroy;
@ -400,7 +464,180 @@ begin
end;
function TDragDropInfo.CreateHDrop: HGlobal;
function TDragDropInfo.MakeDataInFormat(const formatEtc: TFormatEtc): HGlobal;
begin
Result := 0;
if (formatEtc.tymed = DWORD(-1)) or // Transport medium not specified.
(Boolean(formatEtc.tymed and TYMED_HGLOBAL)) // Support only HGLOBAL medium.
then
begin
if formatEtc.CfFormat = CF_HDROP then
begin
Result := CreateHDrop(Win32Proc.UnicodeEnabledOS)
end
else if formatEtc.CfFormat = CFU_PREFERRED_DROPEFFECT then
begin
Result := CreatePreferredDropEffect(FPreferredWinDropEffect);
end
else if (formatEtc.CfFormat = CFU_FILENAME) then
begin
Result := CreateFileNames(False);
end
else if (formatEtc.CfFormat = CFU_FILENAMEW) then
begin
Result := CreateFileNames(True);
end
// URIs disabled for now. It may be enough to just report that URL format
// is supported, but not actually format data this way.
{else if (formatEtc.CfFormat = CFU_UNIFORM_RESOURCE_LOCATOR) then
begin
Result := CreateURIs(False);
end
else if (formatEtc.CfFormat = CFU_UNIFORM_RESOURCE_LOCATORW) then
begin
Result := CreateURIs(True);
end}
;
end;
end;
function TDragDropInfo.CreateFileNames(bUnicode: Boolean): HGlobal;
var
FileList: AnsiString;
wsFileList: WideString;
begin
if Files.Count = 0 then Exit;
if bUnicode then
begin
wsFileList := UTF8Decode(Self.Files[0]) + #0;
Result := MakeHGlobal(PWideChar(wsFileList),
Length(wsFileList) * SizeOf(WideChar));
end
else
begin
FileList := FileList + Utf8ToAnsi(Self.Files[0]) + #0;
Result := MakeHGlobal(PAnsiChar(FileList),
Length(FileList) * SizeOf(AnsiChar));
end;
end;
function TDragDropInfo.CreateURIs(bUnicode: Boolean): HGlobal;
var
UriList: AnsiString;
wsUriList: WideString;
I: Integer;
begin
wsUriList := '';
for I := 0 to Self.Files.Count - 1 do
begin
if I > 0 then
wsUriList := wsUriList + LineEnding;
wsUriList := wsUriList
+ fileScheme + '//' { don't put hostname }
+ URIEncode(UTF8Decode(
StringReplace(Files[I], '\', '/', [rfReplaceAll] )));
end;
wsUriList := wsUriList + #0;
if bUnicode then
Result := MakeHGlobal(PWideChar(wsUriList),
Length(wsUriList) * SizeOf(WideChar))
else
begin
// Wide to Ansi
UriList := Utf8ToAnsi(UTF8Encode(wsUriList));
Result := MakeHGlobal(PAnsiChar(UriList),
Length(UriList) * SizeOf(AnsiChar));
end;
end;
function TDragDropInfo.CreatePreferredDropEffect(WinDropEffect: DWORD) : HGlobal;
begin
Result := MakeHGlobal(@WinDropEffect, SizeOf(WinDropEffect));
end;
function TDragDropInfo.MakeHGlobal(ptr: Pointer; Size: LongWord): HGlobal;
var
DataPointer : Pointer;
DataHandle : HGLOBAL;
begin
Result := 0;
if Assigned(ptr) then
begin
DataHandle := GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT, Size);
if (DataHandle <> 0) then
begin
DataPointer := GlobalLock(DataHandle);
if Assigned(DataPointer) then
begin
CopyMemory(DataPointer, ptr, Size);
GlobalUnlock(DataHandle);
Result := DataHandle;
end
else
begin
GlobalFree(DataHandle);
end;
end;
end;
end;
function TDragDropInfo.CreateHDrop(bUnicode: Boolean): HGlobal;
var
@ -412,6 +649,8 @@ var
DropFiles: PDropFiles;
FileList: AnsiString;
wsFileList: WideString;
begin
@ -432,36 +671,44 @@ begin
}
{
Bring the filenames in a form,
separated by #0 and ending with a double #0#0
}
for I := 0 to Self.Files.Count - 1 do
if bUnicode then
begin
begin
for I := 0 to Self.Files.Count - 1 do
wsFileList := wsFileList + UTF8Decode(Self.Files[I]) + #0;
wsFileList:= wsFileList + UTF8Decode(Self.Files[I]) + #0;
wsFileList := wsFileList + #0;
end;
{ Îïðåäåëÿåì íåîáõîäèìûé ðàçìåð ñòðóêòóðû }
wsFileList:= wsFileList + #0;
RequiredSize := SizeOf(TDropFiles) + Length(wsFileList) * SizeOf(WChar);
{ Îïðåäåëÿåì íåîáõîäèìûé ðàçìåð ñòðóêòóðû }
end
else
begin
RequiredSize := SizeOf(TDropFiles) + Length(wsFileList) * 2;
for I := 0 to Self.Files.Count - 1 do
FileList := FileList + Utf8ToAnsi(Self.Files[I]) + #0;
FileList := FileList + #0;
{ Îïðåäåëÿåì íåîáõîäèìûé ðàçìåð ñòðóêòóðû }
RequiredSize := SizeOf(TDropFiles) + Length(FileList) * SizeOf(AnsiChar);
end;
hGlobalDropInfo := GlobalAlloc((GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT),
RequiredSize);
hGlobalDropInfo := GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT, RequiredSize);
if (hGlobalDropInfo <> 0) then
begin
{ Çàáëîêèðóåì îáëàñòü ïàìÿòè, ÷òîáû ê íåé
ìîæíî áûëî îáðàòèòüñÿ
@ -471,7 +718,6 @@ begin
DropFiles := GlobalLock(hGlobalDropInfo);
{ Çàïîëíèì ïîëÿ ñòðóêòóðû DropFiles }
{
@ -490,9 +736,7 @@ begin
DropFiles.fNC := Self.InClientArea;
DropFiles.fWide := True;
DropFiles.fWide := bUnicode;
{
@ -506,9 +750,14 @@ begin
}
{ The pointer should be aligned nicely,
because the TDropFiles record is not packed. }
DropFiles := Pointer(DropFiles) + DropFiles.pFiles;
CopyMemory(DropFiles, PWideChar(wsFileList), Length(wsFileList) * 2);
if bUnicode then
CopyMemory(DropFiles, PWideChar(wsFileList), Length(wsFileList) * SizeOf(WChar))
else
CopyMemory(DropFiles, PAnsiChar(FileList), Length(FileList) * SizeOf(AnsiChar));
@ -619,7 +868,8 @@ var
DropEffect: TDropEffect;
begin
dwEffect := GetEffectByKeyState(grfKeyState);
// dwEffect parameter states which effects are allowed by the source.
dwEffect := dwEffect and GetEffectByKeyState(grfKeyState);
if Assigned(FDragDropTarget.GetDragEnterEvent) then
begin
@ -645,7 +895,8 @@ var
DropEffect: TDropEffect;
begin
dwEffect := GetEffectByKeyState(grfKeyState);
// dwEffect parameter states which effects are allowed by the source.
dwEffect := dwEffect and GetEffectByKeyState(grfKeyState);
if Assigned(FDragDropTarget.GetDragOverEvent) then
begin
@ -763,76 +1014,91 @@ begin
begin
{ Ïîëó÷àåì êîëè÷åñòâî ôàéëîâ è
case Medium.Tymed of
ïðî÷èå ñâåäåíèÿ }
TYMED_HGLOBAL:
NumFiles := DragQueryFile(Medium.hGlobal, $FFFFFFFF, nil, 0);
begin
InClient := DragQueryPoint(Medium.hGlobal, @DropPoint);
{ Ïîëó÷àåì êîëè÷åñòâî ôàéëîâ è
if (DropPoint.X = 0) and (DropPoint.Y = 0) then
DropPoint := pt;
ïðî÷èå ñâåäåíèÿ }
bWideStrings := DragQueryWide( Medium.hGlobal );
NumFiles := DragQueryFile(Medium.hGlobal, $FFFFFFFF, nil, 0);
InClient := DragQueryPoint(Medium.hGlobal, @DropPoint);
if (DropPoint.X = 0) and (DropPoint.Y = 0) then
DropPoint := pt;
bWideStrings := DragQueryWide( Medium.hGlobal );
{ Ñîçäàåì îáúåêò TDragDropInfo }
{ Ñîçäàåì îáúåêò TDragDropInfo }
DropInfo := TDragDropInfo.Create(DropPoint, InClient);
DropInfo := TDragDropInfo.Create(DropPoint, InClient, dwEffect);
{ Çàíîñèì âñå ôàéëû â ñïèñîê }
{ Çàíîñèì âñå ôàéëû â ñïèñîê }
for i := 0 to NumFiles - 1 do
for i := 0 to NumFiles - 1 do
begin
begin
DragQueryFile(Medium.hGlobal, i,
DragQueryFile(Medium.hGlobal, i,
szFilename,
szFilename,
sizeof(szFilename));
sizeof(szFilename));
// If Wide strings, then do Wide to UTF-8 transform
if( bWideStrings ) then
DropInfo.Add( UTF8Encode( szFileName ) )
else
DropInfo.Add(szFilename);
// If Wide strings, then do Wide to UTF-8 transform
if( bWideStrings ) then
DropInfo.Add( UTF8Encode( szFileName ) )
else
DropInfo.Add( AnsiToUtf8( szFilename ) );
end;
end;
{ Åñëè óêàçàí îáðàáîò÷èê, âûçûâàåì åãî }
{ Åñëè óêàçàí îáðàáîò÷èê, âûçûâàåì åãî }
if (Assigned(FDragDropTarget.GetDropEvent)) then
if (Assigned(FDragDropTarget.GetDropEvent)) then
begin
begin
// Set default effect by examining keyboard keys.
dwEffect := GetEffectByKeyState(grfKeyState);
// Set default effect by examining keyboard keys, taking into
// consideration effects allowed by the source (dwEffect parameter).
dwEffect := dwEffect and GetEffectByKeyState(grfKeyState);
DropEffect := WinEffectToDropEffect(dwEffect);
DropEffect := WinEffectToDropEffect(dwEffect);
if FDragDropTarget.GetDropEvent()(DropInfo.Files, DropEffect, DropInfo.DropPoint) = False then
if FDragDropTarget.GetDropEvent()(DropInfo.Files, DropEffect, DropInfo.DropPoint) = False then
;
;
dwEffect := DropEffectToWinEffect(DropEffect);
dwEffect := DropEffectToWinEffect(DropEffect);
end;
end;
DropInfo.Free;
end; // TYMED_HGLOBAL
DropInfo.Free;
end; // case
{ Release memory allocated on DoDragDrop }
DragFinish( Medium.hGlobal );
if (Medium.PUnkForRelease = nil) then
ReleaseStgMedium(@Medium);
// Drop target must release the medium allocated by GetData.
// This does the same as DragFinish(Medium.hGlobal) in this case,
// but can support other media.
ReleaseStgMedium(@Medium)
else
// Drop source is responsible for releasing medium via this object.
IUnknown(Medium.PUnkForRelease)._Release;
end;
@ -854,6 +1120,7 @@ begin
end;
{
QueryContinueDrag îïðåäåëÿåò íåîáõîäèìûå äåéñòâèÿ.
@ -931,7 +1198,7 @@ function TFileDropSource.GiveFeedback(dwEffect: longint): HResult;
begin
case dwEffect of
case LongWord(dwEffect) of
DROPEFFECT_NONE,
@ -941,9 +1208,9 @@ begin
DROPEFFECT_LINK,
DROPEFFECT_SCROLL: Result :=
DROPEFFECT_SCROLL:
DRAGDROP_S_USEDEFAULTCURSORS;
Result := DRAGDROP_S_USEDEFAULTCURSORS;
else
@ -956,7 +1223,8 @@ end;
{ THDropDataObject }
constructor THDropDataObject.Create(ADropPoint: TPoint; AInClient: boolean);
constructor THDropDataObject.Create(ADropPoint: TPoint; AInClient: boolean;
PreferredWinDropEffect: DWORD);
begin
@ -964,7 +1232,7 @@ begin
_AddRef;
FDropInfo := TDragDropInfo.Create(ADropPoint, AInClient);
FDropInfo := TDragDropInfo.Create(ADropPoint, AInClient, PreferredWinDropEffect);
end;
@ -1019,15 +1287,20 @@ begin
begin
medium.tymed := TYMED_HGLOBAL;
{ Create data in specified format. }
{ The hGlobal will be released by the caller of GetData. }
{ Çà îñâîáîæäåíèå îòâå÷àåò
medium.hGlobal := FDropInfo.MakeDataInFormat(formatetcIn);
âûçûâàþùàÿ ñòîðîíà! }
if medium.hGlobal <> 0 then
medium.hGlobal := FDropInfo.CreateHDrop;
begin
Result := S_OK;
medium.tymed := TYMED_HGLOBAL;
Result := S_OK;
end;
end;
@ -1048,17 +1321,57 @@ end;
function THDropDataObject.QueryGetData(const formatetc: TFormatEtc): HResult;
begin
var
i:Integer;
Result := DV_E_FORMATETC;
begin
with formatetc do
if dwAspect = DVASPECT_CONTENT then
if (cfFormat = CF_HDROP) and (tymed = TYMED_HGLOBAL) then
begin
Result := S_OK;
Result := DV_E_FORMATETC; // begin with 'format not supported'
// See if the queried format is supported.
for i := 0 to DataFormats.Count - 1 do
begin
if Assigned(DataFormats[i]) then
begin
if cfFormat = PFormatEtc(DataFormats[i])^.CfFormat then
begin
// Format found, see if transport medium is supported.
if (tymed = DWORD(-1)) or
(Boolean(tymed and PFormatEtc(DataFormats[i])^.tymed)) then
begin
Result := S_OK;
end
else
Result := DV_E_TYMED; // transport medium not supported
Exit; // exit if format found (regardless of transport medium)
end
end
end
end
else
Result := DV_E_DVASPECT; // aspect not supported
end;
@ -1088,30 +1401,6 @@ end;
function THDropDataObject.EnumFormatEtc(dwDirection: LongWord;
out enumFormatEtc: IEnumFormatEtc): HResult;
const
DataFormats: array [0..0] of TFormatEtc =
(
(
cfFormat: CF_HDROP;
ptd: nil;
dwAspect: DVASPECT_CONTENT;
lindex: -1;
tymed: TYMED_HGLOBAL;
)
);
DataFormatCount = 1;
begin
{ Ïîääåðæèâàåòñÿ òîëüêî Get. Çàäàòü
@ -1122,7 +1411,7 @@ begin
begin
enumFormatEtc := TEnumFormatEtc.Create(@DataFormats, DataFormatCount, 0);
enumFormatEtc := TEnumFormatEtc.Create;
Result := S_OK;
@ -1248,7 +1537,8 @@ begin
DropSource:= TFileDropSource.Create;
// and data object
DropData:= THDropDataObject.Create(ScreenStartPoint, True);
DropData:= THDropDataObject.Create(ScreenStartPoint, False,
DROPEFFECT_COPY { default effect } );
for I:= 0 to FileNamesList.Count - 1 do
DropData.Add (FileNamesList[i]);
@ -1296,13 +1586,9 @@ begin
GetDragEndEvent()()
end;
{ ОÑ<EFBFBD>вобождаем иÑ<EFBFBD>пользованнÑе реÑ<EFBFBD>урÑ<EFBFBD>Ñ
поÑ<EFBFBD>ле завершениÑ<EFBFBD> работы }
{ DropSource.Free;
DropData.Free; }
// Release created objects.
DropSource._Release;
DropData._Release;
end;
@ -1318,8 +1604,11 @@ end;
destructor TDragDropTargetWindows.Destroy;
begin
inherited Destroy;
if FDragDropTarget <> nil then
FreeAndNil(FDragDropTarget);
if Assigned(FDragDropTarget) then
begin
FDragDropTarget._Release;
FDragDropTarget := nil;
end;
end;
function TDragDropTargetWindows.RegisterEvents(
@ -1345,18 +1634,23 @@ procedure TDragDropTargetWindows.UnregisterEvents;
begin
inherited;
if Assigned(FDragDropTarget) then
FreeAndNil(FDragDropTarget); // Freeing will unregister events
begin
FDragDropTarget._Release; // Freeing will unregister events
FDragDropTarget := nil;
end;
end;
initialization
OleInitialize(nil);
InitDataFormats;
finalization
OleUninitialize;
DestroyDataFormats;
end.