Componentes.Terceros.Mustan.../official/1.7.0/Common Library/Source/MPDataObject.pas
david 778b05bf9f Importación inicial
- Mustangpeak Common Library - 1.7.0
  - EasyListview - 1.7.0

git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.Mustangpeak@2 60b41242-d4b9-2247-b156-4ccd40706241
2007-09-11 08:33:06 +00:00

2355 lines
72 KiB
ObjectPascal

unit MPDataObject;
// Version 1.7.0
//
// The contents of this file are subject to the Mozilla Public License
// Version 1.1 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
//
// Alternatively, you may redistribute this library, use and/or modify it under the terms of the
// GNU Lesser General Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any later version.
// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/.
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
// specific language governing rights and limitations under the License.
//
// The initial developer of this code is Jim Kueneman <jimdk@mindspring.com>
// Special thanks to the following in no particular order for their help/support/code
// Danijel Malik, Robert Lee, Werner Lehmann, Alexey Torgashin, Milan Vandrovec
//
//----------------------------------------------------------------------------
interface
{.$DEFINE GX_DEBUG}
{$I Compilers.inc}
{$I Options.inc}
{$I ..\Include\Debug.inc}
{$I ..\Include\Addins.inc}
uses
Windows,
Messages,
SysUtils,
Classes,
Graphics,
Controls,
Forms,
ActiveX,
ShlObj,
ShellAPI,
{$IFDEF GX_DEBUG}
DbugIntf,
{$ENDIF}
MPShellTypes,
MPCommonUtilities,
MPCommonObjects,
{$IFDEF TNTSUPPORT}
TntStdCtrls,
TntClasses,
TntWideStrings,
{$ENDIF}
AxCtrls;
const
// Standard Shell Formats
CFSTR_LOGICALPERFORMEDDROPEFFECT = 'Logical Performed DropEffect';
CFSTR_PREFERREDDROPEFFECT = 'Preferred DropEffect';
CFSTR_PERFORMEDDROPEFFECT = 'Performed DropEffect';
CFSTR_PASTESUCCEEDED = 'Paste Succeeded';
CFSTR_INDRAGLOOP = 'InShellDragLoop';
CFSTR_SHELLIDLISTOFFSET = 'Shell Object Offsets';
SIZE_SHELLDRAGLOOPDATA = 4;
type
PPerformedDropEffect = ^TPerformedDropEffect;
TPerformedDropEffect = (
effectNone, // No Operation (DROPEFFECT_NONE)
effectCopy, // Operation was a copy (DROPEFFECT_COPY)
effectMove, // Operation was a move (DROPEFFECT_MOVE)
effectLink // Operation was a link (DROPEFFECT_LINK)
);
type
TFormatEtcArray = array of TFormatEtc;
TDataObjectInfo = record
FormatEtc: TFormatEtc;
StgMedium: TStgMedium;
OwnedByDataObject: Boolean
end;
TDataObjectInfoArray = array of TDataObjectInfo;
type
// This is just a WAG for the size. I can't imagine it ever needing this
// many formats
TeltArray = array[0..255] of TFormatEtc;
{$IFNDEF COMPILER_6_UP}
PCardinal = ^Cardinal;
{$ENDIF}
//------------------------------------------------------------------------------
// TCommonEnumFormatEtc :
// Implements the IEnumFormatEtc interface for the IDataObject
// implementation. This interface is called by a potential droptarget to see it
// the IDataObject contains data that the target knows how to handle and would
// like a shot at accepting it.
//-------------------------------------------------------------------------------
TCommonEnumFormatEtc = class(TInterfacedObject, IEnumFormatEtc)
private
FInternalIndex: integer;
FFormats: TFormatEtcArray;
protected
{ IEnumFormatEtc }
function Next(celt: Longint; out elt; pceltFetched: PLongint): HResult; stdcall;
function Skip(celt: Longint): HResult; stdcall;
function Reset: HResult; stdcall;
function Clone(out Enum: IEnumFormatEtc): HResult; stdcall;
property InternalIndex: integer read FInternalIndex write FInternalIndex;
public
constructor Create;
destructor Destroy; override;
procedure SetFormatLength(Size: Integer);
property Formats: TFormatEtcArray read FFormats write FFormats;
end;
//-------------------------------------------------------------------------------}
// TCommonDataObject : }
// Implements the IDataObject interface. This interface is called by a }
// potential droptarget to see it the IDataObject contains data that the target }
// knows how to handle and would like a shot at accepting it. }
//-------------------------------------------------------------------------------}
ICommonDataObject = interface(IDataObject)
['{F8B3EE47-C6C1-4FE3-9D94-757AA35DC038}']
function AssignDragImage(Image: TBitmap; HotSpot: TPoint; TransparentColor: TColor): Boolean;
function SaveGlobalBlock(Format: TClipFormat; MemoryBlock: Pointer; MemoryBlockSize: integer): Boolean;
function LoadGlobalBlock(Format: TClipFormat; var MemoryBlock: Pointer): Boolean;
end;
TGetDataEvent = procedure(Sender: TObject; const FormatEtcIn: TFormatEtc; var Medium: TStgMedium; var Handled: Boolean) of object;
TQueryGetDataEvent = procedure(Sender: TObject; const FormatEtcIn: TFormatEtc; var FormatAvailable: Boolean; var Handled: Boolean) of object;
TCommonDataObject = class(TObject, IUnknown, IDataObject, ICommonDataObject, ICommonExtractObj)
private
FRefCount: Integer;
protected
FAdviseHolder: IDataAdviseHolder;
FFormats: TDataObjectInfoArray;
FOnGetData: TGetDataEvent;
FOnQueryGetData: TQueryGetDataEvent; // Reference to an OLE supplied implementation for advising.
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
function CanonicalIUnknown(TestUnknown: IUnknown): IUnknown;
function DAdvise(const formatetc: TFormatEtc; advf: Longint; const advSink: IAdviseSink; out dwConnection: Longint): HResult; virtual; stdcall;
function DUnadvise(dwConnection: Longint): HResult; virtual; stdcall;
function EnumDAdvise(out enumAdvise: IEnumStatData): HResult;virtual; stdcall;
function EnumFormatEtc(dwDirection: Longint; out enumFormatEtc: IEnumFormatEtc): HResult;virtual; stdcall;
function EqualFormatEtc(FormatEtc1, FormatEtc2: TFormatEtc): Boolean;
function FindFormatEtc(TestFormatEtc: TFormatEtc): integer;
function GetCanonicalFormatEtc(const formatetc: TFormatEtc; out formatetcOut: TFormatEtc): HResult;virtual; stdcall;
function GetData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium): HResult;virtual; stdcall;
function GetDataHere(const formatetc: TFormatEtc; out medium: TStgMedium): HResult;virtual; stdcall;
function HGlobalClone(HGlobal: THandle): THandle;
function QueryGetData(const formatetc: TFormatEtc): HResult;virtual; stdcall;
function SetData(const formatetc: TFormatEtc; var medium: TStgMedium; fRelease: BOOL): HResult;virtual; stdcall;
procedure DoGetCustomFormats(var Formats: TFormatEtcArray); virtual;
procedure DoOnGetData(const FormatEtcIn: TFormatEtc; var Medium: TStgMedium; var Handled: Boolean); virtual;
procedure DoOnQueryGetData(const FormatEtcIn: TFormatEtc; var FormatAvailable: Boolean; var Handled: Boolean); virtual;
function RetrieveOwnedStgMedium(Format: TFormatEtc; var StgMedium: TStgMedium): HRESULT;
function StgMediumIncRef(const InStgMedium: TStgMedium; var OutStgMedium: TStgMedium; CopyInMedium: Boolean): HRESULT;
function GetObj: TObject;
property AdviseHolder: IDataAdviseHolder read FAdviseHolder;
property Formats: TDataObjectInfoArray read FFormats write FFormats;
property Obj: TObject read GetObj;
property RefCount: Integer read FRefCount;
public
constructor Create;
destructor Destroy; override;
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
class function NewInstance: TObject; override;
function AssignDragImage(Image: TBitmap; HotSpot: TPoint; TransparentColor: TColor): Boolean;
function GetUserData(Format: TFormatEtc; var StgMedium: TStgMedium): Boolean; virtual;
function LoadGlobalBlock(Format: TClipFormat; var MemoryBlock: Pointer): Boolean;
function SaveGlobalBlock(Format: TClipFormat; MemoryBlock: Pointer; MemoryBlockSize: integer): Boolean;
property OnGetData: TGetDataEvent read FOnGetData write FOnGetData;
property OnQueryGetData: TQueryGetDataEvent read FOnQueryGetData write FOnQueryGetData;
end;
TCommonClipboardFormat = class
public
function GetFormatEtc: TFormatEtc; virtual;
function LoadFromClipboard: Boolean; virtual;
function LoadFromDataObject(DataObject: IDataObject): Boolean; virtual; abstract;
function SaveToClipboard: Boolean; virtual;
function SaveToDataObject(DataObject: IDataObject): Boolean; virtual; abstract;
end;
TCommonStreamClipFormat = class(TCommonClipboardFormat)
public
function GetFormatEtc: TFormatEtc; override;
function LoadFromClipboard: Boolean; override;
function LoadFromDataObject(DataObject: IDataObject; CoolStream: TCommonStream): Boolean; reintroduce;
function SaveToClipboard: Boolean; override;
function SaveToDataObject(DataObject: IDataObject; CoolStream: TCommonStream): Boolean; reintroduce;
end;
// Simpifies dealing with the CFSTR_FILEGROUPDESCRIPTOR format
TDescriptorAArray = array of TFileDescriptorA;
TDescriptorWArray = array of TFileDescriptorW;
TFileGroupDescriptorA = class(TCommonClipboardFormat)
private
FStream: TStream;
function GetDescriptorCount: Integer;
function GetFileDescriptorA(Index: Integer): TFileDescriptorA;
procedure SetFileDescriptor(Index: Integer;
const Value: TFileDescriptorA);
protected
FFileDescriptors: TDescriptorAArray;
property Stream: TStream read FStream write FStream;
public
procedure AddFileDescriptor(FileDescriptor: TFileDescriptorA);
procedure DeleteFileDescriptor(Index: integer);
function GetFormatEtc: TFormatEtc; override;
function FillDescriptor(FileName: string): TFileDescriptorA;
function GetFileStream(const DataObject: IDataObject; FileIndex: Integer): TStream;
procedure LoadFileGroupDestriptor(FileGroupDiscriptor: PFileGroupDescriptorA);
function LoadFromClipboard: Boolean; override;
function LoadFromDataObject(DataObject: IDataObject): Boolean; override;
function SaveToClipboard: Boolean; override;
function SaveToDataObject(DataObject: IDataObject): Boolean; override;
property DescriptorCount: Integer read GetDescriptorCount;
property FileDescriptor[Index: Integer]: TFileDescriptorA read GetFileDescriptorA write SetFileDescriptor;
end;
TFileGroupDescriptorW = class(TCommonClipboardFormat)
private
FStream: TStream;
function GetDescriptorCount: Integer;
function GetFileDescriptorW(Index: Integer): TFileDescriptorW;
procedure SetFileDescriptor(Index: Integer;
const Value: TFileDescriptorW);
protected
FFileDescriptors: TDescriptorWArray;
property Stream: TStream read FStream write FStream;
public
procedure AddFileDescriptor(FileDescriptor: TFileDescriptorW);
procedure DeleteFileDescriptor(Index: integer);
function FillDescriptor(FileName: WideString): TFileDescriptorW;
function GetFileStream(const DataObject: IDataObject; FileIndex: Integer): TStream;
function GetFormatEtc: TFormatEtc; override;
procedure LoadFileGroupDestriptor(FileGroupDiscriptor: PFileGroupDescriptorW);
function LoadFromClipboard: Boolean; override;
function LoadFromDataObject(DataObject: IDataObject): Boolean; override;
function SaveToClipboard: Boolean; override;
function SaveToDataObject(DataObject: IDataObject): Boolean; override;
property DescriptorCount: Integer read GetDescriptorCount;
property FileDescriptor[Index: Integer]: TFileDescriptorW read GetFileDescriptorW write SetFileDescriptor;
end;
// Simpifies dealing with the CF_HDROP format
TCommonHDrop = class(TCommonClipboardFormat)
private
procedure SetDropFiles(const Value: PDropFiles);
function GetHDropStruct: THandle;
protected
FDropFiles: PDropFiles;
FStructureSize: integer;
FFileCount: integer;
procedure AllocStructure(Size: integer);
function CalculateDropFileStructureSizeA(Value: PDropFiles): integer;
function CalculateDropFileStructureSizeW(Value: PDropFiles): integer;
function FileCountA: Integer;
function FileCountW: Integer;
function FileNameA(Index: integer): string;
function FileNameW(Index: integer): WideString;
procedure FreeStructure; // Frees memory allocated
public
destructor Destroy; override;
function AssignFromClipboard: Boolean;
function LoadFromClipboard: Boolean; override;
function LoadFromDataObject(DataObject: IDataObject): Boolean; override;
function FileCount: integer;
function FileName(Index: integer): WideString;
function GetFormatEtc: TFormatEtc; override;
procedure AssignFilesA(FileList: TStringList);
{$IFDEF TNTSUPPORT}
procedure AssignFilesW(FileList: TWideStrings);
procedure FileNamesW(FileList: TWideStrings);
{$ENDIF}
procedure FileNamesA(FileList: TStrings);
property HDropStruct: THandle read GetHDropStruct;
function SaveToClipboard: Boolean; override;
function SaveToDataObject(DataObject: IDataObject): Boolean; override;
property StructureSize: integer read FStructureSize;
property DropFiles: PDropFiles read FDropFiles write SetDropFiles;
end;
// Simpifies dealing with the CFSTR_SHELLIDLIST format
type
TCommonShellIDList = class(TCommonClipboardFormat)
private
FCIDA: PIDA;
function GetCIDASize: integer;
function InternalChildPIDL(Index: integer): PItemIDList;
function InternalParentPIDL: PItemIDList;
procedure SetCIDA(const Value: PIDA);
public
function AbsolutePIDL(Index: integer): PItemIDList;
procedure AbsolutePIDLs(APIDLList: TCommonPIDLList);
procedure AssignPIDLs(APIDLList: TCommonPIDLList);
destructor Destroy; override;
function GetFormatEtc: TFormatEtc; override;
function LoadFromClipboard: Boolean; override;
function LoadFromDataObject(DataObject: IDataObject): Boolean; override;
function ParentPIDL: PItemIDList;
function PIDLCount: integer;
function RelativePIDL(Index: integer): PItemIDList;
procedure RelativePIDLs(APIDLList: TCommonPIDLList);
function SaveToClipboard: Boolean; override;
function SaveToDataObject(DataObject: IDataObject): Boolean; override;
property CIDA: PIDA read FCIDA write SetCIDA;
property CIDASize: integer read GetCIDASize;
end;
// Simpilies dealing with the CFSTR_LOGICALPERFORMEDDROPEFFECT format
TCommonLogicalPerformedDropEffect = class(TCommonClipboardFormat)
private
FAction: TPerformedDropEffect;
public
function GetFormatEtc: TFormatEtc; override;
function LoadFromDataObject(DataObject: IDataObject): Boolean; override;
function SaveToDataObject(DataObject: IDataObject): Boolean; override;
property Action: TPerformedDropEffect read FAction write FAction;
end;
// Simpilies dealing with the CFSTR_PerferredDropEffect format
TCommonPreferredDropEffect = class(TCommonLogicalPerformedDropEffect)
public
function GetFormatEtc: TFormatEtc; override;
end;
TCommonInShellDragLoop = class(TCommonClipboardFormat)
private
FData: Cardinal;
public
function GetFormatEtc: TFormatEtc; override;
function LoadFromDataObject(DataObject: IDataObject): Boolean; override;
function SaveToDataObject(DataObject: IDataObject): Boolean; override;
property Data: Cardinal read FData write FData;
end;
function FillFormatEtc(cfFormat: Word; ptd: PDVTargetDevice = nil;
dwAspect: Longint = DVASPECT_CONTENT; lindex: Longint = -1; tymed: Longint = TYMED_HGLOBAL): TFormatEtc;
function DataObjectSupportsShell(const DataObj: IDataObject): Boolean;
function DataObjectContainsPIDL(APIDL: PItemIDList; const DataObj: IDataObject): Boolean;
function HDropFormat: TFormatEtc;
function ShellIDListFormat: TFormatEtc;
function FileDescriptorAFormat: TFormatEtc;
function FileDescriptorWFormat: TFormatEtc;
var
CF_SHELLIDLIST,
CF_PERFORMEDDROPEFFECT,
CF_PASTESUCCEEDED,
CF_INDRAGLOOP,
CF_SHELLIDLISTOFFSET,
CF_LOGICALPERFORMEDDROPEFFECT,
CF_PREFERREDDROPEFFECT,
CF_FILECONTENTS,
CF_FILEDESCRIPTORA,
CF_FILEDESCRIPTORW: TClipFormat;
implementation
var
PIDLMgr: TCommonPIDLManager;
ShellILIsEqual: function(PIDL1: PItemIDList; PIDL2: PItemIDList): LongBool; stdcall;
ShellILIsEqualChecked: Boolean = False;
function LoadShellILIsEqual: Boolean;
begin
if not ShellILIsEqualChecked then
begin
ShellILIsEqual := GetProcAddress(GetModuleHandle(PChar(Shell32)), PChar(21));
ShellILIsEqualChecked := True;
end;
Result := Assigned(ShellILIsEqual)
end;
function DataObjectContainsPIDL(APIDL: PItemIDList; const DataObj: IDataObject): Boolean;
var
ShellIDList: TCommonShellIDList;
i: Integer;
P: PItemIDList;
begin
Result := False;
;
if Assigned(DataObj) and Assigned(APIDL) and LoadShellILIsEqual then
begin
if Succeeded(DataObj.QueryGetData(ShellIDListFormat)) then
begin
ShellIDList := TCommonShellIDList.Create;
try
if ShellIDList.LoadFromDataObject(DataObj) then
begin
i := 0;
while not Result and (i < ShellIDList.PIDLCount) do
begin
P := ShellIDList.AbsolutePIDL(i);
Result := ShellILIsEqual(P, APIDL);
PIDLMgr.FreePIDL(P);
Inc(i)
end
end
finally
ShellIDList.Free
end
end
end
end;
function DataObjectSupportsShell(const DataObj: IDataObject): Boolean;
begin
Result := False;
if Assigned(DataObj) then
begin
Result := Succeeded(DataObj.QueryGetData(HDropFormat)) or
Succeeded(DataObj.QueryGetData(ShellIDListFormat)) or
Succeeded(DataObj.QueryGetData(FileDescriptorAFormat)) or
Succeeded(DataObj.QueryGetData(FileDescriptorWFormat))
end
end;
function HDropFormat: TFormatEtc;
begin
Result.cfFormat := CF_HDROP; // This guy is always registered for all applications
Result.ptd := nil;
Result.dwAspect := DVASPECT_CONTENT;
Result.lindex := -1;
Result.tymed := TYMED_HGLOBAL
end;
function ShellIDListFormat: TFormatEtc;
begin
Result.cfFormat := CF_SHELLIDLIST;
Result.ptd := nil;
Result.dwAspect := DVASPECT_CONTENT;
Result.lindex := -1;
Result.tymed := TYMED_HGLOBAL;
end;
function FileDescriptorAFormat: TFormatEtc;
begin
Result.cfFormat := CF_FILEDESCRIPTORA;
Result.ptd := nil;
Result.dwAspect := DVASPECT_CONTENT;
Result.lindex := -1;
Result.tymed := TYMED_HGLOBAL
end;
function FileDescriptorWFormat: TFormatEtc;
begin
Result.cfFormat := CF_FILEDESCRIPTORW;
Result.ptd := nil;
Result.dwAspect := DVASPECT_CONTENT;
Result.lindex := -1;
Result.tymed := TYMED_HGLOBAL
end;
function FillFormatEtc(cfFormat: Word; ptd: PDVTargetDevice = nil;
dwAspect: Longint = DVASPECT_CONTENT; lindex: Longint = -1; tymed: Longint = TYMED_HGLOBAL): TFormatEtc;
begin
Result.cfFormat := cfFormat;
Result.ptd := ptd;
Result.dwAspect := dwAspect;
Result.lindex := lindex;
Result.tymed := tymed
end;
{ TCommonClipboardFormat }
function TCommonClipboardFormat.GetFormatEtc: TFormatEtc;
begin
FillChar(Result, SizeOf(Result), #0);
end;
function TCommonClipboardFormat.LoadFromClipboard: Boolean;
begin
Result := False;
end;
function TCommonClipboardFormat.SaveToClipboard: Boolean;
begin
Result := False;
end;
{ TLogicalPerformedDropEffect }
function TCommonLogicalPerformedDropEffect.GetFormatEtc: TFormatEtc;
begin
Result.cfFormat := CF_LOGICALPERFORMEDDROPEFFECT;
Result.ptd := nil;
Result.dwAspect := DVASPECT_CONTENT;
Result.lindex := -1;
Result.tymed := TYMED_HGLOBAL
end;
function TCommonLogicalPerformedDropEffect.LoadFromDataObject(DataObject: IDataObject): Boolean;
var
Ptr: PPerformedDropEffect;
StgMedium: TStgMedium;
begin
Result := False;
FillChar(StgMedium, SizeOf(StgMedium), #0);
if Succeeded(DataObject.GetData(GetFormatEtc, StgMedium)) then
try
Ptr := GlobalLock(StgMedium.hGlobal);
try
if Assigned(Ptr) then
begin
FAction := Ptr^;
Result := True;
end;
finally
GlobalUnLock(StgMedium.hGlobal);
end
finally
ReleaseStgMedium(StgMedium)
end
end;
function TCommonLogicalPerformedDropEffect.SaveToDataObject(DataObject: IDataObject): Boolean;
var
Ptr: PPerformedDropEffect;
StgMedium: TStgMedium;
begin
FillChar(StgMedium, SizeOf(StgMedium), #0);
StgMedium.hGlobal := GlobalAlloc(GPTR, SizeOf(FAction));
Ptr := GlobalLock(StgMedium.hGlobal);
try
Ptr^ := FAction;
StgMedium.tymed := TYMED_HGLOBAL;
Result := Succeeded(DataObject.SetData(GetFormatEtc, StgMedium, True))
finally
GlobalUnLock(StgMedium.hGlobal);
end
end;
{ THDrop }
procedure TCommonHDrop.AllocStructure(Size: integer);
begin
FreeStructure;
GetMem(FDropFiles, Size);
FStructureSize := Size;
FillChar(FDropFiles^, Size, #0);
end;
procedure TCommonHDrop.AssignFilesA(FileList: TStringList);
var
i: Integer;
Size: integer;
Path: PChar;
begin
if Assigned(FileList) then
begin
FreeStructure;
Size := 0;
for i := 0 to FileList.Count - 1 do
Inc(Size, Length(FileList[i]) + SizeOf(Char)); // add spot for the null
Inc(Size, SizeOf(TDropFiles));
Inc(Size, SizeOf(Char)); // room for the terminating null
AllocStructure(Size);
DropFiles.pFiles := SizeOf(TDropFiles);
DropFiles.pt.x := 0;
DropFiles.pt.y := 0;
DropFiles.fNC := False;
DropFiles.fWide := False; // Don't support wide char let NT convert it
Path := PChar(FDropFiles) + FDropFiles.pFiles;
for i := 0 to FileList.Count - 1 do
begin
MoveMemory(Path, Pointer(FileList[i]), Length(FileList[i]));
Inc(Path, Length(FileList[i]) + 1); // skip over the single null #0
end
end
end;
function TCommonHDrop.AssignFromClipboard: Boolean;
var
Handle: THandle;
Ptr: PDropFiles;
begin
Result := False;
Handle := 0;
OpenClipboard(Application.Handle);
try
Handle := GetClipboardData(CF_HDROP);
if Handle <> 0 then
begin
Ptr := GlobalLock(Handle);
if Assigned(Ptr) then
begin
DropFiles := Ptr;
Result := True;
end;
end;
finally
CloseClipboard;
GlobalUnLock(Handle);
end;
end;
function TCommonHDrop.CalculateDropFileStructureSizeA(
Value: PDropFiles): integer;
var
Head: PChar;
Len: integer;
begin
if Assigned(Value) then
begin
Result := Value^.pFiles;
Head := PChar( Value) + Value^.pFiles;
Len := lstrlen(Head);
while Len > 0 do
begin
Result := Result + Len + 1;
Head := Head + Len + 1;
Len := lstrlen(Head);
end;
Inc(Result, 1); // Add second null
end else
Result := 0
end;
function TCommonHDrop.CalculateDropFileStructureSizeW(
Value: PDropFiles): integer;
var
Head: PChar;
Len: integer;
begin
if Assigned(Value) then
begin
Result := Value^.pFiles;
Head := PChar( Value) + Value^.pFiles;
Len := 2 * (lstrlenW(PWideChar( Head)));
while Len > 0 do
begin
Result := Result + Len + 2;
Head := Head + Len + 2;
Len := 2 * (lstrlenW(PWideChar( Head)));
end;
Inc(Result, 2); // Add second null
end else
Result := 0
end;
destructor TCommonHDrop.Destroy;
begin
FreeStructure;
inherited;
end;
function TCommonHDrop.FileCount: integer;
begin
if Assigned(DropFiles) then
begin
if FFileCount = 0 then
begin
if DropFiles.fWide then
Result := FileCountW
else
Result := FileCountA;
FFileCount := Result;
end;
end else
FFileCount := 0;
Result := FFileCount
end;
function TCommonHDrop.FileCountA: Integer;
var
Head: PChar;
Len: integer;
begin
Result := 0;
if Assigned(DropFiles) then
begin
Head := PChar( DropFiles) + DropFiles^.pFiles;
Len := lstrlen(Head);
while Len > 0 do
begin
Head := Head + Len + 1;
Inc(Result);
Len := lstrlen(Head);
end
end
end;
function TCommonHDrop.FileCountW: Integer;
var
Head: PChar;
Len: integer;
begin
Result := 0;
if Assigned(DropFiles) then
begin
Head := PChar( DropFiles) + DropFiles^.pFiles;
Len := 2 * (lstrlenW(PWideChar( Head)));
while Len > 0 do
begin
Head := Head + Len + 2;
Inc(Result);
Len := 2 * (lstrlenW(PWideChar( Head)));
end
end;
end;
function TCommonHDrop.FileName(Index: integer): WideString;
begin
if Assigned(DropFiles) then
begin
if DropFiles.fWide then
Result := FileNameW(Index)
else
Result := FileNameA(Index)
end
end;
function TCommonHDrop.FileNameA(Index: integer): string;
var
Head: PChar;
PathNameCount: integer;
Done: Boolean;
Len: integer;
begin
PathNameCount := 0;
Done := False;
if Assigned(DropFiles) then
begin
Head := PChar( DropFiles) + DropFiles^.pFiles;
Len := lstrlen(Head);
while (not Done) and (PathNameCount < FileCount) do
begin
if PathNameCount = Index then
begin
SetLength(Result, Len + 1);
CopyMemory(@Result[1], Head, Len + 1); // Include the NULL
Done := True;
end;
Head := Head + Len + 1;
Inc(PathNameCount);
Len := lstrlen(Head);
end
end
end;
{$IFDEF TNTSUPPORT}
procedure TCommonHDrop.AssignFilesW(FileList: TWideStrings);
var
i: Integer;
Size: integer;
Path: PChar;
ByteSize: Integer;
begin
if Assigned(FileList) then
begin
FreeStructure;
Size := 0;
if UnicodeStringLists then
ByteSize := 2
else
ByteSize := 1;
for i := 0 to FileList.Count - 1 do
Inc(Size, (Length(FileList[i])+1)*(SizeOf(Char)*ByteSize)); // add spot for the null
Inc(Size, SizeOf(TDropFiles));
Inc(Size, SizeOf(Char)*2); // room for the terminating null
AllocStructure(Size);
DropFiles.pFiles := SizeOf(TDropFiles);
DropFiles.pt.x := 0;
DropFiles.pt.y := 0;
DropFiles.fNC := False;
DropFiles.fWide := UnicodeStringLists;
Path := PChar(FDropFiles) + FDropFiles.pFiles;
for i := 0 to FileList.Count - 1 do
begin
MoveMemory(Path, Pointer(FileList[i]), Length(FileList[i])*ByteSize);
Inc(Path, (Length(FileList[i]) + 1)*ByteSize); // skip over the single null #0
end
end
end;
procedure TCommonHDrop.FileNamesW(FileList: TWideStrings);
var
i: integer;
begin
if Assigned(FileList) then
begin
for i := 0 to FileCount - 1 do
FileList.Add(FileNameW(i));
end;
end;
{$ENDIF}
procedure TCommonHDrop.FileNamesA(FileList: TStrings);
var
i: integer;
begin
if Assigned(FileList) then
begin
for i := 0 to FileCount - 1 do
FileList.Add(FileName(i));
end;
end;
function TCommonHDrop.FileNameW(Index: integer): WideString;
var
Head: PChar;
PathNameCount: integer;
Done: Boolean;
Len: integer;
begin
PathNameCount := 0;
Done := False;
if Assigned(DropFiles) then
begin
Head := PChar( DropFiles) + DropFiles^.pFiles;
Len := 2 * (lstrlenW(PWideChar( Head)));
while (not Done) and (PathNameCount < FileCount) do
begin
if PathNameCount = Index then
begin
SetLength(Result, (Len + 1) div 2);
CopyMemory(@Result[1], Head, Len + 2); // Include the NULL
Done := True;
end;
Head := Head + Len + 2;
Inc(PathNameCount);
Len := 2 * (lstrlenW(PWideChar( Head)));
end
end
end;
procedure TCommonHDrop.FreeStructure;
begin
FFileCount := 0;
if Assigned(FDropFiles) then
FreeMem(FDropFiles, FStructureSize);
FDropFiles := nil;
FStructureSize := 0;
end;
function TCommonHDrop.GetFormatEtc: TFormatEtc;
begin
Result.cfFormat := CF_HDROP; // This guy is always registered for all applications
Result.ptd := nil;
Result.dwAspect := DVASPECT_CONTENT;
Result.lindex := -1;
Result.tymed := TYMED_HGLOBAL
end;
function TCommonHDrop.GetHDropStruct: THandle;
var
Files: PDropFiles;
begin
Result := GlobalAlloc(GHND, StructureSize);
Files := GlobalLock(Result);
try
MoveMemory(Files, FDropFiles, StructureSize);
finally
GlobalUnlock(Result)
end;
end;
function TCommonHDrop.LoadFromClipboard: Boolean;
var
Handle: THandle;
Ptr: PDropFiles;
begin
Result := False;
Handle := 0;
OpenClipboard(Application.Handle);
try
Handle := GetClipboardData(CF_HDROP);
if Handle <> 0 then
begin
Ptr := GlobalLock(Handle);
if Assigned(Ptr) then
begin
DropFiles := Ptr;
Result := True;
end;
end;
finally
CloseClipboard;
GlobalUnLock(Handle);
end;
end;
function TCommonHDrop.LoadFromDataObject(DataObject: IDataObject): Boolean;
var
Medium: TStgMedium;
Files: PDropFiles;
begin
Result := False;
if Assigned(DataObject) then
begin
if Succeeded(DataObject.GetData(GetFormatEtc, Medium)) then
try
Files := GlobalLock(Medium.hGlobal);
try
DropFiles := Files
finally
GlobalUnlock(Medium.hGlobal)
end
finally
ReleaseStgMedium(Medium)
end;
Result := Assigned(DropFiles)
end
end;
function TCommonHDrop.SaveToClipboard: Boolean;
begin
Result := False;
OpenClipboard(Application.Handle);
try
SetClipboardData(CF_HDROP, HDropStruct)
finally
CloseClipboard;
end;
end;
function TCommonHDrop.SaveToDataObject(DataObject: IDataObject): Boolean;
var
Medium: TStgMedium;
begin
Result := False;
FillChar(Medium, SizeOf(Medium), #0);
Medium.tymed := TYMED_HGLOBAL;
Medium.hGlobal := HDropStruct;
// Give the block to the DataObject
if Succeeded(DataObject.SetData(GetFormatEtc, Medium, True)) then
Result := True
else
GlobalFree(Medium.hGlobal)
end;
procedure TCommonHDrop.SetDropFiles(const Value: PDropFiles);
begin
FreeStructure;
if Assigned(Value) then
begin
if Value.fWide then
FStructureSize := CalculateDropFileStructureSizeW(Value)
else
FStructureSize := CalculateDropFileStructureSizeA(Value);
AllocStructure(StructureSize);
CopyMemory(FDropFiles, Value, StructureSize);
end;
end;
{ TPreferredDropEffect }
function TCommonPreferredDropEffect.GetFormatEtc: TFormatEtc;
begin
Result.cfFormat := CF_PREFERREDDROPEFFECT;
Result.ptd := nil;
Result.dwAspect := DVASPECT_CONTENT;
Result.lindex := -1;
Result.tymed := TYMED_HGLOBAL
end;
{ TCoolStreamClipFormat }
function TCommonStreamClipFormat.GetFormatEtc: TFormatEtc;
begin
Result.cfFormat := 0;
Result.ptd := nil;
Result.dwAspect := DVASPECT_CONTENT;
Result.lindex := -1;
Result.tymed := TYMED_HGLOBAL
end;
function TCommonStreamClipFormat.LoadFromClipboard: Boolean;
begin
Result := False;
Assert(True=False, 'TCoolStream.LoadFromClipboard not Implemented');
end;
function TCommonStreamClipFormat.LoadFromDataObject(DataObject: IDataObject;
CoolStream: TCommonStream): Boolean;
var
Medium: TStgMedium;
PMem, PSize: Pointer;
Size: Int64;
begin
Result := False;
if Succeeded(DataObject.GetData(GetFormatEtc, Medium)) then
begin
PMem := GlobalLock(Medium.hGlobal);
try
PSize := @Size;
// Get the size of the Stream
MoveMemory(PMem, PSize, SizeOf(Int64));
CoolStream.Seek(0, soFromBeginning);
CoolStream.SetSize(Size);
Inc(PChar( PMem), SizeOf(Int64));
// Copy the data to the stream
MoveMemory(PMem, CoolStream.Memory, Size);
finally
GlobalUnlock(Medium.hGlobal);
ReleaseStgMedium(Medium);
end
end
end;
function TCommonStreamClipFormat.SaveToClipboard: Boolean;
begin
Result := False;
Assert(True=False, 'TCoolStream.SaveToClipboard not Implemented');
end;
function TCommonStreamClipFormat.SaveToDataObject(DataObject: IDataObject;
CoolStream: TCommonStream): Boolean;
var
Medium: TStgMedium;
Mem: HGlobal;
PMem: Pointer;
Size: Int64;
PSize: Pointer;
begin
Mem := GlobalAlloc(GMEM_SHARE or GMEM_MOVEABLE, CoolStream.Size + SizeOf(Int64));
PMem := GlobalLock(Mem);
try
FillChar(Medium, SizeOf(Medium), #0);
PSize := @Size;
// Write the size of the Stream to the block
Size := CoolStream.Size;
MoveMemory(PMem, PSize, SizeOf(Int64));
// Copy the Stream to a global memory block
MoveMemory(PMem, CoolStream.Memory, CoolStream.Size);
// Transfer the data with a global memory block
Medium.tymed := TYMED_HGLOBAL;
Medium.hGlobal := Mem;
// Give it to the DataObject so it may destroy it when the clients are done
Result := Succeeded(DataObject.SetData(GetFormatEtc, Medium, True))
finally
GlobalUnlock(Mem)
end
end;
{ TShellIDList }
function TCommonShellIDList.AbsolutePIDL(Index: integer): PItemIDList;
{ Appends the single ItemID with the Parent folder to create an Absolute PIDL }
begin
if Assigned(FCIDA) then
begin
Result := PIDLMgr.AppendPIDL(InternalParentPIDL, InternalChildPIDL(Index));
end else
Result := nil
end;
procedure TCommonShellIDList.AbsolutePIDLs(APIDLList: TCommonPIDLList);
var
i: integer;
begin
if Assigned(APIDLList) and Assigned(FCIDA) then
begin
for i := 0 to PIDLCount - 1 do
APIDLList.Add( PIDLMgr.AppendPIDL(InternalParentPIDL, InternalChildPIDL(i)))
end;
end;
procedure TCommonShellIDList.AssignPIDLs(APIDLList: TCommonPIDLList);
{ PIDLs[0] must be the Absolute Parent PIDL and the rest single ItemID children }
var
Count: Integer;
i: Integer;
Head: Pointer;
PIDLLength: Integer;
begin
Count := 0;
if Assigned(APIDLList) then
begin
{ Free previously assigned CIDA }
if Assigned(FCIDA) then
FreeMem(FCIDA, CIDASize);
FCIDA := nil;
Inc(Count, SizeOf(FCIDA.cidl));
Inc(Count, SizeOf(FCIDA.aoffset) * (APIDLList.Count));
for i := 0 to APIDLList.Count - 1 do
Inc(Count, PIDLMgr.PIDLSize( APIDLList[i]));
GetMem(FCIDA, Count);
Head := FCIDA;
{ Head points to the position of the first PIDL }
Inc(PChar(Head), SizeOf(FCIDA.cidl) + (SizeOf(FCIDA.aoffset) * APIDLList.Count));
{ Don't count the absolute parent PIDL }
FCIDA.cidl := APIDLList.Count - 1;
for i := 0 to APIDLList.Count - 1 do
begin
{ Set up the array index to point to the actual PIDL data }
FCIDA.aoffset[i] := LongWord(Head-PChar( CIDA));
PIDLLength := PIDLMgr.PIDLSize(APIDLList[i]);
Move(APIDLList[i]^, Head^, PIDLLength);
Inc(PChar(Head), PIDLLength);
end;
end;
end;
destructor TCommonShellIDList.Destroy;
begin
{ Free previously assigned CIDA }
if Assigned(FCIDA) then
FreeMem(FCIDA, CIDASize);
inherited;
end;
function TCommonShellIDList.GetCIDASize: integer;
var
Count: integer;
i: integer;
begin
Count := 0;
if Assigned(FCIDA) then
begin
Inc(Count, SizeOf( FCIDA.cidl));
Inc(Count, SizeOf( FCIDA.aoffset) * (PIDLCount + 1)); // Does't count [0]
Inc(Count, PIDLMgr.PIDLSize(InternalParentPIDL));
for i := 0 to PIDLCount - 1 do
Inc(Count, PIDLMgr.PIDLSize(InternalChildPIDL(i)));
end;
Result := Count;
end;
function TCommonShellIDList.GetFormatEtc: TFormatEtc;
begin
Result.cfFormat := CF_SHELLIDLIST;
Result.ptd := nil;
Result.dwAspect := DVASPECT_CONTENT;
Result.lindex := -1;
Result.tymed := TYMED_HGLOBAL;
end;
function TCommonShellIDList.InternalChildPIDL(Index: integer): PItemIDList;
{ Remember PIDLCount does not count index [0] where the Absolute Parent is }
begin
if Assigned(FCIDA) and (Index > -1) and (Index < PIDLCount) then
Result := PItemIDList( PChar(FCIDA) + PDWORD(PChar(@FCIDA^.aoffset)+sizeof(FCIDA^.aoffset[0])*(1+Index))^)
else
Result := nil
end;
function TCommonShellIDList.InternalParentPIDL: PItemIDList;
{ Remember PIDLCount does not count index [0] where the Absolute Parent is }
begin
if Assigned(FCIDA) then
Result := PItemIDList( PChar(FCIDA) + FCIDA^.aoffset[0])
else
Result := nil
end;
function TCommonShellIDList.LoadFromClipboard: Boolean;
var
Handle: THandle;
Ptr: PIDA;
begin
Result := True;
Handle := 0;
if Result then
begin
try
try
Handle := GetClipboardData(CF_SHELLIDLIST);
if Handle <> 0 then
begin
Ptr := GlobalLock(Handle);
if Assigned(Ptr) then
begin
CIDA := Ptr;
Result := True;
end;
end;
except
Result := False;
raise;
end;
finally
GlobalUnLock(Handle);
end;
end
end;
function TCommonShellIDList.LoadFromDataObject(DataObject: IDataObject): Boolean;
var
Ptr: PIDA;
StgMedium: TStgMedium;
begin
Result := False;
FillChar(StgMedium, SizeOf(StgMedium), #0);
if Succeeded(DataObject.GetData(GetFormatEtc, StgMedium)) then
try
Ptr := GlobalLock(StgMedium.hGlobal);
try
if Assigned(Ptr) then
begin
CIDA := Ptr;
Result := True;
end;
finally
GlobalUnLock(StgMedium.hGlobal);
end;
finally
ReleaseStgMedium(StgMedium)
end;
end;
function TCommonShellIDList.ParentPIDL: PItemIDList;
begin
Result := PIDLMgr.CopyPIDL( InternalParentPIDL)
end;
function TCommonShellIDList.PIDLCount: integer;
{ indexing is a bit weird. Index 0 is the Absolute Parent PIDL but it is not }
{ counted in the first byte of the structure. }
begin
if Assigned(FCIDA) then
Result := FCIDA^.cidl
else
Result := 0
end;
function TCommonShellIDList.RelativePIDL(Index: integer): PItemIDList;
{ Retrieves the single ItemID child by index }
begin
Result := PIDLMgr.CopyPIDL( InternalChildPIDL(Index))
end;
procedure TCommonShellIDList.RelativePIDLs(APIDLList: TCommonPIDLList);
{ Loads APIDLList with PIDL's stored in the CIDA. ReturnCopy flags if the }
{ contents will be the origionals or copies created by the PIDLMgr. }
var
i: integer;
begin
if Assigned(APIDLList) and Assigned(FCIDA) then
begin
APIDLList.CopyAdd( InternalParentPIDL);
for i := 0 to PIDLCount - 1 do
APIDLList.CopyAdd( InternalChildPIDL(i))
end;
end;
function TCommonShellIDList.SaveToClipboard: Boolean;
var
DataObject: IDataObject;
begin
Result := False;
DataObject := TCommonDataObject.Create;
if SaveToDataObject(DataObject) then
Result := Succeeded(OleSetClipboard(DataObject))
end;
function TCommonShellIDList.SaveToDataObject(DataObject: IDataObject): Boolean;
var
StgMedium: TStgMedium;
Ptr: PIDA;
begin
FillChar(StgMedium, SizeOf(StgMedium), #0);
StgMedium.hGlobal := GlobalAlloc(GPTR, GetCIDASize);
Ptr := GlobalLock(StgMedium.hGlobal);
try
StgMedium.tymed := TYMED_HGLOBAL;
CopyMemory(Ptr, CIDA, GetCIDASize);
Result := Succeeded(DataObject.SetData(GetFormatEtc, StgMedium, True))
finally
GlobalUnLock(StgMedium.hGlobal);
end;
end;
procedure TCommonShellIDList.SetCIDA(const Value: PIDA);
var
TempSize: integer;
begin
{ Free previously assigned CIDA }
if Assigned(FCIDA) then
begin
FreeMem(FCIDA, CIDASize);
FCIDA := nil;
end;
if Value <> nil then
begin
{ Temporally assign the passed PIDA to the object }
FCIDA := Value;
{ Get the size of the passed PIDA }
TempSize := CIDASize;
{ Get memory to make a copy of the passed PIDA }
GetMem(FCIDA, TempSize);
{ Copy the passed PIDA }
Move(Value^, FCIDA^, TempSize);
end;
end;
{ TCommonEnumFormatEtc }
function TCommonEnumFormatEtc.Clone(out Enum: IEnumFormatEtc): HResult;
// Creates a exact copy of the current object.
var
EnumFormatEtc: TCommonEnumFormatEtc;
begin
Result := S_OK; // Think positive
EnumFormatEtc := TCommonEnumFormatEtc.Create; // Does not increase COM reference
if Assigned(EnumFormatEtc) then
begin
SetLength(EnumFormatEtc.FFormats, Length(Formats));
// Make copy of Format info
Move(FFormats[0], EnumFormatEtc.FFormats[0], Length(Formats) * SizeOf(TFormatEtc));
EnumFormatEtc.InternalIndex := InternalIndex;
Enum := EnumFormatEtc as IEnumFormatEtc; // Sets COM reference to 1
end else
Result := E_UNEXPECTED
end;
constructor TCommonEnumFormatEtc.Create;
begin
inherited Create;
InternalIndex := 0;
end;
destructor TCommonEnumFormatEtc.Destroy;
begin
inherited;
end;
function TCommonEnumFormatEtc.Next(celt: Integer; out elt; pceltFetched: PLongint): HResult;
// Another EnumXXXX function. This function returns the number of objects
// requested by the caller in celt. The return buffer, elt, is a pointer to an}
// array of, in this case, TFormatEtc structures. The total number of
// structures returned is placed in pceltFetched. pceltFetched may be nil if
// celt is only asking for one structure at a time.
var
i: integer;
begin
if Assigned(Formats) then
begin
i := 0;
while (i < celt) and (InternalIndex < Length(Formats)) do
begin
TeltArray( elt)[i] := Formats[InternalIndex];
inc(i);
inc(FInternalIndex);
end; // while
if assigned(pceltFetched) then
pceltFetched^ := i;
if i = celt then
Result := S_OK
else
Result := S_FALSE
end else
Result := E_UNEXPECTED
end;
function TCommonEnumFormatEtc.Reset: HResult;
begin
InternalIndex := 0;
Result := S_OK
end;
function TCommonEnumFormatEtc.Skip(celt: Integer): HResult;
// Allows the caller to skip over unwanted TFormatEtc structures. Simply adds
// celt to the index as long as it does not skip past the last structure in
// the list.
begin
if Assigned(Formats) then
begin
if InternalIndex + celt < Length(Formats) then
begin
InternalIndex := InternalIndex + celt;
Result := S_OK
end else
Result := S_FALSE
end else
Result := E_UNEXPECTED
end;
procedure TCommonEnumFormatEtc.SetFormatLength(Size: Integer);
begin
SetLength(FFormats, Size)
end;
{ TCommonDataObject }
class function TCommonDataObject.NewInstance: TObject;
begin
Result := inherited NewInstance;
TCommonDataObject(Result).FRefCount := 1;
end;
function TCommonDataObject.AssignDragImage(Image: TBitmap;
HotSpot: TPoint; TransparentColor: TColor): Boolean;
//
// Stores the Bitmap in the IDataObject to support the IDragSourceHelper drag image
// in Win2K and above.
//
var
DragSourceHelper: IDragSourceHelper;
SHDragImage: TSHDragImage;
begin
Result := False;
// NT can't swallow this CoCreateInstance call
if not IsWinNT4 then
begin
if Succeeded(CoCreateInstance(CLSID_DragDropHelper, nil, CLSCTX_INPROC_SERVER, IID_IDragSourceHelper, DragSourceHelper)) then
begin
FillChar(SHDragImage, SizeOf(SHDragImage), #0);
SHDragImage.sizeDragImage.cx := Image.Width;
SHDragImage.sizeDragImage.cy := Image.Height;
SHDragImage.ptOffset := HotSpot;
SHDragImage.ColorRef := ColorToRGB(TransparentColor);
SHDragImage.hbmpDragImage := CopyImage(Image.Handle, IMAGE_BITMAP, Image.Width,
Image.Height, LR_COPYRETURNORG);
if SHDragImage.hbmpDragImage <> 0 then
if Succeeded(DragSourceHelper.InitializeFromBitmap(SHDragImage, Self as IDataObject)) then
Result := True
else
DeleteObject(SHDragImage.hbmpDragImage);
end
end
end;
function TCommonDataObject.CanonicalIUnknown(TestUnknown: IUnknown): IUnknown;
// Uses COM object identity: An explicit call to the IUnknown::QueryInterface
// method, requesting the IUnknown interface, will always return the same
// pointer.
begin
if Assigned(TestUnknown) then
begin
if CommonSupports(TestUnknown, IUnknown, Result) then
IUnknown(Result)._Release // Don't actually need it just need the pointer value
else
Result := TestUnknown
end else
Result := TestUnknown
end;
constructor TCommonDataObject.Create;
begin
inherited;
end;
function TCommonDataObject.DAdvise(const formatetc: TFormatEtc; advf: Integer;
const advSink: IAdviseSink; out dwConnection: Integer): HResult;
begin
if not Assigned(AdviseHolder) then
CreateDataAdviseHolder(FAdviseHolder);
if Assigned(FAdviseHolder) then
Result := AdviseHolder.Advise(Self as IDataObject, formatetc, advf, advSink, dwConnection)
else
Result := OLE_E_ADVISENOTSUPPORTED;
end;
destructor TCommonDataObject.Destroy;
begin
inherited;
end;
function TCommonDataObject.GetObj: TObject;
begin
Result := Self
end;
function TCommonDataObject.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if GetInterface(IID, Obj) then
Result := 0
else
Result := E_NOINTERFACE;
end;
function TCommonDataObject._AddRef: Integer;
begin
Result := InterlockedIncrement(FRefCount);
{$IFDEF GX_DEBUG}
SendDebug('TCommonDataObject: ' + IntToHex(Integer(Self), 8) + ' AddRef: Count = ' + IntToStr(FRefCount));
{$ENDIF}
end;
function TCommonDataObject._Release: Integer;
begin
Result := InterlockedDecrement(FRefCount);
{$IFDEF GX_DEBUG}
SendDebug('TCommonDataObject: ' + IntToHex(Integer(Self), 8) + ' Release: Count = ' + IntToStr(FRefCount));
{$ENDIF}
if Result = 0 then
Destroy;
end;
procedure TCommonDataObject.AfterConstruction;
begin
// Release the constructor's implicit refcount
InterlockedDecrement(FRefCount);
end;
procedure TCommonDataObject.BeforeDestruction;
begin
// if RefCount <> 0 then
// Error(reInvalidPtr);
end;
procedure TCommonDataObject.DoGetCustomFormats(var Formats: TFormatEtcArray);
begin
end;
procedure TCommonDataObject.DoOnGetData(const FormatEtcIn: TFormatEtc;
var Medium: TStgMedium; var Handled: Boolean);
begin
if Assigned(FOnGetData) then
OnGetData(Self, FormatEtcIn, Medium, Handled);
end;
procedure TCommonDataObject.DoOnQueryGetData(
const FormatEtcIn: TFormatEtc; var FormatAvailable: Boolean; var Handled: Boolean);
begin
if Assigned(FOnQueryGetData) then
OnQueryGetData(Self, FormatEtcIn, FormatAvailable, Handled);
end;
function TCommonDataObject.DUnadvise(dwConnection: Integer): HResult;
begin
if Assigned(AdviseHolder) then
Result := AdviseHolder.Unadvise(dwConnection)
else
Result := OLE_E_ADVISENOTSUPPORTED;
end;
function TCommonDataObject.EnumDAdvise(out enumAdvise: IEnumStatData): HResult;
begin
if Assigned(AdviseHolder) then
Result := AdviseHolder.EnumAdvise(enumAdvise)
else
Result := OLE_E_ADVISENOTSUPPORTED;
end;
function TCommonDataObject.EnumFormatEtc(dwDirection: Integer;
out enumFormatEtc: IEnumFormatEtc): HResult;
// Called when DoDragDrop wants to know what clipboard formats are supported
// by Enumerating the TFormatEtc array through an IEnumFormatEtc object.
var
LocalEnumFormatEtc: TCommonEnumFormatEtc;
i: integer;
begin
// Always return an object even if it is empty
LocalEnumFormatEtc := TCommonEnumFormatEtc.Create;
// Get the reference count in sync
enumFormatEtc := LocalEnumFormatEtc as IEnumFormatEtc;
{ if Assigned(Formats) then
begin }
Result := S_OK;
if dwDirection = DATADIR_GET then
begin
// Copy the internal supported Formats for the EnumFormatEtc
SetLength(LocalEnumFormatEtc.FFormats, Length(Formats));
for i := 0 to Length(Formats) - 1 do
LocalEnumFormatEtc.Formats[i] := Formats[i].FormatEtc;
// Now copy any custom formats
DoGetCustomFormats(LocalEnumFormatEtc.FFormats);
if not Assigned(enumFormatEtc) then
Result := E_OUTOFMEMORY
end else
begin
enumFormatEtc := nil;
Result := E_NOTIMPL;
end;
{ end else
begin
if dwDirection = DATADIR_GET then
Result := S_OK
else
Result := E_NOTIMPL
end }
end;
function TCommonDataObject.EqualFormatEtc(FormatEtc1, FormatEtc2: TFormatEtc): Boolean;
begin
Result := (FormatEtc1.cfFormat = FormatEtc2.cfFormat) and
(FormatEtc1.ptd = FormatEtc2.ptd) and
(FormatEtc1.dwAspect = FormatEtc2.dwAspect) and
(FormatEtc1.lindex = FormatEtc2.lindex) and
(FormatEtc1.tymed = FormatEtc2.tymed)
end;
function TCommonDataObject.FindFormatEtc(TestFormatEtc: TFormatEtc): integer;
var
i: integer;
Found: Boolean;
begin
i := 0;
Found := False;
Result := -1;
while (i < Length(FFormats)) and not Found do
begin
Found := EqualFormatEtc(Formats[i].FormatEtc, TestFormatEtc);
if Found then
Result := i;
Inc(i);
end
end;
function TCommonDataObject.GetCanonicalFormatEtc(const formatetc: TFormatEtc;
out formatetcOut: TFormatEtc): HResult;
// Since we do not have two TFormatEtcs that return the same type of data we can
// ingore this function. It is only for TFormatEtc structures that will return
// the exact same data if each is called. This could happen if the data is
// target dependant and the target can handle both types of data. This keeps
// the target from asking for redundant information.
begin
formatetcOut.ptd := nil;
Result := E_NOTIMPL;
end;
function TCommonDataObject.GetData(const FormatEtcIn: TFormatEtc;
out Medium: TStgMedium): HResult;
// This is the workhorse of the functions. It looks at the clipboard format
// the IDropTarget wants, makes sure we can support it. If supported then see
// if it is owned by the object or the program will supply the data.
var
Handled: Boolean;
begin
Result := E_UNEXPECTED;
Handled := False;
DoOnGetData(FormatEtcIn, Medium, Handled);
if not Handled then
begin
if Assigned(Formats) then
begin
{ Do we support this type of Data? }
Result := QueryGetData(FormatEtcIn);
if Result = S_OK then
begin
// If the data is owned by the IDataObject just retrieve and return it.
if RetrieveOwnedStgMedium(FormatEtcIn, Medium) = E_INVALIDARG then
{ This data is defined by the Object Inspector or a custom format need to }
{ Retrive it from the DragSourceManager }
if not GetUserData(FormatEtcIn, Medium) then
Result := E_UNEXPECTED
end
end
end else
Result := S_OK
end;
function TCommonDataObject.GetDataHere(const formatetc: TFormatEtc;
out medium: TStgMedium): HResult;
begin
Result := E_NOTIMPL;
end;
function TCommonDataObject.GetUserData(Format: TFormatEtc; var StgMedium: TStgMedium): Boolean;
begin
Result := False;
end;
function TCommonDataObject.HGlobalClone(HGlobal: THandle): THandle;
// Returns a global memory block that is a copy of the passed memory block.
var
Size: LongWord;
Data, NewData: PChar;
begin
Size := GlobalSize(HGlobal);
Result := GlobalAlloc(GPTR, Size);
Data := GlobalLock(hGlobal);
try
NewData := GlobalLock(Result);
try
Move(Data, NewData, Size);
finally
GlobalUnLock(Result);
end
finally
GlobalUnLock(hGlobal)
end
end;
function TCommonDataObject.LoadGlobalBlock(Format: TClipFormat;
var MemoryBlock: Pointer): Boolean;
var
FormatEtc: TFormatEtc;
StgMedium: TStgMedium;
GlobalObject: Pointer;
begin
Result := False;
FormatEtc.cfFormat := Format;
FormatEtc.ptd := nil;
FormatEtc.dwAspect := DVASPECT_CONTENT;
FormatEtc.lindex := -1;
FormatEtc.tymed := TYMED_HGLOBAL;
if Succeeded(QueryGetData(FormatEtc)) and Succeeded(GetData(FormatEtc, StgMedium)) then
begin
MemoryBlock := AllocMem( GlobalSize(StgMedium.hGlobal));
GlobalObject := GlobalLock(StgMedium.hGlobal);
try
if Assigned(MemoryBlock) and Assigned(GlobalObject) then
begin
Move(GlobalObject^, MemoryBlock^, GlobalSize(StgMedium.hGlobal));
end
finally
GlobalUnLock(StgMedium.hGlobal);
end
end;
end;
function TCommonDataObject.QueryGetData(const formatetc: TFormatEtc): HResult;
// This function allows the IDragTarget to see if we can possibly support some
// type of data transfer.
var
i: integer;
FormatAvailable, Handled: Boolean;
begin
Handled := False;
FormatAvailable := False;
DoOnQueryGetData(FormatEtc, FormatAvailable, Handled);
if Handled then
begin
if FormatAvailable then
Result := S_OK
else
Result := DV_E_FORMATETC
end else
begin
if not FormatAvailable then
begin
if Assigned(Formats) then
begin
i := 0;
Result := DV_E_FORMATETC;
while (i < Length(Formats)) and (Result = DV_E_FORMATETC) do
begin
if Formats[i].FormatEtc.cfFormat = formatetc.cfFormat then
begin
if (Formats[i].FormatEtc.dwAspect = formatetc.dwAspect) then
begin
if (Formats[i].FormatEtc.tymed and formatetc.tymed <> 0) then
Result := S_OK
else
Result := DV_E_TYMED;
end else
Result := DV_E_DVASPECT;
end else
Result := DV_E_FORMATETC;
Inc(i)
end
end else
Result := E_UNEXPECTED;
end else
Result := S_OK
end
end;
function TCommonDataObject.RetrieveOwnedStgMedium(Format: TFormatEtc; var StgMedium: TStgMedium): HRESULT;
var
i: integer;
begin
Result := E_INVALIDARG;
i := FindFormatEtc(Format);
if (i > -1) and Formats[i].OwnedByDataObject then
Result := StgMediumIncRef(Formats[i].StgMedium, StgMedium, False)
end;
function TCommonDataObject.SaveGlobalBlock(Format: TClipFormat;
MemoryBlock: Pointer; MemoryBlockSize: integer): Boolean;
var
FormatEtc: TFormatEtc;
StgMedium: TStgMedium;
GlobalObject: Pointer;
begin
FormatEtc.cfFormat := Format;
FormatEtc.ptd := nil;
FormatEtc.dwAspect := DVASPECT_CONTENT;
FormatEtc.lindex := -1;
FormatEtc.tymed := TYMED_HGLOBAL;
StgMedium.tymed := TYMED_HGLOBAL;
StgMedium.unkForRelease := nil;
StgMedium.hGlobal := GlobalAlloc(GHND or GMEM_SHARE, MemoryBlockSize);
GlobalObject := GlobalLock(StgMedium.hGlobal);
try
try
Move(MemoryBlock^, GlobalObject^, MemoryBlockSize);
Result := Succeeded( SetData(FormatEtc, StgMedium, True))
except
Result := False;
end
finally
GlobalUnLock(StgMedium.hGlobal);
end
end;
function TCommonDataObject.SetData(const formatetc: TFormatEtc; var medium: TStgMedium; fRelease: BOOL): HResult;
// Allows dynamic adding to the IDataObject during its existance. Most noteably
// it is used to implement IDropSourceHelper in win2k
var
Index: integer;
begin
// See if we already have a format of that type available.
Index := FindFormatEtc(FormatEtc);
if Index > - 1 then
begin
// Yes we already have that format type stored. Just use the TCommonClipboardFormat
// in the List after releasing the data
ReleaseStgMedium(Formats[Index].StgMedium);
FillChar(Formats[Index].StgMedium, SizeOf(Formats[Index].StgMedium), #0);
end else
begin
// It is a new format so create a new TDataObjectInfo record and store it in
// the Format array
SetLength(FFormats, Length(Formats) + 1);
Formats[Length(Formats) - 1].FormatEtc := FormatEtc;
Index := Length(Formats) - 1;
end;
// The data is owned by the TCommonClipboardFormat object
Formats[Index].OwnedByDataObject := True;
if fRelease then
begin
// We are simply being given the data and we take control of it.
Formats[Index].StgMedium := Medium;
Result := S_OK
end else
// We need to reference count or copy the data and keep our own references
// to it.
Result := StgMediumIncRef(Medium, Formats[Index].StgMedium, True);
// Can get a circular reference if the client calls GetData then calls
// SetData with the same StgMedium. Because the unkForRelease and for
// the IDataObject can be marshalled it is necessary to get pointers that
// can be correctly compared.
// See the IDragSourceHelper article by Raymond Chen at MSDN.
if Assigned(Formats[Index].StgMedium.unkForRelease) then
begin
if CanonicalIUnknown(Self) =
CanonicalIUnknown(IUnknown( Formats[Index].StgMedium.unkForRelease)) then
begin
IUnknown( Formats[Index].StgMedium.unkForRelease)._Release;
Formats[Index].StgMedium.unkForRelease := nil
end;
end;
// Tell all registered advice sinks about the data change.
if Assigned(AdviseHolder) then
AdviseHolder.SendOnDataChange(Self as IDataObject, 0, 0);
end;
function TCommonDataObject.StgMediumIncRef(const InStgMedium: TStgMedium;
var OutStgMedium: TStgMedium; CopyInMedium: Boolean): HRESULT;
// This function increases the reference count of the passed StorageMedium in a
// variety of ways depending on the value of CopyInMedium.
// InStgMedium is the data that is requested a copy of, OutStgMedium is the data that
// we are to return either a copy of or increase the IDataObject's reference and
// send ourselves back as the data (unkForRelease). The InStgMedium is usually
// the result of a call to find a particular FormatEtc that has been stored
// locally through a call to SetData. If CopyInMedium is not true we
// already have a local copy of the data when the SetData function was called
// (during that call the CopyInMedium must be true). Then as the caller asks
// for the data through GetData we do not have to make copy of the data for the
// caller only to have them destroy it then need us to copy it again if
// necessary. This way we increase the reference count to ourselves and pass
// the STGMEDIUM structure initially stored in SetData. This way when the
// caller frees the structure it sees the unkForRelease is not nil and calls
// Release on the object instead of destroying the actual data.
begin
Result := S_OK;
// Simply copy all fields to start with.
OutStgMedium := InStgMedium;
case InStgMedium.tymed of
TYMED_HGLOBAL:
begin
if CopyInMedium then
begin
// Generate a unique copy of the data passed
OutStgMedium.hGlobal := HGlobalClone(InStgMedium.hGlobal);
if OutStgMedium.hGlobal = 0 then
Result := E_OUTOFMEMORY
end else
// Don't generate a copy just use ourselves and the copy previoiusly saved
OutStgMedium.unkForRelease := Pointer(Self as IDataObject) // Does increase RefCount
end;
TYMED_FILE:
begin
if CopyInMedium then
begin
OutStgMedium.lpszFileName := CoTaskMemAlloc(lstrLenW(InStgMedium.lpszFileName));
MoveMemory(PWideChar(OutStgMedium.lpszFileName), PWideChar(InStgMedium.lpszFileName), lstrlenW(InStgMedium.lpszFileName) * 2);
end else
OutStgMedium.unkForRelease := Pointer(Self as IDataObject) // Does increase RefCount
end;
TYMED_ISTREAM:
// Simply increase the reference so the stream object
// Note here stm is a pointer to the auto reference counting won't work and
// we have to call _AddRef explicitly
IUnknown( OutStgMedium.stm)._AddRef;
TYMED_ISTORAGE:
// Simply increase the reference so the storage object
// Note here stm is a pointer to the auto reference counting won't work and
// we have to call _AddRef explicitly
IUnknown( OutStgMedium.stg)._AddRef;
TYMED_GDI:
if not CopyInMedium then
// Don't generate a copy just use ourselves and the copy previoiusly saved data
OutStgMedium.unkForRelease := Pointer(Self as IDataObject) // Does not increase RefCount
else
Result := DV_E_TYMED; // Don't know how to copy GDI objects right now
TYMED_MFPICT:
if not CopyInMedium then
OutStgMedium.unkForRelease := Pointer(Self as IDataObject) // Does not increase RefCount
else
Result := DV_E_TYMED; // Don't know how to copy MetaFile objects right now
TYMED_ENHMF:
if not CopyInMedium then
{ Don't generate a copy just use ourselves and the copy previoiusly saved data }
OutStgMedium.unkForRelease := Pointer(Self as IDataObject) // Does not increase RefCount
else
Result := DV_E_TYMED; // Don't know how to copy enhanced metafiles objects right now
else
Result := DV_E_TYMED
end;
// I still have to do this. The Compiler will call _Release on the above Self as IDataObject
// casts which is not what is necessary. The DataObject is released correctly.
if Assigned(OutStgMedium.unkForRelease) and (Result = S_OK) then
IUnknown(OutStgMedium.unkForRelease)._AddRef
end;
{ TFileGroupDescriptorA }
procedure TFileGroupDescriptorA.AddFileDescriptor(
FileDescriptor: TFileDescriptorA);
begin
SetLength(FFileDescriptors, Length(FFileDescriptors) + 1);
FFileDescriptors[Length(FFileDescriptors) - 1] := FileDescriptor;
end;
procedure TFileGroupDescriptorA.DeleteFileDescriptor(Index: integer);
var
i: Integer;
begin
for i := Index to Length(FFileDescriptors) - 1 do
FileDescriptor[i] := FileDescriptor[i+1];
SetLength(FFileDescriptors, Length(FFileDescriptors) - 1);
end;
function TFileGroupDescriptorA.FillDescriptor(FileName: string): TFileDescriptorA;
begin
FillChar(Result, SizeOf(Result), #0);
StrCopy(Result.cFileName, PChar(FileName));
end;
function TFileGroupDescriptorA.GetDescriptorCount: Integer;
begin
Result := Length(FFileDescriptors)
end;
function TFileGroupDescriptorA.GetFileDescriptorA(Index: Integer): TFileDescriptorA;
begin
FillChar(Result, SizeOf(Result), #0);
if (Index > -1) and (Index < Length(FFileDescriptors)) then
Result := FFileDescriptors[Index]
end;
function TFileGroupDescriptorA.GetFileStream(const DataObject: IDataObject;
FileIndex: Integer): TStream;
var
Format: TFormatEtc;
Medium: TStgMedium;
begin
if Assigned(Stream) then
FreeAndNil(FStream);
if Assigned(DataObject) and (FileIndex > 0) and (FileIndex < DescriptorCount) then
begin
Format.cfFormat := CF_FILECONTENTS;
Format.ptd := nil;
Format.dwAspect := DVASPECT_CONTENT;
Format.lindex := FileIndex;
Format.tymed := TYMED_ISTREAM;
if Succeeded(DataObject.GetData(Format, Medium)) then
begin
Stream := TOLEStream.Create(IStream(Medium.stm));
ReleaseStgMedium(Medium);
end
end;
Result := Stream;
end;
function TFileGroupDescriptorA.GetFormatEtc: TFormatEtc;
begin
Result := FileDescriptorAFormat
end;
procedure TFileGroupDescriptorA.LoadFileGroupDestriptor(FileGroupDiscriptor: PFileGroupDescriptorA);
var
i: Cardinal;
begin
if Assigned(FileGroupDiscriptor) then
begin
SetLength(FFileDescriptors, FileGroupDiscriptor.cItems);
for i := 0 to FileGroupDiscriptor.cItems - 1 do
begin
FFileDescriptors[i] := FileGroupDiscriptor.fgd[i]
end
end else
FFileDescriptors := nil;
end;
function TFileGroupDescriptorA.LoadFromClipboard: Boolean;
var
DataObject: IDataObject;
begin
Result := False;
if Succeeded(OleGetClipboard(DataObject)) then
Result := LoadFromDataObject(DataObject);
end;
function TFileGroupDescriptorA.LoadFromDataObject(DataObject: IDataObject): Boolean;
var
GroupDescriptor: PFileGroupDescriptorA;
Medium: TStgMedium;
i: Integer;
begin
Result := False;
if Succeeded(DataObject.GetData(GetFormatEtc, Medium)) then
begin
GroupDescriptor := GlobalLock(Medium.hGlobal);
try
for i := 0 to GroupDescriptor^.cItems - 1 do
AddFileDescriptor(GroupDescriptor^.fgd[i])
finally
GlobalUnlock(Medium.hGlobal);
ReleaseStgMedium(Medium);
Result := True
end
end
end;
function TFileGroupDescriptorA.SaveToClipboard: Boolean;
var
DataObject: IDataObject;
begin
Result := False;
DataObject := TCommonDataObject.Create;
if SaveToDataObject(DataObject) then
Result := Succeeded(OleSetClipboard(DataObject))
end;
function TFileGroupDescriptorA.SaveToDataObject(DataObject: IDataObject): Boolean;
var
Mem: THandle;
GroupDescriptor: PFileGroupDescriptorA;
Medium: TStgMedium;
Format: TFormatEtc;
begin
Result := False;
if Assigned(DataObject) and (DescriptorCount > 0) then
begin
Mem := GlobalAlloc(GHND, DescriptorCount * SizeOf(TFileDescriptorA) + SizeOf(GroupDescriptor.cItems));
GroupDescriptor := GlobalLock(Mem);
try
GroupDescriptor.cItems := DescriptorCount;
CopyMemory(@GroupDescriptor^.fgd[0], @FFileDescriptors[0], DescriptorCount * SizeOf(TFileDescriptorA));
finally
GlobalUnlock(Mem)
end;
FillChar(Medium, SizeOf(Medium), #0);
Medium.tymed := TYMED_HGLOBAL;
Medium.hGlobal := Mem;
DataObject.SetData(GetFormatEtc, Medium, True);
Medium.tymed := TYMED_ISTREAM;
Medium.stm := nil;
Format.cfFormat := CF_FILECONTENTS;
Format.ptd := nil;
Format.dwAspect := DVASPECT_CONTENT;
Format.lindex := -1;
Format.tymed := TYMED_ISTREAM;
DataObject.SetData(Format, Medium, True);
end
end;
procedure TFileGroupDescriptorA.SetFileDescriptor(Index: Integer; const Value: TFileDescriptorA);
begin
if (Index > -1) and (Index < Length(FFileDescriptors)) then
FFileDescriptors[Index] := Value
end;
{ TFileGroupDescriptorW }
procedure TFileGroupDescriptorW.AddFileDescriptor(
FileDescriptor: TFileDescriptorW);
begin
SetLength(FFileDescriptors, Length(FFileDescriptors) + 1);
FFileDescriptors[Length(FFileDescriptors) - 1] := FileDescriptor;
end;
procedure TFileGroupDescriptorW.DeleteFileDescriptor(Index: integer);
var
i: Integer;
begin
for i := Index to Length(FFileDescriptors) - 1 do
FileDescriptor[i] := FileDescriptor[i+1];
SetLength(FFileDescriptors, Length(FFileDescriptors) - 1);
end;
function TFileGroupDescriptorW.FillDescriptor(FileName: WideString): TFileDescriptorW;
begin
FillChar(Result, SizeOf(Result), #0);
StrCopyW(Result.cFileName, PWideChar(FileName));
end;
function TFileGroupDescriptorW.GetDescriptorCount: Integer;
begin
Result := Length(FFileDescriptors)
end;
function TFileGroupDescriptorW.GetFileDescriptorW(Index: Integer): TFileDescriptorW;
begin
FillChar(Result, SizeOf(Result), #0);
if (Index > -1) and (Index < Length(FFileDescriptors)) then
Result := FFileDescriptors[Index]
end;
function TFileGroupDescriptorW.GetFileStream(const DataObject: IDataObject; FileIndex: Integer): TStream;
var
Format: TFormatEtc;
Medium: TStgMedium;
begin
if Assigned(Stream) then
FreeAndNil(FStream);
if Assigned(DataObject) and (FileIndex > -1) and (FileIndex < DescriptorCount) then
begin
Format.cfFormat := CF_FILECONTENTS;
Format.ptd := nil;
Format.dwAspect := DVASPECT_CONTENT;
Format.lindex := FileIndex;
Format.tymed := TYMED_ISTREAM;
if Succeeded(DataObject.GetData(Format, Medium)) then
begin
Stream := TOLEStream.Create(IStream(Medium.stm));
ReleaseStgMedium(Medium);
end;
end;
Result := Stream;
end;
function TFileGroupDescriptorW.GetFormatEtc: TFormatEtc;
begin
Result := FileDescriptorWFormat
end;
procedure TFileGroupDescriptorW.LoadFileGroupDestriptor(FileGroupDiscriptor: PFileGroupDescriptorW);
var
i: Cardinal;
begin
if Assigned(FileGroupDiscriptor) then
begin
SetLength(FFileDescriptors, FileGroupDiscriptor.cItems);
for i := 0 to FileGroupDiscriptor.cItems - 1 do
begin
FFileDescriptors[i] := FileGroupDiscriptor.fgd[i]
end
end else
FFileDescriptors := nil;
end;
function TFileGroupDescriptorW.LoadFromClipboard: Boolean;
var
DataObject: IDataObject;
begin
Result := False;
if Succeeded(OleGetClipboard(DataObject)) then
Result := LoadFromDataObject(DataObject);
end;
function TFileGroupDescriptorW.LoadFromDataObject(DataObject: IDataObject): Boolean;
var
GroupDescriptor: PFileGroupDescriptorW;
Medium: TStgMedium;
i: Integer;
begin
Result := False;
if Succeeded(DataObject.GetData(GetFormatEtc, Medium)) then
begin
GroupDescriptor := GlobalLock(Medium.hGlobal);
try
for i := 0 to GroupDescriptor^.cItems - 1 do
AddFileDescriptor(GroupDescriptor^.fgd[i])
finally
GlobalUnlock(Medium.hGlobal);
ReleaseStgMedium(Medium);
Result := True;
end
end
end;
function TFileGroupDescriptorW.SaveToClipboard: Boolean;
var
DataObject: IDataObject;
begin
Result := False;
DataObject := TCommonDataObject.Create;
if SaveToDataObject(DataObject) then
Result := Succeeded(OleSetClipboard(DataObject))
end;
function TFileGroupDescriptorW.SaveToDataObject(DataObject: IDataObject): Boolean;
var
Mem: THandle;
GroupDescriptor: PFileGroupDescriptorW;
Medium: TStgMedium;
Format: TFormatEtc;
begin
Result := False;
if Assigned(DataObject) and (DescriptorCount > 0) then
begin
Mem := GlobalAlloc(GHND, DescriptorCount * SizeOf(TFileDescriptorW) + SizeOf(GroupDescriptor.cItems));
GroupDescriptor := GlobalLock(Mem);
try
GroupDescriptor.cItems := DescriptorCount;
CopyMemory(@GroupDescriptor^.fgd[0], @FFileDescriptors[0], DescriptorCount * SizeOf(TFileDescriptorW));
finally
GlobalUnlock(Mem)
end;
FillChar(Medium, SizeOf(Medium), #0);
Medium.tymed := TYMED_HGLOBAL;
Medium.hGlobal := Mem;
DataObject.SetData(GetFormatEtc, Medium, True);
Medium.tymed := TYMED_ISTREAM;
Medium.stm := nil;
Format.cfFormat := CF_FILECONTENTS;
Format.ptd := nil;
Format.dwAspect := DVASPECT_CONTENT;
Format.lindex := -1;
Format.tymed := TYMED_ISTREAM;
DataObject.SetData(Format, Medium, True);
end
end;
procedure TFileGroupDescriptorW.SetFileDescriptor(Index: Integer; const Value: TFileDescriptorW);
begin
if (Index > -1) and (Index < Length(FFileDescriptors)) then
FFileDescriptors[Index] := Value
end;
{ TCommonInShellDragLoop }
function TCommonInShellDragLoop.GetFormatEtc: TFormatEtc;
begin
Result.cfFormat := CF_INDRAGLOOP;
Result.ptd := nil;
Result.dwAspect := DVASPECT_CONTENT;
Result.lindex := -1;
Result.tymed := TYMED_HGLOBAL
end;
function TCommonInShellDragLoop.LoadFromDataObject(DataObject: IDataObject): Boolean;
var
StgMedium: TStgMedium;
DataPtr: PCardinal;
begin
Result := False;
FillChar(StgMedium, SizeOf(StgMedium), #0);
if Succeeded(DataObject.GetData(GetFormatEtc, StgMedium)) then
try
DataPtr := GlobalLock(StgMedium.hGlobal);
try
if Assigned(DataPtr) then
begin
Data := DataPtr^;
Result := True;
end;
finally
GlobalUnLock(StgMedium.hGlobal);
end
finally
ReleaseStgMedium(StgMedium)
end
end;
function TCommonInShellDragLoop.SaveToDataObject(DataObject: IDataObject): Boolean;
var
StgMedium: TStgMedium;
Ptr: PCardinal;
begin
FillChar(StgMedium, SizeOf(StgMedium), #0);
StgMedium.hGlobal := GlobalAlloc(GPTR, SIZE_SHELLDRAGLOOPDATA);
Ptr := GlobalLock(StgMedium.hGlobal);
try
StgMedium.tymed := TYMED_HGLOBAL;
Ptr^ := FData;
Result := Succeeded(DataObject.SetData(GetFormatEtc, StgMedium, True))
finally
GlobalUnLock(StgMedium.hGlobal);
end
end;
initialization
CF_SHELLIDLIST := RegisterClipboardFormat(CFSTR_SHELLIDLIST);
CF_LOGICALPERFORMEDDROPEFFECT := RegisterClipboardFormat(CFSTR_LOGICALPERFORMEDDROPEFFECT);
CF_PREFERREDDROPEFFECT := RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
CF_PERFORMEDDROPEFFECT := RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
CF_PASTESUCCEEDED := RegisterClipboardFormat(CFSTR_PASTESUCCEEDED);
CF_INDRAGLOOP := RegisterClipboardFormat(CFSTR_INDRAGLOOP);
CF_SHELLIDLISTOFFSET := RegisterClipboardFormat(CFSTR_SHELLIDLISTOFFSET);
CF_FILECONTENTS := RegisterClipboardFormat(CFSTR_FILECONTENTS);
CF_FILEDESCRIPTORA := RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
CF_FILEDESCRIPTORW := RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
PIDLMgr := TCommonPIDLManager.Create;
finalization
PIDLMgr.Free;
end.