mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-28 10:02:14 +00:00
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:
parent
e5e47437b7
commit
a8ee99d0fa
2 changed files with 533 additions and 203 deletions
182
uClipboard.pas
182
uClipboard.pas
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
560
uOleDragDrop.pas
560
uOleDragDrop.pas
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue