Subversion Repositories decoder

Compare Revisions

No changes between revisions

Regard whitespace Rev 1 → Rev 2

/trunk/VCL_DRAGDROP/DragDrop.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDrop.inc
0,0 → 1,135
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Module: DragDrop.inc
// Description: This include file contains common defines used by the
// library.
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2000 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
 
// -----------------------------------------------------------------------------
// Detect compiler version
// -----------------------------------------------------------------------------
 
// Delphi 1.x
{$IFDEF VER80}
{$DEFINE VER8_PLUS}
{$DEFINE VER_OK}
{$ENDIF}
 
// Delphi 2.x
{$IFDEF VER90}
{$DEFINE VER9x}
{$DEFINE VER9_PLUS}
{$DEFINE VER_OK}
{$ENDIF}
 
// C++ Builder 1.x
{$IFDEF VER93}
{$DEFINE VER9x}
{$DEFINE VER93_PLUS}
{$DEFINE VER_OK}
{$ENDIF}
 
// Delphi 3.x
{$IFDEF VER100}
{$DEFINE VER10_PLUS}
{$DEFINE VER_OK}
{$ENDIF}
 
// C++ Builder 3.x
{$IFDEF VER110}
{$DEFINE VER11_PLUS}
{$DEFINE VER_OK}
{$ENDIF}
 
// Delphi 4.x
{$IFDEF VER120}
{$DEFINE VER12_PLUS}
{$DEFINE VER_OK}
{$ENDIF}
 
// C++ Builder 4.x
{$IFDEF VER125}
{$DEFINE VER125_PLUS}
{$DEFINE VER_OK}
{$ENDIF}
 
// Delphi 5.x
{$IFDEF VER130}
{$DEFINE VER13_PLUS}
{$DEFINE VER_OK}
{$ENDIF}
 
// C++ Builder 5.x - Not verified!
{$IFDEF VER130}
{$IFDEF BCB}
{$DEFINE VER135_PLUS}
{$DEFINE VER_OK}
{$ENDIF}
{$ENDIF}
 
// Delphi 6.x
{$IFDEF VER140}
{$DEFINE VER14_PLUS}
{$DEFINE VER_OK}
{$ENDIF}
 
// Unknown compiler version - assume D6 compatible
{$IFNDEF VER_OK}
{$DEFINE VER14_PLUS}
{$ELSE}
{$UNDEF VER_OK}
{$ENDIF}
 
{$IFDEF VER14_PLUS}
{$DEFINE VER135_PLUS}
{$ENDIF}
{$IFDEF VER135_PLUS}
{$DEFINE VER13_PLUS}
{$ENDIF}
{$IFDEF VER13_PLUS}
{$DEFINE VER125_PLUS}
{$ENDIF}
{$IFDEF VER125_PLUS}
{$DEFINE VER12_PLUS}
{$ENDIF}
{$IFDEF VER12_PLUS}
{$DEFINE VER11_PLUS}
{$ENDIF}
{$IFDEF VER11_PLUS}
{$DEFINE VER10_PLUS}
{$ENDIF}
{$IFDEF VER10_PLUS}
{$DEFINE VER93_PLUS}
{$ENDIF}
{$IFDEF VER93_PLUS}
{$DEFINE VER9_PLUS}
{$ENDIF}
{$IFDEF VER9_PLUS}
{$DEFINE VER8_PLUS}
{$ENDIF}
 
 
// -----------------------------------------------------------------------------
// Required compiler directives
// -----------------------------------------------------------------------------
 
{$BOOLEVAL OFF} // Short circuit boolean evaluation.
{$EXTENDEDSYNTAX ON} // Enable Delphi Pascal extensions.
{$LONGSTRINGS ON} // String = AnsiString.
{$ALIGN ON} // Aligned data. Required by COM.
{$ifdef BCB}
{$ObjExportAll ON} // Required for C++ Builder
{$endif}
 
// The following are not realy nescessary, but they are good practice.
{$TYPEDADDRESS ON} // @ operator returns typed pointer.
{$WRITEABLECONST OFF} // Typed consts are R/O.
 
// Disable platform warnings. This library is only supported on Windows.
{$ifdef VER14_PLUS}
{$WARN SYMBOL_PLATFORM OFF}
{$endif}
 
/trunk/VCL_DRAGDROP/DragDrop.pas
0,0 → 1,1958
unit DragDrop;
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Module: DragDrop
// Description: Implements base classes and utility functions.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
// TODO -oanme -cPortability : Replace all public use of HWND with THandle. BCB's HWND <> Delphi's HWND.
{$include DragDrop.inc}
 
interface
 
uses
Classes,
Windows,
ActiveX;
 
{$IFDEF BCB}
{$HPPEMIT '#ifndef NO_WIN32_LEAN_AND_MEAN'}
{$HPPEMIT '"Error: The NO_WIN32_LEAN_AND_MEAN symbol must be defined in your projects conditional defines"'}
{$HPPEMIT '#endif'}
{$ENDIF}
 
 
const
DROPEFFECT_NONE = ActiveX.DROPEFFECT_NONE;
DROPEFFECT_COPY = ActiveX.DROPEFFECT_COPY;
DROPEFFECT_MOVE = ActiveX.DROPEFFECT_MOVE;
DROPEFFECT_LINK = ActiveX.DROPEFFECT_LINK;
DROPEFFECT_SCROLL = ActiveX.DROPEFFECT_SCROLL;
 
type
// TDragType enumerates the three possible drag/drop operations.
TDragType = (dtCopy, dtMove, dtLink);
TDragTypes = set of TDragType;
 
type
// TDataDirection is used by the clipboard format registration to specify
// if the clipboard format should be listed in get (read) format enumerations,
// set (write) format enumerations or both.
// ddRead : Destination (IDropTarget) can read data from IDataObject.
// ddWrite : Destination (IDropTarget) can write data to IDataObject.
TDataDirection = (ddRead, ddWrite);
TDataDirections = set of TDataDirection;
 
const
ddReadWrite = [ddRead, ddWrite];
 
type
// TConversionScope is used by the clipboard format registration to specify
// if a clipboard format conversion is supported by the drop source, the drop
// target or both.
// ddSource : Conversion is valid for drop source (IDropSource).
// ddTarget : Conversion is valid for drop target (IDropTarget).
TConversionScope = (csSource, csTarget);
TConversionScopes = set of TConversionScope;
 
const
csSourceTarget = [csSource, csTarget];
 
// C++ Builder's declaration of IEnumFORMATETC is incorrect, so we must generate
// the typedef for C++ Builder.
{$IFDEF BCB}
{$HPPEMIT 'typedef System::DelphiInterface<IEnumFORMATETC> _di_IEnumFORMATETC;' }
{$ENDIF}
 
////////////////////////////////////////////////////////////////////////////////
//
// TInterfacedComponent
//
////////////////////////////////////////////////////////////////////////////////
// Top level base class for the drag/drop component hierachy.
// Implements the IUnknown interface.
// Corresponds to TInterfacedObject (see VCL on-line help), but descends from
// TComponent instead of TObject.
// Reference counting is disabled (_AddRef and _Release methods does nothing)
// since the component life span is controlled by the component owner.
////////////////////////////////////////////////////////////////////////////////
type
TInterfacedComponent = class(TComponent, IUnknown)
protected
function QueryInterface(const IID: TGuid; out Obj): HRESULT;
{$IFDEF VER13_PLUS} override; {$ELSE}
{$IFDEF VER12_PLUS} reintroduce; {$ENDIF}{$ENDIF} stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Abstract base class. Extracts or injects data of a specific low level format
// from or to an IDataObject.
////////////////////////////////////////////////////////////////////////////////
type
TCustomDataFormat = class;
 
TClipboardFormat = class(TObject)
private
FDataDirections: TDataDirections;
FDataFormat: TCustomDataFormat;
protected
FFormatEtc: TFormatEtc;
constructor CreateFormat(Atymed: Longint); virtual;
constructor CreateFormatEtc(const AFormatEtc: TFormatEtc); virtual;
{ Extracts data from the specified medium }
function DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean; virtual;
{ Transfer data to the specified medium }
function DoSetData(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean; virtual;
function GetClipboardFormat: TClipFormat; virtual;
procedure SetClipboardFormat(Value: TClipFormat); virtual;
function GetClipboardFormatName: string; virtual;
procedure SetClipboardFormatName(const Value: string); virtual;
procedure SetFormatEtc(const Value: TFormatEtc);
public
constructor Create; virtual; abstract;
destructor Destroy; override;
{ Determines if the object can read from the specified data object }
function HasValidFormats(ADataObject: IDataObject): boolean; virtual;
{ Determines if the object can read the specified format }
function AcceptFormat(const AFormatEtc: TFormatEtc): boolean; virtual;
{ Extracts data from the specified IDataObject }
function GetData(ADataObject: IDataObject): boolean; virtual;
{ Extracts data from the specified IDataObject via the specified medium }
function GetDataFromMedium(ADataObject: IDataObject;
var AMedium: TStgMedium): boolean; virtual;
{ Transfers data to the specified IDataObject }
function SetData(ADataObject: IDataObject; const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean; virtual;
{ Transfers data to the specified medium }
function SetDataToMedium(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean;
{ Copies data from the specified source format to the object }
function Assign(Source: TCustomDataFormat): boolean; virtual;
{ Copies data from the object to the specified target format }
function AssignTo(Dest: TCustomDataFormat): boolean; virtual;
{ Clears the objects data }
procedure Clear; virtual; abstract;
{ Returns true if object can supply data }
function HasData: boolean; virtual;
{ Unregisters the clipboard format and all mappings involving it from the global database }
class procedure UnregisterClipboardFormat;
{ Returns the clipboard format value }
property ClipboardFormat: TClipFormat read GetClipboardFormat
write SetClipboardFormat;
{ Returns the clipboard format name }
property ClipboardFormatName: string read GetClipboardFormatName
write SetClipboardFormatName;
{ Provides access to the objects format specification }
property FormatEtc: TFormatEtc read FFormatEtc;
{ Specifies whether the format can read and write data }
property DataDirections: TDataDirections read FDataDirections
write FDataDirections;
{ Specifies the data format which owns and controls this clipboard format }
property DataFormat: TCustomDataFormat read FDataFormat write FDataFormat;
end;
 
TClipboardFormatClass = class of TClipboardFormat;
 
// TClipboardFormats
// List of TClipboardFormat objects.
TClipboardFormats = class(TObject)
private
FList: TList;
FOwnsObjects: boolean;
FDataFormat: TCustomDataFormat;
protected
function GetFormat(Index: integer): TClipboardFormat;
function GetCount: integer;
public
constructor Create(ADataFormat: TCustomDataFormat; AOwnsObjects: boolean);
destructor Destroy; override;
procedure Clear;
function Add(ClipboardFormat: TClipboardFormat): integer;
function Contain(ClipboardFormatClass: TClipboardFormatClass): boolean;
function FindFormat(ClipboardFormatClass: TClipboardFormatClass): TClipboardFormat;
property Formats[Index: integer]: TClipboardFormat read GetFormat; default;
property Count: integer read GetCount;
property DataFormat: TCustomDataFormat read FDataFormat;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDragDropComponent
//
////////////////////////////////////////////////////////////////////////////////
// Base class for drag/drop components.
////////////////////////////////////////////////////////////////////////////////
TDataFormats = class;
 
TDragDropComponent = class(TInterfacedComponent)
private
protected
FDataFormats: TDataFormats;
//: Only used by TCustomDropMultiSource and TCustomDropMultiTarget and
// their descendants.
property DataFormats: TDataFormats read FDataFormats;
public
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomFormat
//
////////////////////////////////////////////////////////////////////////////////
// Abstract base class.
// Renders the data of one or more TClipboardFormat objects to or from a
// specific high level data format.
////////////////////////////////////////////////////////////////////////////////
TCustomDataFormat = class(TObject)
private
FCompatibleFormats : TClipboardFormats;
FFormatList : TDataFormats;
FOwner : TDragDropComponent;
FOnChanging : TNotifyEvent;
protected
{ Determines if the object can accept data from the specified source format }
function SupportsFormat(ClipboardFormat: TClipboardFormat): boolean;
procedure DoOnChanging(Sender: TObject);
procedure Changing; virtual;
property FormatList: TDataFormats read FFormatList;
public
constructor Create(AOwner: TDragDropComponent); virtual;
destructor Destroy; override;
procedure Clear; virtual; abstract;
{ Copies data between the specified clipboard format to the object }
function Assign(Source: TClipboardFormat): boolean; virtual;
function AssignTo(Dest: TClipboardFormat): boolean; virtual;
{ Extracts data from the specified IDataObject }
function GetData(DataObject: IDataObject): boolean; virtual;
{ Determines if the object contains *any* data }
function HasData: boolean; virtual; abstract;
{ Determines if the object needs/can use *more* data }
function NeedsData: boolean; virtual;
{ Determines if the object can read from the specified data object }
function HasValidFormats(ADataObject: IDataObject): boolean; virtual;
{ Determines if the object can read the specified format }
function AcceptFormat(const FormatEtc: TFormatEtc): boolean; virtual;
{ Registers the data format in the data format list }
class procedure RegisterDataFormat;
{ Registers the specified clipboard format as being compatible with the data format }
class procedure RegisterCompatibleFormat(ClipboardFormatClass: TClipboardFormatClass;
Priority: integer {$ifdef VER12_PLUS} = 0 {$endif};
ConversionScopes: TConversionScopes {$ifdef VER12_PLUS} = csSourceTarget {$endif};
DataDirections: TDataDirections {$ifdef VER12_PLUS} = [ddRead] {$endif});
{ Unregisters the specified clipboard format from the compatibility list }
class procedure UnregisterCompatibleFormat(ClipboardFormatClass: TClipboardFormatClass);
{ Unregisters data format and all mappings involving it from the global database }
class procedure UnregisterDataFormat;
{ List of compatible source formats }
property CompatibleFormats: TClipboardFormats read FCompatibleFormats;
property Owner: TDragDropComponent read FOwner;
property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
// TODO : Add support for delayed rendering with DelayedRender property.
end;
 
// TDataFormats
// List of TCustomDataFormat objects.
TDataFormats = class(TObject)
private
FList: TList;
protected
function GetFormat(Index: integer): TCustomDataFormat;
function GetCount: integer;
public
constructor Create;
destructor Destroy; override;
function Add(DataFormat: TCustomDataFormat): integer; virtual;
function IndexOf(DataFormat: TCustomDataFormat): integer; virtual;
procedure Remove(DataFormat: TCustomDataFormat); virtual;
property Formats[Index: integer]: TCustomDataFormat read GetFormat; default;
property Count: integer read GetCount;
end;
 
// TDataFormatClasses
// List of TCustomDataFormat classes.
TDataFormatClass = class of TCustomDataFormat;
 
TDataFormatClasses = class(TObject)
private
FList: TList;
protected
function GetFormat(Index: integer): TDataFormatClass;
function GetCount: integer;
{ Provides singleton access to the global data format database }
class function Instance: TDataFormatClasses;
public
constructor Create;
destructor Destroy; override;
function Add(DataFormat: TDataFormatClass): integer; virtual;
procedure Remove(DataFormat: TDataFormatClass); virtual;
property Formats[Index: integer]: TDataFormatClass read GetFormat; default;
property Count: integer read GetCount;
end;
 
// TDataFormatMap
// Format conversion database. Contains mappings between TClipboardFormat
// and TCustomDataFormat.
// Used internally by TCustomDropMultiTarget and TCustomDropMultiSource.
TDataFormatMap = class(TObject)
FList: TList;
protected
function FindMap(DataFormatClass: TDataFormatClass; ClipboardFormatClass: TClipboardFormatClass): integer;
procedure Sort;
{ Provides singleton access to the global format map database }
class function Instance: TDataFormatMap;
public
constructor Create;
destructor Destroy; override;
procedure Add(DataFormatClass: TDataFormatClass;
ClipboardFormatClass: TClipboardFormatClass;
Priority: integer {$ifdef VER12_PLUS} = 0 {$endif};
ConversionScopes: TConversionScopes {$ifdef VER12_PLUS} = csSourceTarget {$endif};
DataDirections: TDataDirections {$ifdef VER12_PLUS} = [ddRead] {$endif});
procedure Delete(DataFormatClass: TDataFormatClass;
ClipboardFormatClass: TClipboardFormatClass);
procedure DeleteByClipboardFormat(ClipboardFormatClass: TClipboardFormatClass);
procedure DeleteByDataFormat(DataFormatClass: TDataFormatClass);
procedure GetSourceByDataFormat(DataFormatClass: TDataFormatClass;
ClipboardFormats: TClipboardFormats; ConversionScope: TConversionScope);
function CanMap(DataFormatClass: TDataFormatClass;
ClipboardFormatClass: TClipboardFormatClass): boolean;
 
{ Registers the specified format mapping }
procedure RegisterFormatMap(DataFormatClass: TDataFormatClass;
ClipboardFormatClass: TClipboardFormatClass;
Priority: integer {$ifdef VER12_PLUS} = 0 {$endif};
ConversionScopes: TConversionScopes {$ifdef VER12_PLUS} = csSourceTarget {$endif};
DataDirections: TDataDirections {$ifdef VER12_PLUS} = [ddRead] {$endif});
{ Unregisters the specified format mapping }
procedure UnregisterFormatMap(DataFormatClass: TDataFormatClass;
ClipboardFormatClass: TClipboardFormatClass);
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDataFormatAdapter
//
////////////////////////////////////////////////////////////////////////////////
// Helper component used to add additional data formats to a drop source or
// target at design time.
// Requires that data formats have been registered with
// TCustomDataFormat.RegisterDataFormat.
////////////////////////////////////////////////////////////////////////////////
TDataFormatAdapter = class(TComponent)
private
FDragDropComponent: TDragDropComponent;
FDataFormat: TCustomDataFormat;
FDataFormatClass: TDataFormatClass;
FEnabled: boolean;
function GetDataFormatName: string;
procedure SetDataFormatName(const Value: string);
protected
procedure SetDataFormatClass(const Value: TDataFormatClass);
procedure SetDragDropComponent(const Value: TDragDropComponent);
function GetEnabled: boolean;
procedure SetEnabled(const Value: boolean);
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
procedure Loaded; override;
public
destructor Destroy; override;
property DataFormatClass: TDataFormatClass read FDataFormatClass
write SetDataFormatClass;
property DataFormat: TCustomDataFormat read FDataFormat;
published
property DragDropComponent: TDragDropComponent read FDragDropComponent
write SetDragDropComponent;
property DataFormatName: string read GetDataFormatName
write SetDataFormatName;
property Enabled: boolean read GetEnabled write SetEnabled;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Drag Drop helper interfaces
//
////////////////////////////////////////////////////////////////////////////////
// Requires Windows 2000 or later.
////////////////////////////////////////////////////////////////////////////////
type
PSHDRAGIMAGE = ^TSHDRAGIMAGE;
{_$EXTERNALSYM _SHDRAGIMAGE}
_SHDRAGIMAGE = packed record
sizeDragImage: TSize; { The length and Width of the rendered image }
ptOffset: TPoint; { The Offset from the mouse cursor to the upper left corner of the image }
hbmpDragImage: HBitmap; { The Bitmap containing the rendered drag images }
crColorKey: COLORREF; { The COLORREF that has been blitted to the background of the images }
end;
TSHDRAGIMAGE = _SHDRAGIMAGE;
{_$EXTERNALSYM SHDRAGIMAGE}
SHDRAGIMAGE = _SHDRAGIMAGE;
 
const
CLSID_DragDropHelper: TGUID = (
D1:$4657278a; D2:$411b; D3:$11d2; D4:($83,$9a,$00,$c0,$4f,$d9,$18,$d0));
SID_DragDropHelper = '{4657278A-411B-11d2-839A-00C04FD918D0}';
 
const
IID_IDropTargetHelper: TGUID = (
D1:$4657278b; D2:$411b; D3:$11d2; D4:($83,$9a,$00,$c0,$4f,$d9,$18,$d0));
SID_IDropTargetHelper = '{4657278B-411B-11d2-839A-00C04FD918D0}';
 
type
{_$HPPEMIT 'typedef DragDrop::DelphiInterface<IDropTargetHelper> _di_IDropTargetHelper;'}
{_$EXTERNALSYM IDropTargetHelper}
IDropTargetHelper = interface(IUnknown)
[SID_IDropTargetHelper]
function DragEnter(hwndTarget: HWND; const DataObj: IDataObject;
var pt: TPoint; dwEffect: Longint): HResult; stdcall;
function DragLeave: HResult; stdcall;
function DragOver(var pt: TPoint; dwEffect: longInt): HResult; stdcall;
function Drop(const DataObj: IDataObject; var pt: TPoint;
dwEffect: longInt): HResult; stdcall;
function Show(Show: BOOL): HResult; stdcall;
end;
 
const
IID_IDragSourceHelper: TGUID = (
D1:$de5bf786; D2:$477a; D3:$11d2; D4:($83,$9d,$00,$c0,$4f,$d9,$18,$d0));
SID_IDragSourceHelper = '{DE5BF786-477A-11d2-839D-00C04FD918D0}';
 
type
{_$HPPEMIT 'typedef DragDrop::DelphiInterface<IDragSourceHelper> _di_IDragSourceHelper;'}
{_$EXTERNALSYM IDragSourceHelper}
IDragSourceHelper = interface(IUnknown)
[SID_IDragSourceHelper]
function InitializeFromBitmap(var shdi: TSHDRAGIMAGE;
const DataObj: IDataObject): HResult; stdcall;
function InitializeFromWindow(hwnd: HWND; var pt: TPoint;
const DataObj: IDataObject): HResult; stdcall;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Async data transfer interfaces
//
////////////////////////////////////////////////////////////////////////////////
// Requires Windows 2000 or later.
////////////////////////////////////////////////////////////////////////////////
const
IID_IAsyncOperation: TGUID = (
D1:$3D8B0590; D2:$F691; D3:$11D2; D4:($8E,$A9,$00,$60,$97,$DF,$5B,$D4));
SID_IAsyncOperation = '{3D8B0590-F691-11D2-8EA9-006097DF5BD4}';
 
type
{_$HPPEMIT 'typedef DragDrop::DelphiInterface<IAsyncOperation> _di_IAsyncOperation;'}
{_$EXTERNALSYM IAsyncOperation}
IAsyncOperation = interface(IUnknown)
[SID_IAsyncOperation]
function SetAsyncMode(fDoOpAsync: BOOL): HResult; stdcall;
function GetAsyncMode(out fDoOpAsync: BOOL): HResult; stdcall;
function StartOperation(const pbcReserved: IBindCtx): HResult; stdcall;
function InOperation(out pfInAsyncOp: BOOL): HResult; stdcall;
function EndOperation(hResult: HRESULT; const pbcReserved: IBindCtx;
dwEffects: DWORD): HResult; stdcall;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TRawClipboardFormat & TRawDataFormat
//
////////////////////////////////////////////////////////////////////////////////
// These clipboard and data format classes are special in that they don't
// interpret the data in any way.
// Their primary purpose is to enable the TCustomDropMultiSource class to accept
// and store arbitrary (and unknown) data types. This is a requirement for
// drag drop helper object support.
////////////////////////////////////////////////////////////////////////////////
// The TRawDataFormat class does not perform any storage of data itself. Instead
// it relies on the TRawClipboardFormat objects to store data.
////////////////////////////////////////////////////////////////////////////////
TRawDataFormat = class(TCustomDataFormat)
private
FMedium: TStgMedium;
protected
public
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property Medium: TStgMedium read FMedium write FMedium;
end;
 
TRawClipboardFormat = class(TClipboardFormat)
private
FMedium: TStgMedium;
protected
function DoGetData(ADataObject: IDataObject;
const AMedium: TStgMedium): boolean; override;
function DoSetData(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean; override;
procedure SetClipboardFormatName(const Value: string); override;
function GetClipboardFormat: TClipFormat; override;
function GetString: string;
procedure SetString(const Value: string);
public
constructor Create; override;
constructor CreateFormatEtc(const AFormatEtc: TFormatEtc); override;
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
procedure Clear; override;
// Methods to handle the corresponding TRawDataFormat functioinality.
procedure ClearData;
function HasData: boolean; override;
function NeedsData: boolean;
 
// All of these should be moved/mirrored in TRawDataFormat:
procedure CopyFromStgMedium(const AMedium: TStgMedium);
procedure CopyToStgMedium(var AMedium: TStgMedium);
property AsString: string read GetString write SetString;
property Medium: TStgMedium read FMedium write FMedium;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Utility functions
//
////////////////////////////////////////////////////////////////////////////////
function DropEffectToDragType(DropEffect: longInt; var DragType: TDragType): boolean;
function DragTypesToDropEffect(DragTypes: TDragTypes): longint; // V4: New
 
// Coordinate space conversion.
function ClientPtToWindowPt(Handle: THandle; pt: TPoint): TPoint;
 
// Replacement for KeysToShiftState.
function KeysToShiftStatePlus(Keys: Word): TShiftState; // V4: New
function ShiftStateToDropEffect(Shift: TShiftState; AllowedEffects: longint;
Fallback: boolean): longint;
 
// Replacement for the buggy DragDetect API function.
function DragDetectPlus(Handle: THandle; p: TPoint): boolean; // V4: New
 
// Wrapper for urlmon.CopyStgMedium.
// Note: Only works with IE4 or later installed.
function CopyStgMedium(const SrcMedium: TStgMedium; var DstMedium: TStgMedium): boolean;
 
// Get the name of a clipboard format as a Delphi string.
function GetClipboardFormatNameStr(Value: TClipFormat): string;
 
// Raise last Windows API error as an exception.
procedure _RaiseLastWin32Error;
 
////////////////////////////////////////////////////////////////////////////////
//
// Global variables
//
////////////////////////////////////////////////////////////////////////////////
var
ShellMalloc: IMalloc;
 
// Name of the IDE component palette page the drag drop components are
// registered to
var
DragDropComponentPalettePage: string = 'DragDrop';
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc drop target related constants
//
////////////////////////////////////////////////////////////////////////////////
// Drag Drop constants from ActiveX unit
var
// Default inset-width of the auto scroll hot zone.
// Specified in pixels.
// Not used! Instead the height of the target control's font is used.
DragDropScrollInset: integer = DD_DEFSCROLLINSET; // 11
 
// Default delay after entering the scroll zone, before scrolling starts.
// Specified in milliseconds.
DragDropScrollDelay: integer = DD_DEFSCROLLDELAY; // 50
 
// Default scroll interval during auto scroll.
// Specified in milliseconds.
DragDropScrollInterval: integer = DD_DEFSCROLLINTERVAL; // 50
 
// Default delay before dragging should start.
// Specified in milliseconds.
DragDropDragDelay: integer = DD_DEFDRAGDELAY; // 200
 
// Default minimum distance (radius) before dragging should start.
// Specified in pixels.
// Not used! Instead the SM_CXDRAG and SM_CYDRAG system metrics are used.
DragDropDragMinDistance: integer = DD_DEFDRAGMINDIST; // 2
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc drag drop API related constants
//
////////////////////////////////////////////////////////////////////////////////
 
// The following DVASPECT constants are missing from some versions of Delphi and
// C++ Builder.
{$ifndef VER135_PLUS}
const
{$ifndef VER10_PLUS}
DVASPECT_SHORTNAME = 2; // use for CF_HDROP to get short name version of file paths
{$endif}
DVASPECT_COPY = 3; // use to indicate format is a "Copy" of the data (FILECONTENTS, FILEDESCRIPTOR, etc)
DVASPECT_LINK = 4; // use to indicate format is a "Shortcut" to the data (FILECONTENTS, FILEDESCRIPTOR, etc)
{$endif}
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
 
(*******************************************************************************
**
** IMPLEMENTATION
**
*******************************************************************************)
implementation
 
uses
{$ifdef DEBUG}
ComObj,
{$endif}
DropSource,
DropTarget,
DragDropFormats, // Used by TRawClipboardFormat
Messages,
ShlObj,
MMSystem,
SysUtils;
 
resourcestring
sImplementationRequired = 'Internal error: %s.%s needs implementation';
sInvalidOwnerType = '%s is not a valid owner for %s. Owner must be derived from %s';
sFormatNameReadOnly = '%s.ClipboardFormat is read-only';
sNoCopyStgMedium = 'A required system function (URLMON.CopyStgMedium) was not available on this system. Operation aborted.';
sBadConstructor = 'The %s class can not be instantiated with the default constructor';
sUnregisteredDataFormat = 'The %s data format has not been registered by any of the used units';
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDataFormatAdapter]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TInterfacedComponent
//
////////////////////////////////////////////////////////////////////////////////
function TInterfacedComponent.QueryInterface(const IID: TGuid; out Obj): HRESULT;
 
{$ifdef DEBUG}
function GuidToString(const IID: TGuid): string;
var
GUID: string;
begin
GUID := ComObj.GUIDToString(IID);
Result := GetRegStringValue('Interface\'+GUID, '');
if (Result = '') then
Result := GUID;
end;
{$endif}
 
begin
{$ifdef VER12_PLUS}
if GetInterface(IID, Obj) then
Result := 0
else if (VCLComObject <> nil) then
Result := IVCLComObject(VCLComObject).QueryInterface(IID, Obj)
else
Result := E_NOINTERFACE;
{$else}
Result := inherited QueryInterface(IID, Obj);
{$endif}
{$ifdef DEBUG}
OutputDebugString(PChar(format('%s.QueryInterface(%s): %d (%d)',
[ClassName, GuidToString(IID), Result, ord(pointer(Obj) <> nil)])));
{$endif}
end;
 
function TInterfacedComponent._AddRef: Integer;
var
Outer: IUnknown;
begin
// In case we are the inner object of an aggregation, we attempt to delegate
// the reference counting to the outer object. We assume that the component
// owner is the outer object.
if (Owner <> nil) and (Owner.GetInterface(IUnknown, Outer)) then
Result := Outer._AddRef
else
begin
{$ifdef VER12_PLUS}
inherited _AddRef;
{$else}
if (VCLComObject <> nil) then
inherited _AddRef;
{$endif}
Result := -1;
end;
end;
 
function TInterfacedComponent._Release: Integer;
var
Outer: IUnknown;
begin
// See _AddRef for comments.
if (Owner <> nil) and (Owner.GetInterface(IUnknown, Outer)) then
Result := Outer._Release
else
begin
{$ifdef VER12_PLUS}
inherited _Release;
{$else}
if (VCLComObject <> nil) then
inherited _Release;
{$endif}
Result := -1;
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
destructor TClipboardFormat.Destroy;
begin
// Warning: Do not call Clear here. Descendant class has already
// cleaned up and released resources!
inherited Destroy;
end;
 
constructor TClipboardFormat.CreateFormat(Atymed: Longint);
begin
inherited Create;
FDataDirections := [ddRead];
FFormatEtc.cfFormat := ClipboardFormat;
FFormatEtc.ptd := nil;
FFormatEtc.dwAspect := DVASPECT_CONTENT;
FFormatEtc.lindex := -1;
FFormatEtc.tymed := Atymed;
end;
 
constructor TClipboardFormat.CreateFormatEtc(const AFormatEtc: TFormatEtc);
begin
inherited Create;
FDataDirections := [ddRead];
FFormatEtc := AFormatEtc;
end;
 
function TClipboardFormat.HasValidFormats(ADataObject: IDataObject): boolean;
begin
Result := (ADataObject.QueryGetData(FormatEtc) = S_OK);
end;
 
function TClipboardFormat.AcceptFormat(const AFormatEtc: TFormatEtc): boolean;
begin
Result := (AFormatEtc.cfFormat = FFormatEtc.cfFormat) and
(AFormatEtc.ptd = nil) and
(AFormatEtc.dwAspect = FFormatEtc.dwAspect) and
(AFormatEtc.tymed AND FFormatEtc.tymed <> 0);
end;
 
function TClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
Result := False;
end;
 
function TClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
Result := False;
end;
 
function TClipboardFormat.DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean;
begin
Result := False;
end;
 
function TClipboardFormat.DoSetData(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean;
begin
Result := False;
end;
 
function TClipboardFormat.GetData(ADataObject: IDataObject): boolean;
var
Medium : TStgMedium;
begin
Result := False;
 
Clear;
if (ADataObject.GetData(FFormatEtc, Medium) <> S_OK) then
exit;
Result := GetDataFromMedium(ADataObject, Medium);
end;
 
function TClipboardFormat.GetDataFromMedium(ADataObject: IDataObject;
var AMedium: TStgMedium): boolean;
begin
Result := False;
try
Clear;
if ((AMedium.tymed AND FFormatEtc.tymed) <> 0) then
Result := DoGetData(ADataObject, AMedium);
finally
ReleaseStgMedium(AMedium);
end;
end;
 
function TClipboardFormat.SetDataToMedium(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean;
begin
Result := False;
 
FillChar(AMedium, SizeOf(AMedium), 0);
 
if (FormatEtcIn.cfFormat <> FFormatEtc.cfFormat) or
(FormatEtcIn.dwAspect <> FFormatEtc.dwAspect) or
(FormatEtcIn.tymed and FFormatEtc.tymed = 0) then
exit;
 
// Call descendant to allocate medium and transfer data to it
Result := DoSetData(FormatEtcIn, AMedium);
end;
 
function TClipboardFormat.SetData(ADataObject: IDataObject;
const FormatEtcIn: TFormatEtc; var AMedium: TStgMedium): boolean;
begin
// Transfer data to medium
Result := SetDataToMedium(FormatEtcIn, AMedium);
 
// Call IDataObject to set data
if (Result) then
Result := (ADataObject.SetData(FormatEtc, AMedium, True) = S_OK);
 
// If we didn't succeed in transfering ownership of the data medium to the
// IDataObject, we must deallocate the medium ourselves.
if (not Result) then
ReleaseStgMedium(AMedium);
end;
 
class procedure TClipboardFormat.UnregisterClipboardFormat;
begin
TDataFormatMap.Instance.DeleteByClipboardFormat(Self);
end;
 
function TClipboardFormat.GetClipboardFormat: TClipFormat;
begin
// This should have been a virtual abstract class method, but this isn't supported by C++ Builder.
raise Exception.CreateFmt(sImplementationRequired, [ClassName, 'GetClipboardFormat']);
end;
 
procedure TClipboardFormat.SetClipboardFormat(Value: TClipFormat);
begin
FFormatEtc.cfFormat := Value;
end;
 
function TClipboardFormat.GetClipboardFormatName: string;
var
Len : integer;
begin
SetLength(Result, 255); // 255 is just an artificial limit.
Len := Windows.GetClipboardFormatName(GetClipboardFormat, PChar(Result), 255);
SetLength(Result, Len);
end;
 
procedure TClipboardFormat.SetClipboardFormatName(const Value: string);
begin
raise Exception.CreateFmt(sFormatNameReadOnly, [ClassName]);
end;
 
function TClipboardFormat.HasData: boolean;
begin
// Descendant classes are not required to override this method, so by default
// we just pretend that data is available. No harm is done by this.
Result := True;
end;
 
procedure TClipboardFormat.SetFormatEtc(const Value: TFormatEtc);
begin
FFormatEtc := Value;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TClipboardFormats
//
////////////////////////////////////////////////////////////////////////////////
constructor TClipboardFormats.Create(ADataFormat: TCustomDataFormat;
AOwnsObjects: boolean);
begin
inherited Create;
FList := TList.Create;
FDataFormat := ADataFormat;
FOwnsObjects := AOwnsObjects;
end;
 
destructor TClipboardFormats.Destroy;
begin
Clear;
FList.Free;
inherited Destroy;
end;
 
function TClipboardFormats.Add(ClipboardFormat: TClipboardFormat): integer;
begin
Result := FList.Add(ClipboardFormat);
if (FOwnsObjects) and (DataFormat <> nil) then
ClipboardFormat.DataFormat := DataFormat;
end;
 
function TClipboardFormats.FindFormat(ClipboardFormatClass: TClipboardFormatClass): TClipboardFormat;
var
i : integer;
begin
// Search list for an object of the specified type
for i := 0 to Count-1 do
if (Formats[i].InheritsFrom(ClipboardFormatClass)) then
begin
Result := Formats[i];
exit;
end;
Result := nil;
end;
 
function TClipboardFormats.Contain(ClipboardFormatClass: TClipboardFormatClass): boolean;
begin
Result := (FindFormat(ClipboardFormatClass) <> nil);
end;
 
function TClipboardFormats.GetCount: integer;
begin
Result := FList.Count;
end;
 
function TClipboardFormats.GetFormat(Index: integer): TClipboardFormat;
begin
Result := TClipboardFormat(FList[Index]);
end;
 
procedure TClipboardFormats.Clear;
var
i : integer;
Format : TObject;
begin
if (FOwnsObjects) then
// Empty list and delete all objects in it
for i := Count-1 downto 0 do
begin
Format := Formats[i];
FList.Delete(i);
Format.Free;
end;
 
FList.Clear;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomDataFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TCustomDataFormat.Create(AOwner: TDragDropComponent);
var
ConversionScope: TConversionScope;
begin
if (AOwner <> nil) then
begin
if (AOwner is TCustomDropMultiSource) then
ConversionScope := csSource
else if (AOwner is TCustomDropMultiTarget) then
ConversionScope := csTarget
else
raise Exception.CreateFmt(sInvalidOwnerType, [AOwner.ClassName, ClassName,
'TCustomDropMultiSource or TCustomDropMultiTarget']);
// Add object to owners list of data formats.
FOwner := AOwner;
end else
// TODO : This sucks! All this ConversionScope stuff should be redesigned.
ConversionScope := csTarget;
 
FCompatibleFormats := TClipboardFormats.Create(Self, True);
// Populate list with all the clipboard formats that have been registered as
// compatible with this data format.
TDataFormatMap.Instance.GetSourceByDataFormat(TDataFormatClass(ClassType),
FCompatibleFormats, ConversionScope);
 
if (FOwner <> nil) then
FOwner.DataFormats.Add(Self);
end;
 
destructor TCustomDataFormat.Destroy;
begin
FCompatibleFormats.Free;
// Remove object from owners list of target formats
if (FOwner <> nil) then
FOwner.DataFormats.Remove(Self);
inherited Destroy;
end;
 
function TCustomDataFormat.Assign(Source: TClipboardFormat): boolean;
begin
// Called when derived class(es) couldn't convert from the source format.
// Try to let source format convert to this format instead.
Result := Source.AssignTo(Self);
end;
 
function TCustomDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
begin
// Called when derived class(es) couldn't convert to the destination format.
// Try to let destination format convert from this format instead.
Result := Dest.Assign(Self);
end;
 
function TCustomDataFormat.GetData(DataObject: IDataObject): boolean;
var
i: integer;
begin
Result := False;
i := 0;
// Get data from each of our associated clipboard formats until we don't
// need anymore data.
while (NeedsData) and (i < CompatibleFormats.Count) do
begin
CompatibleFormats[i].Clear;
 
if (CompatibleFormats[i].GetData(DataObject)) and
(CompatibleFormats[i].HasData) then
begin
if (Assign(CompatibleFormats[i])) then
begin
// Once data has been sucessfully transfered to the TDataFormat object,
// we clear the data in the TClipboardFormat object in order to conserve
// resources.
CompatibleFormats[i].Clear;
Result := True;
end;
end;
 
inc(i);
end;
end;
 
function TCustomDataFormat.NeedsData: boolean;
begin
Result := not HasData;
end;
 
function TCustomDataFormat.HasValidFormats(ADataObject: IDataObject): boolean;
var
i: integer;
begin
// Determine if any of the registered clipboard formats can read from the
// specified data object.
Result := False;
for i := 0 to CompatibleFormats.Count-1 do
if (CompatibleFormats[i].HasValidFormats(ADataObject)) then
begin
Result := True;
break;
end;
end;
 
function TCustomDataFormat.AcceptFormat(const FormatEtc: TFormatEtc): boolean;
var
i: integer;
begin
// Determine if any of the registered clipboard formats can handle the
// specified clipboard format.
Result := False;
for i := 0 to CompatibleFormats.Count-1 do
if (CompatibleFormats[i].AcceptFormat(FormatEtc)) then
begin
Result := True;
break;
end;
end;
 
class procedure TCustomDataFormat.RegisterDataFormat;
begin
TDataFormatClasses.Instance.Add(Self);
end;
 
class procedure TCustomDataFormat.RegisterCompatibleFormat(ClipboardFormatClass: TClipboardFormatClass;
Priority: integer; ConversionScopes: TConversionScopes;
DataDirections: TDataDirections);
begin
// Register format mapping.
TDataFormatMap.Instance.RegisterFormatMap(Self, ClipboardFormatClass,
Priority, ConversionScopes, DataDirections);
end;
 
function TCustomDataFormat.SupportsFormat(ClipboardFormat: TClipboardFormat): boolean;
begin
Result := CompatibleFormats.Contain(TClipboardFormatClass(ClipboardFormat.ClassType));
end;
 
class procedure TCustomDataFormat.UnregisterCompatibleFormat(ClipboardFormatClass: TClipboardFormatClass);
begin
// Unregister format mapping
TDataFormatMap.Instance.UnregisterFormatMap(Self, ClipboardFormatClass);
end;
 
class procedure TCustomDataFormat.UnregisterDataFormat;
begin
TDataFormatMap.Instance.DeleteByDataFormat(Self);
TDataFormatClasses.Instance.Remove(Self);
end;
 
procedure TCustomDataFormat.DoOnChanging(Sender: TObject);
begin
Changing;
end;
 
procedure TCustomDataFormat.Changing;
begin
if (Assigned(OnChanging)) then
OnChanging(Self);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDataFormats
//
////////////////////////////////////////////////////////////////////////////////
function TDataFormats.Add(DataFormat: TCustomDataFormat): integer;
begin
Result := FList.IndexOf(DataFormat);
if (Result = -1) then
Result := FList.Add(DataFormat);
end;
 
constructor TDataFormats.Create;
begin
inherited Create;
FList := TList.Create;
end;
 
destructor TDataFormats.Destroy;
var
i: integer;
begin
for i := FList.Count-1 downto 0 do
Remove(TCustomDataFormat(FList[i]));
FList.Free;
inherited Destroy;
end;
 
function TDataFormats.GetCount: integer;
begin
Result := FList.Count;
end;
 
function TDataFormats.GetFormat(Index: integer): TCustomDataFormat;
begin
Result := TCustomDataFormat(FList[Index]);
end;
 
function TDataFormats.IndexOf(DataFormat: TCustomDataFormat): integer;
begin
Result := FList.IndexOf(DataFormat);
end;
 
procedure TDataFormats.Remove(DataFormat: TCustomDataFormat);
begin
FList.Remove(DataFormat);
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDataFormatClasses
//
////////////////////////////////////////////////////////////////////////////////
function TDataFormatClasses.Add(DataFormat: TDataFormatClass): integer;
begin
Result := FList.IndexOf(DataFormat);
if (Result = -1) then
Result := FList.Add(DataFormat);
end;
 
constructor TDataFormatClasses.Create;
begin
inherited Create;
FList := TList.Create;
end;
 
destructor TDataFormatClasses.Destroy;
var
i: integer;
begin
for i := FList.Count-1 downto 0 do
Remove(TDataFormatClass(FList[i]));
FList.Free;
inherited Destroy;
end;
 
function TDataFormatClasses.GetCount: integer;
begin
Result := FList.Count;
end;
 
function TDataFormatClasses.GetFormat(Index: integer): TDataFormatClass;
begin
Result := TDataFormatClass(FList[Index]);
end;
 
var
FDataFormatClasses: TDataFormatClasses = nil;
 
class function TDataFormatClasses.Instance: TDataFormatClasses;
begin
if (FDataFormatClasses = nil) then
FDataFormatClasses := TDataFormatClasses.Create;
Result := FDataFormatClasses;
end;
 
procedure TDataFormatClasses.Remove(DataFormat: TDataFormatClass);
begin
FList.Remove(DataFormat);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDataFormatMap
//
////////////////////////////////////////////////////////////////////////////////
type
// TTargetFormat / TClipboardFormat association
TFormatMap = record
DataFormat: TDataFormatClass;
ClipboardFormat: TClipboardFormatClass;
Priority: integer;
ConversionScopes: TConversionScopes;
DataDirections: TDataDirections;
end;
 
PFormatMap = ^TFormatMap;
 
constructor TDataFormatMap.Create;
begin
inherited Create;
FList := TList.Create;
end;
 
destructor TDataFormatMap.Destroy;
var
i : integer;
begin
// Zap any mapings which hasn't been unregistered
// yet (actually an error condition)
for i := FList.Count-1 downto 0 do
Dispose(FList[i]);
FList.Free;
inherited Destroy;
end;
 
procedure TDataFormatMap.Sort;
var
i : integer;
NewMap : PFormatMap;
begin
// Note: We do not use the built-in Sort method of TList because
// we need to preserve the order in which the mappings were added.
// New mappings have higher precedence than old mappings (within the
// same priority).
 
// Preconditions:
// 1) The list is already sorted before a new mapping is added.
// 2) The new mapping is always added to the end of the list.
 
NewMap := PFormatMap(FList.Last);
 
// Scan the list for a map with the same TTargetFormat type
i := FList.Count-2;
while (i > 0) do
begin
if (PFormatMap(FList[i])^.DataFormat = NewMap^.DataFormat) then
begin
// Scan the list for a map with lower priority
repeat
if (PFormatMap(FList[i])^.Priority < NewMap^.Priority) then
begin
// Move the mapping to the new position
FList.Move(FList.Count-1, i+1);
exit;
end;
dec(i);
until (i < 0) or (PFormatMap(FList[i])^.DataFormat <> NewMap^.DataFormat);
// Move the mapping to the new position
FList.Move(FList.Count-1, i+1);
exit;
end;
dec(i);
end;
end;
 
procedure TDataFormatMap.Add(DataFormatClass: TDataFormatClass;
ClipboardFormatClass: TClipboardFormatClass; Priority: integer;
ConversionScopes: TConversionScopes; DataDirections: TDataDirections);
var
FormatMap : PFormatMap;
OldMap : integer;
begin
// Avoid duplicate mappings
OldMap := FindMap(DataFormatClass, ClipboardFormatClass);
if (OldMap = -1) then
begin
// Add new mapping...
New(FormatMap);
FList.Add(FormatMap);
FormatMap^.ConversionScopes := ConversionScopes;
FormatMap^.DataDirections := DataDirections;
end else
begin
// Replace old mapping...
FormatMap := FList[OldMap];
FList.Move(OldMap, FList.Count-1);
FormatMap^.ConversionScopes := FormatMap^.ConversionScopes + ConversionScopes;
FormatMap^.DataDirections := FormatMap^.DataDirections + DataDirections;
end;
 
FormatMap^.ClipboardFormat := ClipboardFormatClass;
FormatMap^.DataFormat := DataFormatClass;
FormatMap^.Priority := Priority;
// ...and sort list
Sort;
end;
 
function TDataFormatMap.CanMap(DataFormatClass: TDataFormatClass;
ClipboardFormatClass: TClipboardFormatClass): boolean;
begin
Result := (FindMap(DataFormatClass, ClipboardFormatClass) <> -1);
end;
 
procedure TDataFormatMap.Delete(DataFormatClass: TDataFormatClass;
ClipboardFormatClass: TClipboardFormatClass);
var
Index : integer;
begin
Index := FindMap(DataFormatClass, ClipboardFormatClass);
if (Index <> -1) then
begin
Dispose(FList[Index]);
FList.Delete(Index);
end;
end;
 
procedure TDataFormatMap.DeleteByClipboardFormat(ClipboardFormatClass: TClipboardFormatClass);
var
i : integer;
begin
// Delete all mappings associated with the specified clipboard format
for i := FList.Count-1 downto 0 do
if (PFormatMap(FList[i])^.ClipboardFormat.InheritsFrom(ClipboardFormatClass)) then
begin
Dispose(FList[i]);
FList.Delete(i);
end;
end;
 
procedure TDataFormatMap.DeleteByDataFormat(DataFormatClass: TDataFormatClass);
var
i : integer;
begin
// Delete all mappings associated with the specified target format
for i := FList.Count-1 downto 0 do
if (PFormatMap(FList[i])^.DataFormat.InheritsFrom(DataFormatClass)) then
begin
Dispose(FList[i]);
FList.Delete(i);
end;
end;
 
function TDataFormatMap.FindMap(DataFormatClass: TDataFormatClass;
ClipboardFormatClass: TClipboardFormatClass): integer;
var
i : integer;
begin
for i := 0 to FList.Count-1 do
if (PFormatMap(FList[i])^.DataFormat.InheritsFrom(DataFormatClass)) and
(PFormatMap(FList[i])^.ClipboardFormat.InheritsFrom(ClipboardFormatClass)) then
begin
Result := i;
exit;
end;
Result := -1;
end;
 
procedure TDataFormatMap.GetSourceByDataFormat(DataFormatClass: TDataFormatClass;
ClipboardFormats: TClipboardFormats; ConversionScope: TConversionScope);
var
i: integer;
ClipboardFormat: TClipboardFormat;
begin
// Clear the list...
ClipboardFormats.Clear;
// ...and populate it with *instances* of all the clipbard
// formats associated with the specified target format and
// registered with the specified data direction.
for i := 0 to FList.Count-1 do
if (ConversionScope in PFormatMap(FList[i])^.ConversionScopes) and
(PFormatMap(FList[i])^.DataFormat.InheritsFrom(DataFormatClass)) then
begin
ClipboardFormat := PFormatMap(FList[i])^.ClipboardFormat.Create;
ClipboardFormat.DataDirections := PFormatMap(FList[i])^.DataDirections;
ClipboardFormats.Add(ClipboardFormat);
end;
end;
 
procedure TDataFormatMap.RegisterFormatMap(DataFormatClass: TDataFormatClass;
ClipboardFormatClass: TClipboardFormatClass; Priority: integer;
ConversionScopes: TConversionScopes; DataDirections: TDataDirections);
begin
Add(DataFormatClass, ClipboardFormatClass, Priority, ConversionScopes,
DataDirections);
end;
 
procedure TDataFormatMap.UnregisterFormatMap(DataFormatClass: TDataFormatClass;
ClipboardFormatClass: TClipboardFormatClass);
begin
Delete(DataFormatClass, ClipboardFormatClass);
end;
 
var
FDataFormatMap: TDataFormatMap = nil;
 
class function TDataFormatMap.Instance: TDataFormatMap;
begin
if (FDataFormatMap = nil) then
FDataFormatMap := TDataFormatMap.Create;
Result := FDataFormatMap;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDataFormatAdapter
//
////////////////////////////////////////////////////////////////////////////////
destructor TDataFormatAdapter.Destroy;
begin
inherited Destroy;
end;
 
function TDataFormatAdapter.GetDataFormatName: string;
begin
if Assigned(FDataFormatClass) then
Result := FDataFormatClass.ClassName
else
Result := '';
end;
 
function TDataFormatAdapter.GetEnabled: boolean;
begin
if (csDesigning in ComponentState) then
Result := FEnabled
else
Result := Assigned(FDataFormat) and Assigned(FDataFormatClass);
end;
 
procedure TDataFormatAdapter.Loaded;
begin
inherited;
if (FEnabled) then
Enabled := True;
end;
 
procedure TDataFormatAdapter.Notification(AComponent: TComponent;
Operation: TOperation);
begin
if (Operation = opRemove) and (AComponent = FDragDropComponent) then
DragDropComponent := nil;
inherited;
end;
 
procedure TDataFormatAdapter.SetDataFormatClass(const Value: TDataFormatClass);
begin
if (Value <> FDataFormatClass) then
begin
if not(csLoading in ComponentState) then
Enabled := False;
FDataFormatClass := Value;
end;
end;
 
procedure TDataFormatAdapter.SetDataFormatName(const Value: string);
var
i: integer;
ADataFormatClass: TDataFormatClass;
begin
ADataFormatClass := nil;
if (Value <> '') then
begin
for i := 0 to TDataFormatClasses.Instance.Count-1 do
if (AnsiCompareText(TDataFormatClasses.Instance[i].ClassName, Value) = 0) then
begin
ADataFormatClass := TDataFormatClasses.Instance[i];
break;
end;
if (ADataFormatClass = nil) then
raise Exception.CreateFmt(sUnregisteredDataFormat, [Value]);
end;
DataFormatClass := ADataFormatClass;
end;
 
procedure TDataFormatAdapter.SetDragDropComponent(const Value: TDragDropComponent);
begin
if (Value <> FDragDropComponent) then
begin
if not(csLoading in ComponentState) then
Enabled := False;
if (FDragDropComponent <> nil) then
FDragDropComponent.RemoveFreeNotification(Self);
FDragDropComponent := Value;
if (Value <> nil) then
Value.FreeNotification(Self);
end;
end;
 
procedure TDataFormatAdapter.SetEnabled(const Value: boolean);
begin
if (csLoading in ComponentState) then
begin
FEnabled := Value;
end else
if (csDesigning in ComponentState) then
begin
FEnabled := Value and Assigned(FDragDropComponent) and
Assigned(FDataFormatClass);
end else
if (Value) then
begin
if (Assigned(FDragDropComponent)) and (Assigned(FDataFormatClass)) and
(not Assigned(FDataFormat)) then
FDataFormat := FDataFormatClass.Create(FDragDropComponent);
end else
begin
if Assigned(FDataFormat) then
begin
if Assigned(FDragDropComponent) and
(FDragDropComponent.DataFormats.IndexOf(FDataFormat) <> -1) then
FDataFormat.Free;
FDataFormat := nil;
end;
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TRawClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TRawClipboardFormat.Create;
begin
// Yeah, it's a hack but blame Borland for making TObject.Create public!
raise Exception.CreateFmt(sBadConstructor, [ClassName]);
end;
 
constructor TRawClipboardFormat.CreateFormatEtc(const AFormatEtc: TFormatEtc);
begin
inherited CreateFormatEtc(AFormatEtc);
end;
 
procedure TRawClipboardFormat.SetClipboardFormatName(const Value: string);
begin
ClipboardFormat := RegisterClipboardFormat(PChar(Value));
end;
 
function TRawClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := FFormatEtc.cfFormat;
end;
 
function TRawClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
if (Source is TRawDataFormat) then
begin
Result := True;
end else
Result := inherited Assign(Source);
end;
 
function TRawClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
if (Dest is TRawDataFormat) then
begin
Result := True;
end else
Result := inherited AssignTo(Dest);
end;
 
procedure TRawClipboardFormat.Clear;
begin
// Since TRawDataFormat performs storage for TRawDataFormat we only allow
// TRawDataFormat to clear. To accomplish this TRawDataFormat ignores calls to
// the clear method and instead introduces the ClearData method.
end;
 
procedure TRawClipboardFormat.ClearData;
begin
ReleaseStgMedium(FMedium);
FillChar(FMedium, SizeOf(FMedium), 0);
end;
 
function TRawClipboardFormat.HasData: boolean;
begin
Result := (FMedium.tymed <> TYMED_NULL);
end;
 
function TRawClipboardFormat.NeedsData: boolean;
begin
Result := (FMedium.tymed = TYMED_NULL);
end;
 
procedure TRawClipboardFormat.CopyFromStgMedium(const AMedium: TStgMedium);
begin
CopyStgMedium(AMedium, FMedium);
end;
 
procedure TRawClipboardFormat.CopyToStgMedium(var AMedium: TStgMedium);
begin
CopyStgMedium(FMedium, AMedium);
end;
 
function TRawClipboardFormat.DoGetData(ADataObject: IDataObject;
const AMedium: TStgMedium): boolean;
begin
Result := CopyStgMedium(AMedium, FMedium);
end;
 
function TRawClipboardFormat.DoSetData(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean;
begin
Result := CopyStgMedium(FMedium, AMedium);
end;
 
function TRawClipboardFormat.GetString: string;
begin
with TTextClipboardFormat.Create do
try
if GetDataFromMedium(nil, FMedium) then
Result := Text
else
Result := '';
finally
Free;
end;
end;
 
procedure TRawClipboardFormat.SetString(const Value: string);
begin
with TTextClipboardFormat.Create do
try
Text := Value;
SetDataToMedium(FormatEtc, FMedium);
finally
Free;
end;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TRawDataFormat
//
////////////////////////////////////////////////////////////////////////////////
procedure TRawDataFormat.Clear;
var
i: integer;
begin
Changing;
for i := 0 to CompatibleFormats.Count-1 do
TRawClipboardFormat(CompatibleFormats[i]).ClearData;
end;
 
function TRawDataFormat.HasData: boolean;
var
i: integer;
begin
i := 0;
Result := False;
while (not Result) and (i < CompatibleFormats.Count) do
begin
Result := TRawClipboardFormat(CompatibleFormats[i]).HasData;
inc(i);
end;
end;
 
function TRawDataFormat.NeedsData: boolean;
var
i: integer;
begin
i := 0;
Result := False;
while (not Result) and (i < CompatibleFormats.Count) do
begin
Result := TRawClipboardFormat(CompatibleFormats[i]).NeedsData;
inc(i);
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Utility functions
//
////////////////////////////////////////////////////////////////////////////////
procedure _RaiseLastWin32Error;
begin
{$ifdef VER14_PLUS}
RaiseLastOSError;
{$else}
RaiseLastWin32Error;
{$endif}
end;
 
function DropEffectToDragType(DropEffect: longInt; var DragType: TDragType): boolean;
begin
Result := True;
if ((DropEffect and DROPEFFECT_COPY) <> 0) then
DragType := dtCopy
else
if ((DropEffect and DROPEFFECT_MOVE) <> 0) then
DragType := dtMove
else
if ((DropEffect and DROPEFFECT_LINK) <> 0) then
DragType := dtLink
else
begin
DragType := dtCopy;
Result := False;
end;
end;
 
function DragTypesToDropEffect(DragTypes: TDragTypes): longint;
begin
Result := DROPEFFECT_NONE;
if (dtCopy in DragTypes) then
Result := Result OR DROPEFFECT_COPY;
if (dtMove in DragTypes) then
Result := Result OR DROPEFFECT_MOVE;
if (dtLink in DragTypes) then
Result := Result OR DROPEFFECT_LINK;
end;
 
// Replacement for the buggy DragDetect API function.
function DragDetectPlus(Handle: THandle; p: TPoint): boolean;
var
DragRect: TRect;
Msg: TMsg;
StartTime: DWORD;
OldCapture: HWND;
begin
Result := False;
if (not ClientToScreen(Handle, p)) then
exit;
// Calculate the drag rect. If the mouse leaves this rect while the
// mouse button is pressed, a drag is detected.
DragRect.TopLeft := p;
DragRect.BottomRight := p;
InflateRect(DragRect, GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG));
StartTime := TimeGetTime;
// Capture the mouse so that we will receive mouse messages even after the
// mouse leaves the control rect.
OldCapture := SetCapture(Handle);
try
// Abort if we failed to capture the mouse.
if (GetCapture <> Handle) then
exit;
while (not Result) do
begin
// Detect if all mouse buttons are up (might mean that we missed a
// MW_?BUTTONUP message).
if (GetAsyncKeyState(VK_LBUTTON) AND $8000 = 0) and
(GetAsyncKeyState(VK_RBUTTON) AND $8000 = 0) then
break;
 
if (PeekMessage(Msg, Handle, 0,0, PM_REMOVE)) then
begin
case (Msg.message) of
WM_MOUSEMOVE:
// Mouse were moved. Check if we are still within the drag rect...
Result := (not PtInRect(DragRect, Msg.pt)) and
// ... and that the minimum time has elapsed.
// Note that we ignore time warp (wrap around) and that Msg.Time
// might be smaller than StartTime.
(Msg.time >= StartTime + DWORD(DragDropDragDelay));
WM_RBUTTONUP,
WM_LBUTTONUP,
WM_CANCELMODE:
// Mouse button were released, escape were pressed or some other
// operation cancelled our mouse capture.
break;
WM_QUIT:
// Application is shutting down. Get out of here fast.
exit;
else
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end else
Sleep(0);
end;
finally
ReleaseCapture;
// Restore previous capture.
if (OldCapture <> 0) then
SetCapture(OldCapture);
end;
end;
 
function ClientPtToWindowPt(Handle: THandle; pt: TPoint): TPoint;
var
Rect: TRect;
begin
ClientToScreen(Handle, pt);
GetWindowRect(Handle, Rect);
Result.X := pt.X - Rect.Left;
Result.Y := pt.Y - Rect.Top;
end;
 
const
// Note: The definition of MK_ALT is missing from the current Delphi (D5)
// declarations. Hopefully Delphi 6 will fix this.
MK_ALT = $20;
 
function KeysToShiftStatePlus(Keys: Word): TShiftState;
begin
Result := [];
if (Keys and MK_SHIFT <> 0) then
Include(Result, ssShift);
if (Keys and MK_CONTROL <> 0) then
Include(Result, ssCtrl);
if (Keys and MK_LBUTTON <> 0) then
Include(Result, ssLeft);
if (Keys and MK_RBUTTON <> 0) then
Include(Result, ssRight);
if (Keys and MK_MBUTTON <> 0) then
Include(Result, ssMiddle);
if (Keys and MK_ALT <> 0) then
Include(Result, ssMiddle);
end;
 
function ShiftStateToDropEffect(Shift: TShiftState; AllowedEffects: longint;
Fallback: boolean): longint;
begin
// As we're only interested in ssShift & ssCtrl here,
// mouse button states are screened out.
Shift := Shift * [ssShift, ssCtrl];
 
Result := DROPEFFECT_NONE;
if (Shift = [ssShift, ssCtrl]) then
begin
if (AllowedEffects AND DROPEFFECT_LINK <> 0) then
Result := DROPEFFECT_LINK;
end else
if (Shift = [ssCtrl]) then
begin
if (AllowedEffects AND DROPEFFECT_COPY <> 0) then
Result := DROPEFFECT_COPY;
end else
begin
if (AllowedEffects AND DROPEFFECT_MOVE <> 0) then
Result := DROPEFFECT_MOVE;
end;
 
// Fall back to defaults if the shift-states specified an
// unavailable drop effect.
if (Result = DROPEFFECT_NONE) and (Fallback) then
begin
if (AllowedEffects AND DROPEFFECT_COPY <> 0) then
Result := DROPEFFECT_COPY
else if (AllowedEffects AND DROPEFFECT_MOVE <> 0) then
Result := DROPEFFECT_MOVE
else if (AllowedEffects AND DROPEFFECT_LINK <> 0) then
Result := DROPEFFECT_LINK;
end;
end;
 
var
URLMONDLL: THandle = 0;
_CopyStgMedium: function(const cstgmedSrc: TStgMedium; var stgmedDest: TStgMedium): HResult; stdcall = nil;
 
function CopyStgMedium(const SrcMedium: TStgMedium; var DstMedium: TStgMedium): boolean;
begin
// Copy the medium via the URLMON CopyStgMedium function. This should be safe
// since this function is only called when the drag drop helper object is
// used and the drag drop helper object is only supported on Windows 2000
// and later.
// URLMON.CopyStgMedium requires IE4 or later.
// An alternative approach would be to use OleDuplicateData, but based on a
// disassembly of urlmon.dll, CopyStgMedium seems to do a lot more than
// OleDuplicateData.
if (URLMONDLL = 0) then
begin
URLMONDLL := LoadLibrary('URLMON.DLL');
if (URLMONDLL <> 0) then
@_CopyStgMedium := GetProcAddress(URLMONDLL, 'CopyStgMedium');
end;
 
if (@_CopyStgMedium = nil) then
raise Exception.Create(sNoCopyStgMedium);
 
Result := (_CopyStgMedium(SrcMedium, DstMedium) = S_OK);
end;
 
function GetClipboardFormatNameStr(Value: TClipFormat): string;
var
len: integer;
begin
Setlength(Result, 255);
len := GetClipboardFormatName(Value, PChar(Result), 255);
SetLength(Result, len);
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Initialization/Finalization
//
////////////////////////////////////////////////////////////////////////////////
initialization
OleInitialize(nil);
ShGetMalloc(ShellMalloc);
GetClipboardFormatNameStr(0);
 
finalization
if (FDataFormatMap <> nil) then
begin
FDataFormatMap.Free;
FDataFormatMap := nil;
end;
if (FDataFormatClasses <> nil) then
begin
FDataFormatClasses.Free;
FDataFormatClasses := nil;
end;
 
ShellMalloc := nil;
 
OleUninitialize;
end.
 
/trunk/VCL_DRAGDROP/DragDropC3.bpk
0,0 → 1,179
# ---------------------------------------------------------------------------
!if !$d(BCB)
BCB = $(MAKEDIR)\..
!endif
 
# ---------------------------------------------------------------------------
# IDE SECTION
# ---------------------------------------------------------------------------
# The following section of the project makefile is managed by the BCB IDE.
# It is recommended to use the IDE to change any of the values in this
# section.
# ---------------------------------------------------------------------------
 
VERSION = BCB.03
# ---------------------------------------------------------------------------
PROJECT = DragDropC3.bpl
OBJFILES = DropSource.obj DropURLTarget.obj DropBMPTarget.obj DropPIDLSource.obj \
DropPIDLTarget.obj DropTarget.obj DropURLSource.obj DropBMPSource.obj \
DragDropC3.obj
RESFILES = dragdropC3.res DropSource.dcr DropURLTarget.dcr DropBMPTarget.dcr \
DropPIDLSource.dcr DropPIDLTarget.dcr DropTarget.dcr DropURLSource.dcr \
DropBMPSource.dcr
DEFFILE =
RESDEPEN = $(RESFILES)
LIBFILES =
LIBRARIES =
SPARELIBS = VCL35.lib
PACKAGES = vcl35.bpi
# ---------------------------------------------------------------------------
PATHCPP = .;
PATHASM = .;
PATHPAS = .;
PATHRC = .;
DEBUGLIBPATH = $(BCB)\lib\debug
RELEASELIBPATH = $(BCB)\lib\release
# ---------------------------------------------------------------------------
CFLAG1 = -Od -Hc -w -Ve -r- -k -y -v -vi- -c -b- -w-par -w-inl -Vx
CFLAG2 = -DUSEPACKAGES -I$(BCB)\include;$(BCB)\include\vcl -H=$(BCB)\lib\vcl35.csm
CFLAG3 = -Tkh30000
PFLAGS = -DUSEPACKAGES -U$(BCB)\lib\obj;$(BCB)\lib;$(RELEASELIBPATH) \
-I$(BCB)\include;$(BCB)\include\vcl -H -W -$Y -$W -v -JPHN -M
RFLAGS = -DUSEPACKAGES -i$(BCB)\include;$(BCB)\include\vcl
AFLAGS = /i$(BCB)\include /i$(BCB)\include\vcl /dUSEPACKAGES /mx /w2 /zd
LFLAGS = -L$(BCB)\lib\obj;$(BCB)\lib;$(RELEASELIBPATH) -D"COM Drag/Drop" -aa -Tpp -x -Gn \
-Gl -Gi
IFLAGS =
# ---------------------------------------------------------------------------
ALLOBJ = c0pkg32.obj $(PACKAGES) sysinit.obj $(OBJFILES)
ALLRES = $(RESFILES)
ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib
# ---------------------------------------------------------------------------
!ifdef IDEOPTIONS
 
[Version Info]
IncludeVerInfo=1
AutoIncBuild=1
MajorVer=3
MinorVer=4
Release=1
Build=5
Debug=0
PreRelease=0
Special=0
Private=0
DLL=1
Locale=1030
CodePage=1252
 
[Version Info Keys]
CompanyName=
FileDescription=
FileVersion=3.4.1.5
InternalName=
LegalCopyright=
LegalTrademarks=
OriginalFilename=
ProductName=
ProductVersion=1.0.0.0
Comments=Freeware.
 
[HistoryLists\hlIncludePath]
Count=1
Item0=$(BCB)\include;$(BCB)\include\vcl
 
[HistoryLists\hlLibraryPath]
Count=1
Item0=$(BCB)\lib\obj;$(BCB)\lib
 
[HistoryLists\hlDebugSourcePath]
Count=1
Item0=$(BCB)\source\vcl
 
[HistoryLists\hlConditionals]
Count=1
Item0=USEPACKAGES
 
[Debugging]
DebugSourceDirs=$(BCB)\source\vcl
 
[Parameters]
RunParams=
HostApplication=
 
!endif
 
# ---------------------------------------------------------------------------
# MAKE SECTION
# ---------------------------------------------------------------------------
# This section of the project file is not used by the BCB IDE. It is for
# the benefit of building from the command-line using the MAKE utility.
# ---------------------------------------------------------------------------
 
.autodepend
# ---------------------------------------------------------------------------
!if !$d(BCC32)
BCC32 = bcc32
!endif
 
!if !$d(DCC32)
DCC32 = dcc32
!endif
 
!if !$d(TASM32)
TASM32 = tasm32
!endif
 
!if !$d(LINKER)
LINKER = ilink32
!endif
 
!if !$d(BRCC32)
BRCC32 = brcc32
!endif
# ---------------------------------------------------------------------------
!if $d(PATHCPP)
.PATH.CPP = $(PATHCPP)
.PATH.C = $(PATHCPP)
!endif
 
!if $d(PATHPAS)
.PATH.PAS = $(PATHPAS)
!endif
 
!if $d(PATHASM)
.PATH.ASM = $(PATHASM)
!endif
 
!if $d(PATHRC)
.PATH.RC = $(PATHRC)
!endif
# ---------------------------------------------------------------------------
$(PROJECT): $(OBJFILES) $(RESDEPEN) $(DEFFILE)
$(BCB)\BIN\$(LINKER) @&&!
$(LFLAGS) +
$(ALLOBJ), +
$(PROJECT),, +
$(ALLLIB), +
$(DEFFILE), +
$(ALLRES)
!
# ---------------------------------------------------------------------------
.pas.hpp:
$(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
 
.pas.obj:
$(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
 
.cpp.obj:
$(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
 
.c.obj:
$(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
 
.asm.obj:
$(BCB)\BIN\$(TASM32) $(AFLAGS) $<, $@
 
.rc.res:
$(BCB)\BIN\$(BRCC32) $(RFLAGS) -fo$@ $<
# ---------------------------------------------------------------------------
/trunk/VCL_DRAGDROP/DragDropC3.cpp
0,0 → 1,31
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
USERES("dragdropC3.res");
USEPACKAGE("vcl35.bpi");
USEUNIT("DropSource.pas");
USERES("DropSource.dcr");
USEUNIT("DropURLTarget.pas");
USERES("DropURLTarget.dcr");
USEUNIT("DropBMPTarget.pas");
USERES("DropBMPTarget.dcr");
USEUNIT("DropPIDLSource.pas");
USERES("DropPIDLSource.dcr");
USEUNIT("DropPIDLTarget.pas");
USERES("DropPIDLTarget.dcr");
USEUNIT("DropTarget.pas");
USERES("DropTarget.dcr");
USEUNIT("DropURLSource.pas");
USERES("DropURLSource.dcr");
USEUNIT("DropBMPSource.pas");
USERES("DropBMPSource.dcr");
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
// Package source.
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
return 1;
}
//---------------------------------------------------------------------------
/trunk/VCL_DRAGDROP/DragDropC4.bpk
0,0 → 1,125
<?xml version='1.0' encoding='utf-8' ?>
<!-- C++Builder XML Project -->
<PROJECT>
<MACROS>
<VERSION value="BCB.05.03"/>
<PROJECT value="DragDropC4.bpl"/>
<OBJFILES value="DragDrop.obj DragDropFile.obj DragDropFormats.obj DragDropGraphics.obj
DragDropPIDL.obj DragDropText.obj DragDropURL.obj DropMultiTarget.obj
DropSource.obj DropTarget.obj DragDropC4.obj"/>
<RESFILES value="dragdropC4.res DragDropFile.dcr DragDropGraphics.dcr DragDropPIDL.dcr
DragDropText.dcr DragDropURL.dcr DropMultiTarget.dcr DropSource.dcr
DropTarget.dcr"/>
<IDLFILES value=""/>
<IDLGENFILES value=""/>
<DEFFILE value=""/>
<RESDEPEN value="$(RESFILES)"/>
<LIBFILES value=""/>
<LIBRARIES value="DCLUSR50.lib nmfast50.lib tee50.lib teedb50.lib teeui50.lib vcldbx50.lib
ibsmp50.lib vclbde50.lib vcldb50.lib qrpt50.lib bcbsmp50.lib vcljpg50.lib
vclx50.lib"/>
<SPARELIBS value="vcl50.lib vclx50.lib vcljpg50.lib bcbsmp50.lib qrpt50.lib vcldb50.lib
vclbde50.lib ibsmp50.lib vcldbx50.lib teeui50.lib teedb50.lib tee50.lib
nmfast50.lib DCLUSR50.lib"/>
<PACKAGES value="vcl50.bpi"/>
<PATHCPP value=".;"/>
<PATHPAS value=".;"/>
<PATHRC value=".;"/>
<PATHASM value=".;"/>
<DEBUGLIBPATH value="$(BCB)\lib\debug"/>
<RELEASELIBPATH value="$(BCB)\lib\release"/>
<LINKER value="ilink32"/>
<USERDEFINES value=""/>
<SYSDEFINES value="NO_STRICT;USEPACKAGES"/>
<MAINSOURCE value="DragDropC4.cpp"/>
<INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl"/>
<LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
<WARNINGS value="-w-par -w-8027 -w-8026"/>
</MACROS>
<OPTIONS>
<IDLCFLAGS value="-src_suffixcpp -I$(BCB)\include -I$(BCB)\include\vcl"/>
<CFLAG1 value="-Od -H=d:\DEVELO~1\rampage\lib\vcl50.csm -Hc -Vx -Ve -Tkh30000 -X- -r- -a8
-b- -k -y -v -vi- -c -tWM"/>
<PFLAGS value="-$YD -$W -v -M -JPHNE"/>
<RFLAGS value=""/>
<AFLAGS value="/mx /w2 /zd"/>
<LFLAGS value="-D&quot;Drag and Drop Component Suite&quot; -aa -Tpp -x -Gn -Gl -Gi"/>
</OPTIONS>
<LINKER>
<ALLOBJ value="c0pkg32.obj $(PACKAGES) sysinit.obj $(OBJFILES)"/>
<ALLRES value="$(RESFILES)"/>
<ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib"/>
</LINKER>
<IDEOPTIONS>
[Version Info]
IncludeVerInfo=1
AutoIncBuild=1
MajorVer=4
MinorVer=0
Release=3
Build=12
Debug=0
PreRelease=0
Special=0
Private=0
DLL=1
Locale=1030
CodePage=1252
 
[Version Info Keys]
CompanyName=Johnson &amp; Melander
FileDescription=Drag and Drop Component Suite
FileVersion=4.0.3.12
InternalName=DragDrop
LegalCopyright=Copyright © 1997-2000, Johnson &amp; Melander
LegalTrademarks=
OriginalFilename=DragDropC4
ProductName=DragDrop
ProductVersion=4.0.0.0
Comments=Freeware.
mailto=anders@melander.dk
URL=http://www.melander.dk
 
[HistoryLists\hlIncludePath]
Count=1
Item0=$(BCB)\include;$(BCB)\include\vcl
 
[HistoryLists\hlLibraryPath]
Count=2
Item0=$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib
Item1=$(BCB)\lib\obj;$(BCB)\lib
 
[HistoryLists\hlDebugSourcePath]
Count=1
Item0=$(BCB)\source\vcl
 
[HistoryLists\hlConditionals]
Count=1
Item0=USEPACKAGES
 
[Debugging]
DebugSourceDirs=$(BCB)\source\vcl
 
[Parameters]
RunParams=
HostApplication=
RemoteHost=
RemotePath=
RemoteDebug=0
 
[Compiler]
ShowInfoMsgs=0
LinkDebugVcl=0
LinkCGLIB=0
 
[CORBA]
AddServerUnit=1
AddClientUnit=1
PrecompiledHeaders=1
 
[Language]
ActiveLang=
ProjectLang=
RootDir=
</IDEOPTIONS>
</PROJECT>
/trunk/VCL_DRAGDROP/DragDropC4.cpp
0,0 → 1,33
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
USERES("dragdropC4.res");
USEUNIT("DragDrop.pas");
USEUNIT("DragDropFile.pas");
USERES("DragDropFile.dcr");
USEUNIT("DragDropFormats.pas");
USEUNIT("DragDropGraphics.pas");
USERES("DragDropGraphics.dcr");
USEUNIT("DragDropPIDL.pas");
USERES("DragDropPIDL.dcr");
USEUNIT("DragDropText.pas");
USERES("DragDropText.dcr");
USEUNIT("DragDropURL.pas");
USERES("DragDropURL.dcr");
USEUNIT("DropMultiTarget.pas");
USERES("DropMultiTarget.dcr");
USEUNIT("DropSource.pas");
USERES("DropSource.dcr");
USEUNIT("DropTarget.pas");
USERES("DropTarget.dcr");
USEPACKAGE("vcl50.bpi");
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
// Package source.
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
return 1;
}
//---------------------------------------------------------------------------
/trunk/VCL_DRAGDROP/DragDropC5.bpk
0,0 → 1,123
<?xml version='1.0' encoding='utf-8' ?>
<!-- C++Builder XML Project -->
<PROJECT>
<MACROS>
<VERSION value="BCB.05.03"/>
<PROJECT value="DragDropC5.bpl"/>
<OBJFILES value="DragDrop.obj DragDropFile.obj DragDropFormats.obj DragDropGraphics.obj
DragDropPIDL.obj DragDropText.obj DropSource.obj DropTarget.obj
DragDropInternet.obj DropComboTarget.obj DragDropHandler.obj DragDropC5.obj"/>
<RESFILES value="DragDropFile.dcr DragDropGraphics.dcr DragDropPIDL.dcr DragDropText.dcr
DropSource.dcr DropTarget.dcr DragDropInternet.dcr DropComboTarget.dcr
DragDropHandler.dcr"/>
<IDLFILES value=""/>
<IDLGENFILES value=""/>
<DEFFILE value=""/>
<RESDEPEN value="$(RESFILES)"/>
<LIBFILES value=""/>
<LIBRARIES value=""/>
<SPARELIBS value="Vcl50.lib"/>
<PACKAGES value="Vcl50.bpi"/>
<PATHCPP value=".;"/>
<PATHPAS value=".;"/>
<PATHRC value=".;"/>
<PATHASM value=".;"/>
<DEBUGLIBPATH value="$(BCB)\lib\debug"/>
<RELEASELIBPATH value="$(BCB)\lib\release"/>
<LINKER value="ilink32"/>
<USERDEFINES value="NO_WIN32_LEAN_AND_MEAN"/>
<SYSDEFINES value="NO_STRICT;USEPACKAGES"/>
<MAINSOURCE value="DragDropC5.cpp"/>
<INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl"/>
<LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
<WARNINGS value="-w-par -w-8027 -w-8026"/>
</MACROS>
<OPTIONS>
<IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -src_suffixcpp
-DNO_WIN32_LEAN_AND_MEAN"/>
<CFLAG1 value="-Od -H=d:\DEVELO~1\rampage\lib\vcl50.csm -Hc -Vx -Ve -Tkh30000 -X- -r- -a8
-b- -k -y -v -vi- -c -tWM"/>
<PFLAGS value="-$YD -$W -$R -$Q -v -M -JPHNE"/>
<RFLAGS value=""/>
<AFLAGS value="/mx /w2 /zd"/>
<LFLAGS value="-D&quot;Drag and Drop Component Suite&quot; -aa -Tpp -Gpd -x -Gn -Gl -Gi"/>
</OPTIONS>
<LINKER>
<ALLOBJ value="c0pkg32.obj $(PACKAGES) sysinit.obj $(OBJFILES)"/>
<ALLRES value="$(RESFILES)"/>
<ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib"/>
</LINKER>
<IDEOPTIONS>
[Version Info]
IncludeVerInfo=0
AutoIncBuild=1
MajorVer=4
MinorVer=0
Release=3
Build=13
Debug=0
PreRelease=0
Special=0
Private=0
DLL=1
Locale=1030
CodePage=1252
 
[Version Info Keys]
CompanyName=Johnson &amp; Melander
FileDescription=Drag and Drop Component Suite
FileVersion=4.0.3.13
InternalName=DragDrop
LegalCopyright=Copyright © 1997-2000, Johnson &amp; Melander
LegalTrademarks=
OriginalFilename=DragDropC4
ProductName=DragDrop
ProductVersion=4.0.0.0
Comments=Freeware.
mailto=anders@melander.dk
URL=http://www.melander.dk
 
[HistoryLists\hlIncludePath]
Count=1
Item0=$(BCB)\include;$(BCB)\include\vcl
 
[HistoryLists\hlLibraryPath]
Count=2
Item0=$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib
Item1=$(BCB)\lib\obj;$(BCB)\lib
 
[HistoryLists\hlDebugSourcePath]
Count=1
Item0=$(BCB)\source\vcl
 
[HistoryLists\hlConditionals]
Count=2
Item0=NO_WIN32_LEAN_AND_MEAN
Item1=USEPACKAGES
 
[Debugging]
DebugSourceDirs=$(BCB)\source\vcl
 
[Parameters]
RunParams=
HostApplication=
RemoteHost=
RemotePath=
RemoteDebug=0
 
[Compiler]
ShowInfoMsgs=1
LinkDebugVcl=0
LinkCGLIB=0
 
[CORBA]
AddServerUnit=1
AddClientUnit=1
PrecompiledHeaders=1
 
[Language]
ActiveLang=
ProjectLang=
RootDir=
</IDEOPTIONS>
</PROJECT>
/trunk/VCL_DRAGDROP/DragDropC5.cpp
0,0 → 1,34
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
USEUNIT("DragDrop.pas");
USEUNIT("DragDropFile.pas");
USERES("DragDropFile.dcr");
USEUNIT("DragDropFormats.pas");
USEUNIT("DragDropGraphics.pas");
USERES("DragDropGraphics.dcr");
USEUNIT("DragDropPIDL.pas");
USERES("DragDropPIDL.dcr");
USEUNIT("DragDropText.pas");
USERES("DragDropText.dcr");
USEUNIT("DropSource.pas");
USERES("DropSource.dcr");
USEUNIT("DropTarget.pas");
USERES("DropTarget.dcr");
USEUNIT("DragDropInternet.pas");
USERES("DragDropInternet.dcr");
USEPACKAGE("Vcl50.bpi");
USEUNIT("DropComboTarget.pas");
USERES("DropComboTarget.dcr");
USEUNIT("DragDropHandler.pas");
USERES("DragDropHandler.dcr");
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
// Package source.
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
return 1;
}
//---------------------------------------------------------------------------
/trunk/VCL_DRAGDROP/DragDropComObj.pas
0,0 → 1,344
unit DragDropComObj;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite.
// Module: DragDropComObj
// Description: Implements misc COM support classes.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
interface
 
uses
ComObj,
Classes,
ActiveX;
 
{$include DragDrop.inc}
 
////////////////////////////////////////////////////////////////////////////////
//
// TVCLComObject
//
////////////////////////////////////////////////////////////////////////////////
// Based on TVCLAutoObject.
////////////////////////////////////////////////////////////////////////////////
type
TVCLComObject = class(TComObject, IVCLComObject, IUnknown)
private
FComponent: TComponent;
FOwnsComponent: Boolean;
protected
// IVCLComObject implementation
procedure FreeOnRelease;
function Invoke(DispID: Integer; const IID: TGUID;
LocaleID: Integer; Flags: Word; var Params;
VarResult, ExcepInfo, ArgErr: Pointer): HResult; virtual; stdcall;
function GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; virtual; stdcall;
function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; virtual; stdcall;
function GetTypeInfoCount(out Count: Integer): HResult; virtual; stdcall;
public
// TODO : For now, please ignore linker warning about TVCLComObject.Create
constructor Create(Factory: TComObjectFactory; Component: TComponent);
destructor Destroy; override;
procedure Initialize; override;
function ObjQueryInterface(const IID: TGUID; out Obj): HResult; override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TVCLComObjectFactory
//
////////////////////////////////////////////////////////////////////////////////
// Class factory for component based COM classes.
// Does not require a type library.
// Based on TComponentFactory and TComObjectFactory.
////////////////////////////////////////////////////////////////////////////////
type
TVCLComObjectFactory = class(TComObjectFactory, IClassFactory)
private
protected
function CreateInstance(const UnkOuter: IUnknown; const IID: TGUID;
out Obj): HResult; stdcall;
public
constructor Create(ComServer: TComServerObject; ComponentClass: TComponentClass;
const ClassID: TGUID; const ClassName, Description: string;
Instancing: TClassInstancing);
function CreateComObject(const Controller: IUnknown): TComObject; override;
procedure UpdateRegistry(Register: Boolean); override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TShellExtFactory
//
////////////////////////////////////////////////////////////////////////////////
// Class factory for component based COM classes.
// Specialized for Shell Extensions.
////////////////////////////////////////////////////////////////////////////////
TShellExtFactory = class(TVCLComObjectFactory)
private
FFileExtension: string;
FFileClass: string;
protected
public
constructor Create(ComServer: TComServerObject; ComponentClass: TComponentClass;
const ClassID: TGUID; const ClassName, Description, AFileClass,
AFileExtension: string; Instancing: TClassInstancing);
procedure UpdateRegistry(Register: Boolean); override;
property FileClass: string read FFileClass write FFileClass;
property FileExtension: string read FFileExtension write FFileExtension;
end;
 
 
 
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
implementation
 
uses
Windows;
 
////////////////////////////////////////////////////////////////////////////////
//
// TVCLComObject
//
////////////////////////////////////////////////////////////////////////////////
constructor TVCLComObject.Create(Factory: TComObjectFactory;
Component: TComponent);
begin
FComponent := Component;
CreateFromFactory(Factory, nil);
end;
 
destructor TVCLComObject.Destroy;
begin
if FComponent <> nil then
begin
FComponent.VCLComObject := nil;
if FOwnsComponent then
FComponent.Free;
end;
inherited Destroy;
end;
 
procedure TVCLComObject.FreeOnRelease;
begin
FOwnsComponent := True;
end;
 
function TVCLComObject.GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
begin
Result := E_NOTIMPL;
end;
 
function TVCLComObject.GetTypeInfo(Index, LocaleID: Integer;
out TypeInfo): HResult;
begin
Pointer(TypeInfo) := nil;
Result := E_NOTIMPL;
end;
 
function TVCLComObject.GetTypeInfoCount(out Count: Integer): HResult;
begin
Count := 0;
Result := E_NOTIMPL;
end;
 
procedure TVCLComObject.Initialize;
begin
inherited Initialize;
if FComponent = nil then
begin
FComponent := TComponentClass(Factory.ComClass).Create(nil);
FOwnsComponent := True;
end;
FComponent.VCLComObject := Pointer(IVCLComObject(Self));
end;
 
function TVCLComObject.Invoke(DispID: Integer; const IID: TGUID;
LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
ArgErr: Pointer): HResult;
begin
Result := E_NOTIMPL;
end;
 
function TVCLComObject.ObjQueryInterface(const IID: TGUID;
out Obj): HResult;
begin
Result := inherited ObjQueryInterface(IID, Obj);
if (Result <> 0) and (FComponent <> nil) then
if FComponent.GetInterface(IID, Obj) then
Result := 0;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TApartmentThread
//
////////////////////////////////////////////////////////////////////////////////
// Copied from VCLCom unit.
////////////////////////////////////////////////////////////////////////////////
type
TApartmentThread = class(TThread)
private
FFactory: IClassFactory2;
FUnkOuter: IUnknown;
FIID: TGuid;
FSemaphore: THandle;
FStream: Pointer;
FCreateResult: HResult;
protected
procedure Execute; override;
public
constructor Create(Factory: IClassFactory2; UnkOuter: IUnknown; IID: TGuid);
destructor Destroy; override;
property Semaphore: THandle read FSemaphore;
property CreateResult: HResult read FCreateResult;
property ObjStream: Pointer read FStream;
end;
 
constructor TApartmentThread.Create(Factory: IClassFactory2;
UnkOuter: IUnknown; IID: TGuid);
begin
FFactory := Factory;
FUnkOuter := UnkOuter;
FIID := IID;
FSemaphore := CreateSemaphore(nil, 0, 1, nil);
FreeOnTerminate := True;
inherited Create(False);
end;
 
destructor TApartmentThread.Destroy;
begin
CloseHandle(FSemaphore);
inherited Destroy;
end;
 
procedure TApartmentThread.Execute;
var
msg: TMsg;
Unk: IUnknown;
begin
try
CoInitialize(nil);
try
FCreateResult := FFactory.CreateInstanceLic(FUnkOuter, nil, FIID, '', Unk);
FUnkOuter := nil;
FFactory := nil;
if FCreateResult = S_OK then
CoMarshalInterThreadInterfaceInStream(FIID, Unk, IStream(FStream));
ReleaseSemaphore(FSemaphore, 1, nil);
if FCreateResult = S_OK then
while GetMessage(msg, 0, 0, 0) do
begin
DispatchMessage(msg);
Unk._AddRef;
if Unk._Release = 1 then break;
end;
finally
Unk := nil;
CoUninitialize;
end;
except
{ No exceptions should go unhandled }
end;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TVCLComObjectFactory
//
////////////////////////////////////////////////////////////////////////////////
constructor TVCLComObjectFactory.Create(ComServer: TComServerObject;
ComponentClass: TComponentClass; const ClassID: TGUID; const ClassName,
Description: string; Instancing: TClassInstancing);
begin
inherited Create(ComServer, TComClass(ComponentClass), ClassID, ClassName,
Description, Instancing, tmApartment);
end;
 
function TVCLComObjectFactory.CreateComObject(const Controller: IUnknown): TComObject;
begin
Result := TVCLComObject.CreateFromFactory(Self, Controller);
end;
 
function TVCLComObjectFactory.CreateInstance(const UnkOuter: IUnknown;
const IID: TGUID; out Obj): HResult;
begin
if not IsLibrary then
begin
LockServer(True);
try
with TApartmentThread.Create(Self, UnkOuter, IID) do
begin
if WaitForSingleObject(Semaphore, INFINITE) = WAIT_OBJECT_0 then
begin
Result := CreateResult;
if Result <> S_OK then Exit;
Result := CoGetInterfaceAndReleaseStream(IStream(ObjStream), IID, Obj);
end else
Result := E_FAIL
end;
finally
LockServer(False);
end;
end else
Result := inherited CreateInstance(UnkOuter, IID, Obj);
end;
 
type
TComponentProtectedAccess = class(TComponent);
TComponentProtectedAccessClass = class of TComponentProtectedAccess;
 
procedure TVCLComObjectFactory.UpdateRegistry(Register: Boolean);
begin
if Register then
inherited UpdateRegistry(Register);
TComponentProtectedAccessClass(ComClass).UpdateRegistry(Register,
GUIDToString(ClassID), ProgID);
if not Register then
inherited UpdateRegistry(Register);
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TShellExtFactory
//
////////////////////////////////////////////////////////////////////////////////
constructor TShellExtFactory.Create(ComServer: TComServerObject;
ComponentClass: TComponentClass; const ClassID: TGUID; const ClassName,
Description, AFileClass, AFileExtension: string; Instancing: TClassInstancing);
begin
inherited Create(ComServer, ComponentClass, ClassID, ClassName,
Description, Instancing);
FFileClass := AFileClass;
FFileExtension := AFileExtension;
end;
 
procedure TShellExtFactory.UpdateRegistry(Register: Boolean);
begin
if Register then
begin
inherited UpdateRegistry(Register);
if (FileExtension <> '') then
CreateRegKey(FileExtension, '', FileClass);
end else
begin
if (FileExtension <> '') then
RegDeleteKey(HKEY_CLASSES_ROOT, PChar(FileExtension));
inherited UpdateRegistry(Register);
end;
end;
 
end.
/trunk/VCL_DRAGDROP/DragDropContext.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDropContext.pas
0,0 → 1,358
unit DragDropContext;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite.
// Module: DragDropContext
// Description: Implements Context Menu Handler Shell Extensions.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
interface
 
uses
DragDrop,
DragDropComObj,
Menus,
ShlObj,
ActiveX,
Windows,
Classes;
 
{$include DragDrop.inc}
 
type
////////////////////////////////////////////////////////////////////////////////
//
// TDropContextMenu
//
////////////////////////////////////////////////////////////////////////////////
// Partially based on Borland's ShellExt demo.
////////////////////////////////////////////////////////////////////////////////
// A typical shell context menu handler session goes like this:
// 1. User selects one or more files and right clicks on them.
// The files must of a file type which has a context menu handler registered.
// 2. The shell loads the context menu handler module.
// 3. The shell instantiates the registered context menu handler object as an
// in-process COM server.
// 4. The IShellExtInit.Initialize method is called with a data object which
// contains the dragged data.
// 5. The IContextMenu.QueryContextMenu method is called to populate the popup
// menu.
// TDropContextMenu uses the PopupMenu property to populate the shell context
// menu.
// 6. If the user chooses one of the context menu menu items we have supplied,
// the IContextMenu.InvokeCommand method is called.
// TDropContextMenu locates the corresponding TMenuItem and fires the menu
// items OnClick event.
// 7. The shell unloads the context menu handler module (usually after a few
// seconds).
////////////////////////////////////////////////////////////////////////////////
TDropContextMenu = class(TInterfacedComponent, IShellExtInit, IContextMenu)
private
FContextMenu: TPopupMenu;
FMenuOffset: integer;
FDataObject: IDataObject;
FOnPopup: TNotifyEvent;
FFiles: TStrings;
procedure SetContextMenu(const Value: TPopupMenu);
protected
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
{ IShellExtInit }
function Initialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult; stdcall;
{ IContextMenu }
function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast,
uFlags: UINT): HResult; stdcall;
function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;
function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
pszName: LPSTR; cchMax: UINT): HResult; stdcall;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property DataObject: IDataObject read FDataObject;
property Files: TStrings read FFiles;
published
property ContextMenu: TPopupMenu read FContextMenu write SetContextMenu;
property OnPopup: TNotifyEvent read FOnPopup write FOnPopup;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropContextMenuFactory
//
////////////////////////////////////////////////////////////////////////////////
// COM Class factory for TDropContextMenu.
////////////////////////////////////////////////////////////////////////////////
TDropContextMenuFactory = class(TShellExtFactory)
protected
function HandlerRegSubKey: string; virtual;
public
procedure UpdateRegistry(Register: Boolean); override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc.
//
////////////////////////////////////////////////////////////////////////////////
 
 
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
implementation
 
uses
DragDropFile,
DragDropPIDL,
Registry,
ComObj,
SysUtils;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
 
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDropContextMenu]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Utilities
//
////////////////////////////////////////////////////////////////////////////////
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropContextMenu
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropContextMenu.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FFiles := TStringList.Create;
end;
 
destructor TDropContextMenu.Destroy;
begin
FFiles.Free;
inherited Destroy;
end;
 
function TDropContextMenu.GetCommandString(idCmd, uType: UINT;
pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult;
var
ItemIndex: integer;
begin
ItemIndex := integer(idCmd);
// Make sure we aren't being passed an invalid argument number
if (ItemIndex >= 0) and (ItemIndex < FContextMenu.Items.Count) then
begin
if (uType = GCS_HELPTEXT) then
// return help string for menu item.
StrLCopy(pszName, PChar(FContextMenu.Items[ItemIndex].Hint), cchMax);
Result := NOERROR;
end else
Result := E_INVALIDARG;
end;
 
function TDropContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
var
ItemIndex: integer;
begin
Result := E_FAIL;
 
// Make sure we are not being called by an application
if (FContextMenu = nil) or (HiWord(Integer(lpici.lpVerb)) <> 0) then
Exit;
 
ItemIndex := LoWord(lpici.lpVerb);
// Make sure we aren't being passed an invalid argument number
if (ItemIndex < 0) or (ItemIndex >= FContextMenu.Items.Count) then
begin
Result := E_INVALIDARG;
Exit;
end;
 
// Execute the menu item specified by lpici.lpVerb.
try
try
FContextMenu.Items[ItemIndex].Click;
Result := NOERROR;
except
on E: Exception do
begin
Windows.MessageBox(0, PChar(E.Message), 'Error',
MB_OK or MB_ICONEXCLAMATION or MB_SYSTEMMODAL);
Result := E_UNEXPECTED;
end;
end;
finally
FDataObject := nil;
FFiles.Clear;
end;
end;
 
function TDropContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,
idCmdLast, uFlags: UINT): HResult;
var
i: integer;
Last: integer;
Flags: UINT;
 
function IsLine(Item: TMenuItem): boolean;
begin
{$ifdef VER13_PLUS}
Result := Item.IsLine;
{$else}
Result := Item.Caption = '-';
{$endif}
end;
 
begin
Last := 0;
 
if (FContextMenu <> nil) and (((uFlags and $0000000F) = CMF_NORMAL) or
((uFlags and CMF_EXPLORE) <> 0)) then
begin
FMenuOffset := idCmdFirst;
for i := 0 to FContextMenu.Items.Count-1 do
if (FContextMenu.Items[i].Visible) then
begin
Flags := MF_STRING or MF_BYPOSITION;
if (not FContextMenu.Items[i].Enabled) then
Flags := Flags or MF_GRAYED;
if (IsLine(FContextMenu.Items[i])) then
Flags := Flags or MF_SEPARATOR;
// Add one menu item to context menu
InsertMenu(Menu, indexMenu, Flags, FMenuOffset+i,
PChar(FContextMenu.Items[i].Caption));
inc(indexMenu);
Last := i+1;
end;
end else
FMenuOffset := 0;
 
// Return number of menu items added
Result := MakeResult(SEVERITY_SUCCESS, FACILITY_NULL, Last)
end;
 
function TDropContextMenu.Initialize(pidlFolder: PItemIDList;
lpdobj: IDataObject; hKeyProgID: HKEY): HResult;
begin
FFiles.Clear;
 
if (lpdobj = nil) then
begin
Result := E_INVALIDARG;
Exit;
end;
 
// Save a reference to the source data object.
FDataObject := lpdobj;
 
// Extract source file names and store them in a string list.
with TFileDataFormat.Create(nil) do
try
if GetData(DataObject) then
FFiles.Assign(Files);
finally
Free;
end;
 
if (Assigned(FOnPopup)) then
FOnPopup(Self);
 
Result := NOERROR;
end;
 
procedure TDropContextMenu.SetContextMenu(const Value: TPopupMenu);
begin
if (Value <> FContextMenu) then
begin
if (FContextMenu <> nil) then
FContextMenu.RemoveFreeNotification(Self);
FContextMenu := Value;
if (Value <> nil) then
Value.FreeNotification(Self);
end;
end;
 
procedure TDropContextMenu.Notification(AComponent: TComponent;
Operation: TOperation);
begin
if (Operation = opRemove) and (AComponent = FContextMenu) then
FContextMenu := nil;
inherited;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropContextMenuFactory
//
////////////////////////////////////////////////////////////////////////////////
function TDropContextMenuFactory.HandlerRegSubKey: string;
begin
Result := 'ContextMenuHandlers';
end;
 
procedure TDropContextMenuFactory.UpdateRegistry(Register: Boolean);
var
ClassIDStr: string;
begin
ClassIDStr := GUIDToString(ClassID);
if Register then
begin
inherited UpdateRegistry(Register);
CreateRegKey(FileClass+'\shellex\'+HandlerRegSubKey+'\'+ClassName, '', ClassIDStr);
 
if (Win32Platform = VER_PLATFORM_WIN32_NT) then
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE;
OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions', True);
OpenKey('Approved', True);
WriteString(ClassIDStr, Description);
finally
Free;
end;
end else
begin
if (Win32Platform = VER_PLATFORM_WIN32_NT) then
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE;
OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions', True);
OpenKey('Approved', True);
DeleteKey(ClassIDStr);
finally
Free;
end;
DeleteRegKey(FileClass+'\shellex\'+HandlerRegSubKey+'\'+ClassName);
inherited UpdateRegistry(Register);
end;
end;
 
end.
/trunk/VCL_DRAGDROP/DragDropD3.dof
0,0 → 1,80
[Compiler]
A=1
B=0
C=1
D=1
E=0
F=0
G=1
H=1
I=1
J=1
K=0
L=1
M=0
N=1
O=1
P=1
Q=1
R=1
S=0
T=0
U=0
V=1
W=0
X=1
Y=1
Z=1
ShowHints=1
ShowWarnings=1
UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
[Linker]
MapFile=0
OutputObjs=0
ConsoleApp=1
DebugInfo=0
RemoteSymbols=0
MinStackSize=16384
MaxStackSize=1048576
ImageBase=4194304
ExeDescription=COM DragDrop components
[Directories]
OutputDir=
UnitOutputDir=
PackageDLLOutputDir=
PackageDCPOutputDir=
SearchPath=
Packages=
Conditionals=
DebugSourceDirs=
UsePackages=0
[Parameters]
RunParams=
HostApplication=
[Version Info]
IncludeVerInfo=1
AutoIncBuild=1
MajorVer=3
MinorVer=4
Release=1
Build=8
Debug=0
PreRelease=0
Special=0
Private=0
DLL=1
Locale=1033
CodePage=1252
[Version Info Keys]
CompanyName=Johnson, Melander & Wideman
FileDescription=COM DragDrop components
FileVersion=3.4.1.8
InternalName=DragDrop
LegalCopyright=Copyright © 1997-99, Johnson, Melander & Wideman
LegalTrademarks=
OriginalFilename=DragDrop
ProductName=DragDrop
ProductVersion=1.0.0.0
Comments=Freeware.
mailto=ajohnson@rpi.net.au ; anders@melander.dk ; graham@sdsu.edu
URL=http://www.melander.dk
/trunk/VCL_DRAGDROP/DragDropD3.dpk
0,0 → 1,50
package DragDropD3;
 
{$R *.RES}
{$R 'DropSource.dcr'}
{$R 'DropTarget.dcr'}
{$R 'DropBMPSource.dcr'}
{$R 'DropBMPTarget.dcr'}
{$R 'DropURLSource.dcr'}
{$R 'DropURLTarget.dcr'}
{$R 'DropPIDLSource.dcr'}
{$R 'DropPIDLTarget.dcr'}
{$ALIGN ON}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO ON}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS ON}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION ON}
{$OVERFLOWCHECKS ON}
{$RANGECHECKS ON}
{$REFERENCEINFO OFF}
{$SAFEDIVIDE OFF}
{$STACKFRAMES OFF}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST ON}
{$MINENUMSIZE 1}
{$IMAGEBASE $00400000}
{$DESCRIPTION 'Drag and Drop Component Suite'}
{$DESIGNONLY}
{$IMPLICITBUILD ON}
 
requires
vcl30;
 
contains
DropSource,
DropTarget,
DropBMPSource,
DropBMPTarget,
DropURLSource,
DropURLTarget,
DropPIDLSource,
DropPIDLTarget;
 
end.
/trunk/VCL_DRAGDROP/DragDropD3.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDropD4.dof
0,0 → 1,89
[Compiler]
A=1
B=0
C=1
D=1
E=0
F=0
G=1
H=1
I=1
J=1
K=0
L=0
M=0
N=1
O=0
P=1
Q=1
R=1
S=0
T=0
U=0
V=1
W=0
X=1
Y=1
Z=1
ShowHints=1
ShowWarnings=1
UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
[Linker]
MapFile=0
OutputObjs=0
ConsoleApp=1
DebugInfo=0
RemoteSymbols=0
MinStackSize=16384
MaxStackSize=1048576
ImageBase=4259840
ExeDescription=Drag and Drop Component Suite
[Directories]
OutputDir=
UnitOutputDir=
PackageDLLOutputDir=
PackageDCPOutputDir=
SearchPath=
Packages=
Conditionals=
DebugSourceDirs=
UsePackages=0
[Parameters]
RunParams=
HostApplication=
[Version Info]
IncludeVerInfo=1
AutoIncBuild=1
MajorVer=4
MinorVer=0
Release=3
Build=11
Debug=0
PreRelease=0
Special=0
Private=0
DLL=1
Locale=1033
CodePage=1252
[Version Info Keys]
CompanyName=Anders melander
FileDescription=Drag and Drop Component Suite
FileVersion=4.0.3.11
InternalName=DragDrop
LegalCopyright=Copyright © 1997-2000 Angus Johnson & Anders Melander
LegalTrademarks=
OriginalFilename=DragDrop
ProductName=DragDrop
ProductVersion=1.0.0.0
Comments=Freeware.
mailto=anders@melander.dk
URL=http://www.melander.dk
[Excluded Packages]
$(DELPHI)\Bin\dcltee40.bpl=Borland TeeChart Components
$(DELPHI)\Bin\dcldss40.bpl=Borland Decision Cube Components
[HistoryLists\hlDebugSourcePath]
Count=1
Item0=$(DELPHI)\source\vcl;$(DELPHI)\source\rtl\win
[HistoryLists\hlUnitAliases]
Count=1
Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
/trunk/VCL_DRAGDROP/DragDropD4.dpk
0,0 → 1,61
package DragDropD4;
 
{$R *.RES}
{$R 'DragDrop.dcr'}
{$R 'DropSource.dcr'}
{$R 'DropTarget.dcr'}
{$R 'DragDropText.dcr'}
{$R 'DragDropFile.dcr'}
{$R 'DragDropGraphics.dcr'}
{$R 'DragDropPIDL.dcr'}
{$R 'DragDropInternet.dcr'}
{$R 'DropComboTarget.dcr'}
{$R 'DragDropHandler.dcr'}
{$R 'DragDropContext.dcr'}
{$ALIGN ON}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO ON}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS OFF}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION OFF}
{$OVERFLOWCHECKS ON}
{$RANGECHECKS ON}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES OFF}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST ON}
{$MINENUMSIZE 1}
{$IMAGEBASE $00410000}
{$DESCRIPTION 'Drag and Drop Component Suite'}
{$DESIGNONLY}
{$IMPLICITBUILD OFF}
 
requires
Vcl40;
 
contains
DropSource in 'DropSource.pas',
DropTarget in 'DropTarget.pas',
DragDropPIDL in 'DragDropPIDL.pas',
DragDropFormats in 'DragDropFormats.pas',
DragDropFile in 'DragDropFile.pas',
DragDropText in 'DragDropText.pas',
DragDrop in 'DragDrop.pas',
DragDropGraphics in 'DragDropGraphics.pas',
DropSource3 in 'DropSource3.pas',
DropFileSource3 in 'DropFileSource3.pas',
DragDropInternet in 'DragDropInternet.pas',
DragDropDesign in 'DragDropDesign.pas',
DropComboTarget in 'DropComboTarget.pas',
DragDropHandler in 'DragDropHandler.pas',
DragDropContext in 'DragDropContext.pas',
DragDropComObj in 'DragDropComObj.pas';
 
end.
/trunk/VCL_DRAGDROP/DragDropD4.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDropD5.cfg
0,0 → 1,36
-$A+
-$B-
-$C+
-$D+
-$E-
-$F-
-$G+
-$H+
-$I+
-$J+
-$K-
-$L-
-$M-
-$N+
-$O+
-$P+
-$Q+
-$R+
-$S-
-$T-
-$U-
-$V+
-$W-
-$X+
-$YD
-$Z1
-cg
-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
-H+
-W+
-M
-$M16384,1048576
-K$00400000
-LE"c:\programme\borland\delphi5\Projects\Bpl"
-LN"c:\programme\borland\delphi5\Projects\Bpl"
-Z
/trunk/VCL_DRAGDROP/DragDropD5.dof
0,0 → 1,94
[Compiler]
A=1
B=0
C=1
D=1
E=0
F=0
G=1
H=1
I=1
J=0
K=0
L=0
M=0
N=1
O=0
P=1
Q=1
R=1
S=0
T=0
U=0
V=1
W=0
X=1
Y=1
Z=1
ShowHints=1
ShowWarnings=1
UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
[Linker]
MapFile=0
OutputObjs=0
ConsoleApp=1
DebugInfo=0
RemoteSymbols=0
MinStackSize=16384
MaxStackSize=1048576
ImageBase=4259840
ExeDescription=Drag and Drop Component Suite
[Directories]
OutputDir=
UnitOutputDir=
PackageDLLOutputDir=
PackageDCPOutputDir=
SearchPath=$(DELPHI)\Lib\Debug
Packages=
Conditionals=
DebugSourceDirs=
UsePackages=0
[Parameters]
RunParams=
HostApplication=
[Language]
ActiveLang=
ProjectLang=00000406
RootDir=
[Version Info]
IncludeVerInfo=1
AutoIncBuild=1
MajorVer=4
MinorVer=0
Release=3
Build=19
Debug=0
PreRelease=0
Special=0
Private=0
DLL=1
Locale=1033
CodePage=1252
[Version Info Keys]
CompanyName=Anders Melander
FileDescription=Drag and Drop Component Suite
FileVersion=4.0.3.19
InternalName=DragDrop
LegalCopyright=Copyright © 1997-2000 Angus Johnson & Anders Melander
LegalTrademarks=
OriginalFilename=DragDrop
ProductName=DragDrop
ProductVersion=4.0.0.0
Comments=Freeware.
mailto=anders@melander.dk
URL=http://www.melander.dk
[Excluded Packages]
$(DELPHI)\Projects\Bpl\sbServerPackage.bpl=S-BOSS Server side components
D:\Projects\SkilteDesigner\Bin\DCDComponents.bpl=S-BOSS Designer Components
D:\Library\Delphi3\DragDrop\Competition\UnitOOPS\OLEDD\D5\uoolep5.bpl=UnitOOPS OLE Drag and Drop Components for Delphi 5
[HistoryLists\hlUnitAliases]
Count=1
Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
[HistoryLists\hlSearchPath]
Count=1
Item0=$(DELPHI)\Lib\Debug
/trunk/VCL_DRAGDROP/DragDropD5.dpk
0,0 → 1,61
package DragDropD5;
 
{$R *.RES}
{$R 'DragDrop.dcr'}
{$R 'DropSource.dcr'}
{$R 'DropTarget.dcr'}
{$R 'DragDropText.dcr'}
{$R 'DragDropFile.dcr'}
{$R 'DragDropGraphics.dcr'}
{$R 'DragDropPIDL.dcr'}
{$R 'DragDropInternet.dcr'}
{$R 'DropComboTarget.dcr'}
{$R 'DragDropHandler.dcr'}
{$R 'DragDropContext.dcr'}
{$R 'DropHandler.dcr'}
{$ALIGN ON}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO ON}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS OFF}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION OFF}
{$OVERFLOWCHECKS ON}
{$RANGECHECKS ON}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES OFF}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $410000}
{$DESCRIPTION 'Drag and Drop Component Suite'}
{$DESIGNONLY}
{$IMPLICITBUILD OFF}
 
requires
Vcl50;
 
contains
DropSource in 'DropSource.pas',
DropTarget in 'DropTarget.pas',
DragDropPIDL in 'DragDropPIDL.pas',
DragDropFormats in 'DragDropFormats.pas',
DragDropFile in 'DragDropFile.pas',
DragDropText in 'DragDropText.pas',
DragDrop in 'DragDrop.pas',
DragDropGraphics in 'DragDropGraphics.pas',
DragDropInternet in 'DragDropInternet.pas',
DropComboTarget in 'DropComboTarget.pas',
DragDropDesign in 'DragDropDesign.pas',
DragDropHandler in 'DragDropHandler.pas',
DragDropComObj in 'DragDropComObj.pas',
DragDropContext in 'DragDropContext.pas',
DropHandler in 'DropHandler.pas';
 
end.
/trunk/VCL_DRAGDROP/DragDropD5.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDropD5.~dpk
0,0 → 1,49
package DragDropD5;
 
{$R *.RES}
{$R 'DropSource.dcr'}
{$R 'DropTarget.dcr'}
{$R 'DropBMPSource.dcr'}
{$R 'DropBMPTarget.dcr'}
{$R 'DropURLSource.dcr'}
{$R 'DropURLTarget.dcr'}
{$R 'DropPIDLSource.dcr'}
{$R 'DropPIDLTarget.dcr'}
{$ALIGN ON}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO ON}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS OFF}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION ON}
{$OVERFLOWCHECKS ON}
{$RANGECHECKS ON}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES OFF}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST ON}
{$MINENUMSIZE 1}
{$IMAGEBASE $400000}
{$DESCRIPTION 'Drag and Drop Component Suite'}
{$IMPLICITBUILD OFF}
 
requires
Vcl50;
 
contains
DropSource in 'DropSource.pas',
DropTarget in 'DropTarget.pas',
DropBMPSource in 'DropBMPSource.pas',
DropBMPTarget in 'DropBMPTarget.pas',
DropURLSource in 'DropURLSource.pas',
DropURLTarget in 'DropURLTarget.pas',
DropPIDLSource in 'DropPIDLSource.pas',
DropPIDLTarget in 'DropPIDLTarget.pas';
 
end.
/trunk/VCL_DRAGDROP/DragDropD6.cfg
0,0 → 1,36
-$A8
-$B-
-$C+
-$D+
-$E-
-$F-
-$G+
-$H+
-$I+
-$J+
-$K-
-$L-
-$M-
-$N+
-$O+
-$P+
-$Q+
-$R+
-$S-
-$T-
-$U-
-$V+
-$W-
-$X+
-$YD
-$Z1
-cg
-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
-H+
-W+
-M
-$M16384,1048576
-K$00400000
-LE"c:\programme\borland\delphi6\Projects\Bpl"
-LN"c:\programme\borland\delphi6\Projects\Bpl"
-Z
/trunk/VCL_DRAGDROP/DragDropD6.dof
0,0 → 1,98
[FileVersion]
Version=6.0
[Compiler]
A=4
B=0
C=1
D=1
E=0
F=0
G=0
H=1
I=1
J=0
K=0
L=1
M=0
N=1
O=0
P=1
Q=1
R=1
S=0
T=1
U=0
V=1
W=1
X=1
Y=1
Z=1
ShowHints=1
ShowWarnings=1
UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
[Linker]
MapFile=0
OutputObjs=0
ConsoleApp=1
DebugInfo=0
RemoteSymbols=0
MinStackSize=16384
MaxStackSize=1048576
ImageBase=4548489
ExeDescription=Drag and Drop Component Suite
[Directories]
OutputDir=
UnitOutputDir=
PackageDLLOutputDir=
PackageDCPOutputDir=
SearchPath=$(DELPHI)\Lib\Debug
Packages=
Conditionals=DEBUG
DebugSourceDirs=
UsePackages=0
[Parameters]
RunParams=
HostApplication=
Launcher=
UseLauncher=0
DebugCWD=
[Language]
ActiveLang=
ProjectLang=
RootDir=
[Version Info]
IncludeVerInfo=1
AutoIncBuild=1
MajorVer=4
MinorVer=0
Release=3
Build=27
Debug=0
PreRelease=0
Special=0
Private=0
DLL=1
Locale=1033
CodePage=1252
[Version Info Keys]
CompanyName=Anders Melander
FileDescription=Drag and Drop Component Suite
FileVersion=4.0.3.27
InternalName=DragDrop
LegalCopyright=Copyright © 1997-2001 Anders Melander
LegalTrademarks=
OriginalFilename=DragDrop
ProductName=DragDrop
ProductVersion=4.0.0.0
Comments=This is freeware. Use as you please, but please give me credit.
mailto=anders@melander.dk
URL=http://www.melander.dk
[HistoryLists\hlConditionals]
Count=1
Item0=DEBUG
[HistoryLists\hlUnitAliases]
Count=1
Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
[HistoryLists\hlSearchPath]
Count=1
Item0=$(DELPHI)\Lib\Debug
/trunk/VCL_DRAGDROP/DragDropD6.dpk
0,0 → 1,61
package DragDropD6;
 
{$R *.res}
{$R 'DragDrop.dcr'}
{$R 'DropSource.dcr'}
{$R 'DropTarget.dcr'}
{$R 'DragDropText.dcr'}
{$R 'DragDropFile.dcr'}
{$R 'DragDropGraphics.dcr'}
{$R 'DragDropPIDL.dcr'}
{$R 'DragDropInternet.dcr'}
{$R 'DropComboTarget.dcr'}
{$R 'DragDropHandler.dcr'}
{$R 'DragDropContext.dcr'}
{$R 'DropHandler.dcr'}
{$ALIGN 4}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO ON}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA OFF}
{$IOCHECKS ON}
{$LOCALSYMBOLS ON}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION OFF}
{$OVERFLOWCHECKS ON}
{$RANGECHECKS ON}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES ON}
{$TYPEDADDRESS ON}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $456789}
{$DESCRIPTION 'Drag and Drop Component Suite'}
{$DESIGNONLY}
{$IMPLICITBUILD OFF}
{$DEFINE DEBUG}
 
requires
Vcl;
 
contains
DropSource in 'DropSource.pas',
DropTarget in 'DropTarget.pas',
DragDropPIDL in 'DragDropPIDL.pas',
DragDropFormats in 'DragDropFormats.pas',
DropComboTarget in 'DropComboTarget.pas',
DragDropFile in 'DragDropFile.pas',
DragDropText in 'DragDropText.pas',
DragDrop in 'DragDrop.pas',
DragDropGraphics in 'DragDropGraphics.pas',
DragDropInternet in 'DragDropInternet.pas',
DragDropContext in 'DragDropContext.pas',
DragDropHandler in 'DragDropHandler.pas',
DragDropComObj in 'DragDropComObj.pas',
DropHandler in 'DropHandler.pas';
 
end.
/trunk/VCL_DRAGDROP/DragDropD6.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDropDesign.pas
0,0 → 1,68
unit DragDropDesign;
// -----------------------------------------------------------------------------
//
// NOT FOR RELEASE
//
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Module: DragDropDesign
// Description: Contains design-time support for the drag and drop
// components.
// Version: 4.0
// Date: 25-JUN-2000
// Target: Win32, Delphi 3-6 and C++ Builder 3-5
// Authors: Angus Johnson, ajohnson@rpi.net.au
// Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2000 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
interface
 
procedure Register;
 
implementation
 
{$include DragDrop.inc}
 
uses
DragDrop,
{$ifndef VER14_PLUS}
DsgnIntf,
{$else}
DesignIntf,
DesignEditors,
{$endif}
Classes;
 
type
TDataFormatNameEditor = class(TStringProperty)
public
function GetAttributes: TPropertyAttributes; override;
procedure GetValues(Proc: TGetStrProc); override;
end;
 
procedure Register;
begin
RegisterPropertyEditor(TypeInfo(string), TDataFormatAdapter, 'DataFormatName',
TDataFormatNameEditor);
end;
 
{ TDataFormatNameEditor }
 
function TDataFormatNameEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paValueList, paSortList, paMultiSelect];
end;
 
type
TDataFormatClassesCracker = class(TDataFormatClasses);
 
procedure TDataFormatNameEditor.GetValues(Proc: TGetStrProc);
var
i : Integer;
begin
for i := 0 to TDataFormatClassesCracker.Instance.Count-1 do
Proc(TDataFormatClassesCracker.Instance[i].ClassName);
end;
 
end.
/trunk/VCL_DRAGDROP/DragDropFile.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDropFile.pas
0,0 → 1,858
unit DragDropFile;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite.
// Module: DragDropFile
// Description: Implements Dragging and Dropping of files and folders.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
interface
 
uses
DragDrop,
DropTarget,
DropSource,
DragDropFormats,
ActiveX,
Windows,
Classes;
 
type
////////////////////////////////////////////////////////////////////////////////
//
// TFileClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TFileClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FFiles: TStrings;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
public
constructor Create; override;
destructor Destroy; override;
function GetClipboardFormat: TClipFormat; override;
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
property Files: TStrings read FFiles;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFilenameClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TFilenameClipboardFormat = class(TCustomTextClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property Filename: string read GetString write SetString;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFilenameWClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TFilenameWClipboardFormat = class(TCustomWideTextClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property Filename: WideString read GetText write SetText;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFilenameMapClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// DONE -oanme -cStopShip : Rename TFilenameMapClipboardFormat to TFilenameMapClipboardFormat. Also wide version.
TFilenameMapClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FFileMaps : TStrings;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
public
constructor Create; override;
destructor Destroy; override;
function GetClipboardFormat: TClipFormat; override;
procedure Clear; override;
function HasData: boolean; override;
property FileMaps: TStrings read FFileMaps;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFilenameMapWClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TFilenameMapWClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FFileMaps : TStrings;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
public
constructor Create; override;
destructor Destroy; override;
function GetClipboardFormat: TClipFormat; override;
procedure Clear; override;
function HasData: boolean; override;
property FileMaps: TStrings read FFileMaps;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileMapDataFormat
//
////////////////////////////////////////////////////////////////////////////////
TFileMapDataFormat = class(TCustomDataFormat)
private
FFileMaps : TStrings;
public
constructor Create(AOwner: TDragDropComponent); override;
destructor Destroy; override;
function Assign(Source: TClipboardFormat): boolean; override;
function AssignTo(Dest: TClipboardFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property FileMaps: TStrings read FFileMaps;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileDataFormat
//
////////////////////////////////////////////////////////////////////////////////
TFileDataFormat = class(TCustomDataFormat)
private
FFiles : TStrings;
protected
public
constructor Create(AOwner: TDragDropComponent); override;
destructor Destroy; override;
function Assign(Source: TClipboardFormat): boolean; override;
function AssignTo(Dest: TClipboardFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property Files: TStrings read FFiles;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropFileTarget
//
////////////////////////////////////////////////////////////////////////////////
TDropFileTarget = class(TCustomDropMultiTarget)
private
FFileFormat : TFileDataFormat;
FFileMapFormat : TFileMapDataFormat;
protected
function GetFiles: TStrings;
function GetMappedNames: TStrings;
function GetPreferredDropEffect: LongInt; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Files: TStrings read GetFiles;
property MappedNames: TStrings read GetMappedNames;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropFileSource
//
////////////////////////////////////////////////////////////////////////////////
TDropFileSource = class(TCustomDropMultiSource)
private
FFileFormat : TFileDataFormat;
FFileMapFormat : TFileMapDataFormat;
function GetFiles: TStrings;
function GetMappedNames: TStrings;
protected
procedure SetFiles(AFiles: TStrings);
procedure SetMappedNames(ANames: TStrings);
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
published
property Files: TStrings read GetFiles write SetFiles;
// MappedNames is only needed if files need to be renamed during a drag op.
// E.g. dragging from 'Recycle Bin'.
property MappedNames: TStrings read GetMappedNames write SetMappedNames;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc.
//
////////////////////////////////////////////////////////////////////////////////
function ReadFilesFromHGlobal(const HGlob: HGlobal; Files: TStrings): boolean; // V4: renamed
function ReadFilesFromData(Data: pointer; Size: integer; Files: TStrings): boolean;
function ReadFilesFromZeroList(Data: pointer; Size: integer;
Wide: boolean; Files: TStrings): boolean;
function WriteFilesToZeroList(Data: pointer; Size: integer;
Wide: boolean; Files: TStrings): boolean;
 
 
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
implementation
 
uses
DragDropPIDL,
SysUtils,
ShlObj;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
 
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDropFileTarget,
TDropFileSource]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Utilities
//
////////////////////////////////////////////////////////////////////////////////
 
function ReadFilesFromHGlobal(const HGlob: HGlobal; Files: TStrings): boolean;
var
DropFiles : PDropFiles;
begin
DropFiles := PDropFiles(GlobalLock(HGlob));
try
Result := ReadFilesFromData(DropFiles, GlobalSize(HGlob), Files)
finally
GlobalUnlock(HGlob);
end;
end;
 
function ReadFilesFromData(Data: pointer; Size: integer; Files: TStrings): boolean;
var
Wide : boolean;
begin
Files.Clear;
if (Data <> nil) then
begin
Wide := PDropFiles(Data)^.fWide;
dec(Size, PDropFiles(Data)^.pFiles);
inc(PChar(Data), PDropFiles(Data)^.pFiles);
ReadFilesFromZeroList(Data, Size, Wide, Files);
end;
 
Result := (Files.Count > 0);
end;
 
function ReadFilesFromZeroList(Data: pointer; Size: integer;
Wide: boolean; Files: TStrings): boolean;
var
StringSize : integer;
begin
Result := False;
if (Data <> nil) then
while (Size > 0) and (PChar(Data)^ <> #0) do
begin
if (Wide) then
begin
Files.Add(PWideChar(Data));
StringSize := (Length(PWideChar(Data)) + 1) * 2;
end else
begin
Files.Add(PChar(Data));
StringSize := Length(PChar(Data)) + 1;
end;
inc(PChar(Data), StringSize);
dec(Size, StringSize);
Result := True;
end;
end;
 
function WriteFilesToZeroList(Data: pointer; Size: integer;
Wide: boolean; Files: TStrings): boolean;
var
i : integer;
begin
Result := False;
if (Data <> nil) then
begin
i := 0;
dec(Size);
while (Size > 0) and (i < Files.Count) do
begin
if (Wide) then
begin
StringToWideChar(Files[i], Data, Size);
dec(Size, (Length(Files[i])+1)*2);
end else
begin
StrPLCopy(Data, Files[i], Size);
dec(Size, Length(Files[i])+1);
end;
inc(PChar(Data), Length(Files[i])+1);
inc(i);
Result := True;
end;
 
// Final teminating zero.
if (Size >= 0) then
PChar(Data)^ := #0;
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TFileClipboardFormat.Create;
begin
inherited Create;
FFiles := TStringList.Create;
// Note: Setting dwAspect to DVASPECT_SHORT will request that the data source
// returns the file names in short (8.3) format.
// FFormatEtc.dwAspect := DVASPECT_SHORT;
end;
 
destructor TFileClipboardFormat.Destroy;
begin
FFiles.Free;
inherited Destroy;
end;
 
function TFileClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := CF_HDROP;
end;
 
procedure TFileClipboardFormat.Clear;
begin
FFiles.Clear;
end;
 
function TFileClipboardFormat.HasData: boolean;
begin
Result := (FFiles.Count > 0);
end;
 
function TFileClipboardFormat.GetSize: integer;
var
i : integer;
begin
Result := SizeOf(TDropFiles) + FFiles.Count + 1;
for i := 0 to FFiles.Count-1 do
inc(Result, Length(FFiles[i]));
end;
 
function TFileClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
Result := (Size > SizeOf(TDropFiles));
if (not Result) then
exit;
 
Result := ReadFilesFromData(Value, Size, FFiles);
end;
 
function TFileClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
begin
Result := (Size > SizeOf(TDropFiles));
if (not Result) then
exit;
 
PDropFiles(Value)^.pfiles := SizeOf(TDropFiles);
PDropFiles(Value)^.fwide := False;
inc(PChar(Value), SizeOf(TDropFiles));
dec(Size, SizeOf(TDropFiles));
 
WriteFilesToZeroList(Value, Size, False, FFiles);
end;
 
function TFileClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
if (Source is TFileDataFormat) then
begin
FFiles.Assign(TFileDataFormat(Source).Files);
Result := True;
end else
Result := inherited Assign(Source);
end;
 
function TFileClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
if (Dest is TFileDataFormat) then
begin
TFileDataFormat(Dest).Files.Assign(FFiles);
Result := True;
end else
Result := inherited AssignTo(Dest);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFilenameClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_FILENAMEA: TClipFormat = 0;
 
function TFilenameClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_FILENAMEA = 0) then
CF_FILENAMEA := RegisterClipboardFormat(CFSTR_FILENAMEA);
Result := CF_FILENAMEA;
end;
 
function TFilenameClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
if (Source is TFileDataFormat) then
begin
Result := (TFileDataFormat(Source).Files.Count > 0);
if (Result) then
Filename := TFileDataFormat(Source).Files[0];
end else
Result := inherited Assign(Source);
end;
 
function TFilenameClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
if (Dest is TFileDataFormat) then
begin
TFileDataFormat(Dest).Files.Add(Filename);
Result := True;
end else
Result := inherited AssignTo(Dest);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFilenameWClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_FILENAMEW: TClipFormat = 0;
 
function TFilenameWClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_FILENAMEW = 0) then
CF_FILENAMEW := RegisterClipboardFormat(CFSTR_FILENAMEW);
Result := CF_FILENAMEW;
end;
 
function TFilenameWClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
if (Source is TFileDataFormat) then
begin
Result := (TFileDataFormat(Source).Files.Count > 0);
if (Result) then
Filename := TFileDataFormat(Source).Files[0];
end else
Result := inherited Assign(Source);
end;
 
function TFilenameWClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
if (Dest is TFileDataFormat) then
begin
TFileDataFormat(Dest).Files.Add(Filename);
Result := True;
end else
Result := inherited AssignTo(Dest);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFilenameMapClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_FILENAMEMAP: TClipFormat = 0;
 
constructor TFilenameMapClipboardFormat.Create;
begin
inherited Create;
FFileMaps := TStringList.Create;
end;
 
destructor TFilenameMapClipboardFormat.Destroy;
begin
FFileMaps.Free;
inherited Destroy;
end;
 
function TFilenameMapClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_FILENAMEMAP = 0) then
CF_FILENAMEMAP := RegisterClipboardFormat(CFSTR_FILENAMEMAPA);
Result := CF_FILENAMEMAP;
end;
 
procedure TFilenameMapClipboardFormat.Clear;
begin
FFileMaps.Clear;
end;
 
function TFilenameMapClipboardFormat.HasData: boolean;
begin
Result := (FFileMaps.Count > 0);
end;
 
function TFilenameMapClipboardFormat.GetSize: integer;
var
i : integer;
begin
Result := FFileMaps.Count + 1;
for i := 0 to FFileMaps.Count-1 do
inc(Result, Length(FFileMaps[i]));
end;
 
function TFilenameMapClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
Result := ReadFilesFromZeroList(Value, Size, False, FFileMaps);
end;
 
function TFilenameMapClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
begin
Result := WriteFilesToZeroList(Value, Size, False, FFileMaps);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFilenameMapWClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_FILENAMEMAPW: TClipFormat = 0;
 
constructor TFilenameMapWClipboardFormat.Create;
begin
inherited Create;
FFileMaps := TStringList.Create;
end;
 
destructor TFilenameMapWClipboardFormat.Destroy;
begin
FFileMaps.Free;
inherited Destroy;
end;
 
function TFilenameMapWClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_FILENAMEMAPW = 0) then
CF_FILENAMEMAPW := RegisterClipboardFormat(CFSTR_FILENAMEMAPW);
Result := CF_FILENAMEMAPW;
end;
 
procedure TFilenameMapWClipboardFormat.Clear;
begin
FFileMaps.Clear;
end;
 
function TFilenameMapWClipboardFormat.HasData: boolean;
begin
Result := (FFileMaps.Count > 0);
end;
 
function TFilenameMapWClipboardFormat.GetSize: integer;
var
i : integer;
begin
Result := FFileMaps.Count + 1;
for i := 0 to FFileMaps.Count-1 do
inc(Result, Length(FFileMaps[i]));
inc(Result, Result);
end;
 
function TFilenameMapWClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
Result := ReadFilesFromZeroList(Value, Size, True, FFileMaps);
end;
 
function TFilenameMapWClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
begin
Result := WriteFilesToZeroList(Value, Size, True, FFileMaps);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileMapDataFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TFileMapDataFormat.Create(AOwner: TDragDropComponent);
begin
inherited Create(AOwner);
FFileMaps := TStringList.Create;
TStringList(FFileMaps).OnChanging := DoOnChanging;
end;
 
destructor TFileMapDataFormat.Destroy;
begin
FFileMaps.Free;
inherited Destroy;
end;
 
function TFileMapDataFormat.Assign(Source: TClipboardFormat): boolean;
begin
Result := True;
 
if (Source is TFilenameMapClipboardFormat) then
FFileMaps.Assign(TFilenameMapClipboardFormat(Source).FileMaps)
 
else if (Source is TFilenameMapWClipboardFormat) then
FFileMaps.Assign(TFilenameMapWClipboardFormat(Source).FileMaps)
 
else
Result := inherited Assign(Source);
end;
 
function TFileMapDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
begin
Result := True;
 
if (Dest is TFilenameMapClipboardFormat) then
TFilenameMapClipboardFormat(Dest).FileMaps.Assign(FFileMaps)
 
else if (Dest is TFilenameMapWClipboardFormat) then
TFilenameMapWClipboardFormat(Dest).FileMaps.Assign(FFileMaps)
 
else
Result := inherited AssignTo(Dest);
end;
 
procedure TFileMapDataFormat.Clear;
begin
FFileMaps.Clear;
end;
 
function TFileMapDataFormat.HasData: boolean;
begin
Result := (FFileMaps.Count > 0);
end;
 
function TFileMapDataFormat.NeedsData: boolean;
begin
Result := (FFileMaps.Count = 0);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileDataFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TFileDataFormat.Create(AOwner: TDragDropComponent);
begin
inherited Create(AOwner);
FFiles := TStringList.Create;
TStringList(FFiles).OnChanging := DoOnChanging;
end;
 
destructor TFileDataFormat.Destroy;
begin
FFiles.Free;
inherited Destroy;
end;
 
function TFileDataFormat.Assign(Source: TClipboardFormat): boolean;
begin
Result := True;
 
if (Source is TFileClipboardFormat) then
FFiles.Assign(TFileClipboardFormat(Source).Files)
 
else if (Source is TPIDLClipboardFormat) then
FFiles.Assign(TPIDLClipboardFormat(Source).Filenames)
 
else
Result := inherited Assign(Source);
end;
 
function TFileDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
begin
Result := True;
 
if (Dest is TFileClipboardFormat) then
TFileClipboardFormat(Dest).Files.Assign(FFiles)
 
else if (Dest is TPIDLClipboardFormat) then
TPIDLClipboardFormat(Dest).Filenames.Assign(FFiles)
 
else
Result := inherited AssignTo(Dest);
end;
 
procedure TFileDataFormat.Clear;
begin
FFiles.Clear;
end;
 
function TFileDataFormat.HasData: boolean;
begin
Result := (FFiles.Count > 0);
end;
 
function TFileDataFormat.NeedsData: boolean;
begin
Result := (FFiles.Count = 0);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropFileTarget
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropFileTarget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
OptimizedMove := True;
 
FFileFormat := TFileDataFormat.Create(Self);
FFileMapFormat := TFileMapDataFormat.Create(Self);
end;
 
destructor TDropFileTarget.Destroy;
begin
FFileFormat.Free;
FFileMapFormat.Free;
inherited Destroy;
end;
 
function TDropFileTarget.GetFiles: TStrings;
begin
Result := FFileFormat.Files;
end;
 
function TDropFileTarget.GetMappedNames: TStrings;
begin
Result := FFileMapFormat.FileMaps;
end;
 
function TDropFileTarget.GetPreferredDropEffect: LongInt;
begin
Result := inherited GetPreferredDropEffect;
if (Result = DROPEFFECT_NONE) then
Result := DROPEFFECT_COPY;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropFileSource
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropFileSource.Create(aOwner: TComponent);
begin
inherited Create(AOwner);
 
FFileFormat := TFileDataFormat.Create(Self);
FFileMapFormat := TFileMapDataFormat.Create(Self);
end;
 
destructor TDropFileSource.Destroy;
begin
FFileFormat.Free;
FFileMapFormat.Free;
inherited Destroy;
end;
 
function TDropFileSource.GetFiles: TStrings;
begin
Result := FFileFormat.Files;
end;
 
function TDropFileSource.GetMappedNames: TStrings;
begin
Result := FFileMapFormat.FileMaps;
end;
 
procedure TDropFileSource.SetFiles(AFiles: TStrings);
begin
FFileFormat.Files.Assign(AFiles);
end;
 
procedure TDropFileSource.SetMappedNames(ANames: TStrings);
begin
FFileMapFormat.FileMaps.Assign(ANames);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Initialization/Finalization
//
////////////////////////////////////////////////////////////////////////////////
 
initialization
// Data format registration
TFileDataFormat.RegisterDataFormat;
TFileMapDataFormat.RegisterDataFormat;
// Clipboard format registration
TFileDataFormat.RegisterCompatibleFormat(TFileClipboardFormat, 0, csSourceTarget, [ddRead]);
TFileDataFormat.RegisterCompatibleFormat(TPIDLClipboardFormat, 1, csSourceTarget, [ddRead]);
TFileDataFormat.RegisterCompatibleFormat(TFilenameClipboardFormat, 2, csSourceTarget, [ddRead]);
TFileDataFormat.RegisterCompatibleFormat(TFilenameWClipboardFormat, 2, csSourceTarget, [ddRead]);
 
TFileMapDataFormat.RegisterCompatibleFormat(TFilenameMapClipboardFormat, 0, csSourceTarget, [ddRead]);
TFileMapDataFormat.RegisterCompatibleFormat(TFilenameMapWClipboardFormat, 0, csSourceTarget, [ddRead]);
 
finalization
// Data format unregistration
TFileDataFormat.UnregisterDataFormat;
TFileMapDataFormat.UnregisterDataFormat;
 
// Clipboard format unregistration
TFileClipboardFormat.UnregisterClipboardFormat;
TFilenameClipboardFormat.UnregisterClipboardFormat;
TFilenameWClipboardFormat.UnregisterClipboardFormat;
TFilenameMapClipboardFormat.UnregisterClipboardFormat;
TFilenameMapWClipboardFormat.UnregisterClipboardFormat;
end.
/trunk/VCL_DRAGDROP/DragDropFormats.pas
0,0 → 1,2822
unit DragDropFormats;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite.
// Module: DragDropFormats
// Description: Implements commonly used clipboard formats and base classes.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
interface
 
uses
DragDrop,
Windows,
Classes,
ActiveX,
ShlObj;
 
{$include DragDrop.inc}
 
type
////////////////////////////////////////////////////////////////////////////////
//
// TStreamList
//
////////////////////////////////////////////////////////////////////////////////
// Utility class used by TFileContentsStreamClipboardFormat and
// TDataStreamDataFormat.
////////////////////////////////////////////////////////////////////////////////
TStreamList = class(TObject)
private
FStreams : TStrings;
FOnChanging : TNotifyEvent;
protected
function GetStream(Index: integer): TStream;
function GetCount: integer;
procedure Changing;
public
constructor Create;
destructor Destroy; override;
function Add(Stream: TStream): integer;
function AddNamed(Stream: TStream; Name: string): integer;
procedure Delete(Index: integer);
procedure Clear;
procedure Assign(Value: TStreamList);
property Count: integer read GetCount;
property Streams[Index: integer]: TStream read GetStream; default;
property Names: TStrings read FStreams;
property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TInterfaceList
//
////////////////////////////////////////////////////////////////////////////////
// List of named interfaces.
// Note: Delphi 5 also implements a TInterfaceList, but it can not be used
// because it doesn't support change notification and isn't extensible.
////////////////////////////////////////////////////////////////////////////////
// Utility class used by TFileContentsStorageClipboardFormat.
////////////////////////////////////////////////////////////////////////////////
TInterfaceList = class(TObject)
private
FList : TStrings;
FOnChanging : TNotifyEvent;
protected
function GetCount: integer;
function GetName(Index: integer): string;
function GetItem(Index: integer): IUnknown;
procedure Changing;
public
constructor Create;
destructor Destroy; override;
function Add(Item: IUnknown): integer;
function AddNamed(Item: IUnknown; Name: string): integer;
procedure Delete(Index: integer);
procedure Clear;
procedure Assign(Value: TInterfaceList);
property Items[Index: integer]: IUnknown read GetItem; default;
property Names[Index: integer]: string read GetName;
property Count: integer read GetCount;
property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TStorageInterfaceList
//
////////////////////////////////////////////////////////////////////////////////
// List of IStorage interfaces.
// Used by TFileContentsStorageClipboardFormat.
////////////////////////////////////////////////////////////////////////////////
TStorageInterfaceList = class(TInterfaceList)
private
protected
function GetStorage(Index: integer): IStorage;
public
property Storages[Index: integer]: IStorage read GetStorage; default;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFixedStreamAdapter
//
////////////////////////////////////////////////////////////////////////////////
// TFixedStreamAdapter fixes several serious bugs in TStreamAdapter.CopyTo.
////////////////////////////////////////////////////////////////////////////////
TFixedStreamAdapter = class(TStreamAdapter, IStream)
public
function CopyTo(stm: IStream; cb: Largeint; out cbRead: Largeint;
out cbWritten: Largeint): HResult; override; stdcall;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TMemoryList
//
////////////////////////////////////////////////////////////////////////////////
// List which owns the memory blocks it points to.
////////////////////////////////////////////////////////////////////////////////
TMemoryList = class(TObject)
private
FList: TList;
protected
function Get(Index: Integer): Pointer;
function GetCount: Integer;
public
constructor Create;
destructor Destroy; override;
function Add(Item: Pointer): Integer;
procedure Clear;
procedure Delete(Index: Integer);
property Count: Integer read GetCount;
property Items[Index: Integer]: Pointer read Get; default;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomSimpleClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Abstract base class for simple clipboard formats stored in global memory
// or a stream.
////////////////////////////////////////////////////////////////////////////////
//
// Two different methods of data transfer from the medium to the object are
// supported:
//
// 1) Descendant class reads data from a buffer provided by the base class.
//
// 2) Base class reads data from a buffer provided by the descendant class.
//
// Method #1 only requires that the descedant class implements the ReadData.
//
// Method #2 requires that the descedant class overrides the default
// DoGetDataSized method. The descedant DoGetDataSized method should allocate a
// buffer of the specified size and then call the ReadDataInto method to
// transfer data to the buffer. Even though the ReadData method will not be used
// in this scenario, it should be implemented as an empty method (to avoid
// abstract warnings).
//
// The WriteData method must be implemented regardless of which of the two
// approaches the class implements.
//
////////////////////////////////////////////////////////////////////////////////
TCustomSimpleClipboardFormat = class(TClipboardFormat)
private
protected
function DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean; override;
//: Transfer data from medium to a buffer of the specified size.
function DoGetDataSized(ADataObject: IDataObject; const AMedium: TStgMedium;
Size: integer): boolean; virtual;
//: Transfer data from the specified buffer to the objects storage.
function ReadData(Value: pointer; Size: integer): boolean; virtual; abstract;
//: Transfer data from the medium to the specified buffer.
function ReadDataInto(ADataObject: IDataObject; const AMedium: TStgMedium;
Buffer: pointer; Size: integer): boolean; virtual;
 
function DoSetData(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean; override;
//: Transfer data from the objects storage to the specified buffer.
function WriteData(Value: pointer; Size: integer): boolean; virtual; abstract;
function GetSize: integer; virtual; abstract;
public
constructor Create; override;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomStringClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Abstract base class for simple clipboard formats.
// The data is stored in a string.
////////////////////////////////////////////////////////////////////////////////
TCustomStringClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FData: string;
FTrimZeroes: boolean;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
 
function GetString: string;
procedure SetString(const Value: string);
property Data: string read FData write FData; // DONE : Why is SetString used instead of FData?
public
procedure Clear; override;
function HasData: boolean; override;
property TrimZeroes: boolean read FTrimZeroes write FTrimZeroes;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomStringListClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Abstract base class for simple cr/lf delimited string clipboard formats.
// The data is stored in a TStringList.
////////////////////////////////////////////////////////////////////////////////
TCustomStringListClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FLines : TStrings;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
 
function GetLines: TStrings;
property Lines: TStrings read FLines;
public
constructor Create; override;
destructor Destroy; override;
procedure Clear; override;
function HasData: boolean; override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Abstract base class for simple text based clipboard formats.
////////////////////////////////////////////////////////////////////////////////
TCustomTextClipboardFormat = class(TCustomStringClipboardFormat)
private
protected
function GetSize: integer; override;
property Text: string read GetString write SetString;
public
constructor Create; override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomWideTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Abstract base class for simple wide string clipboard formats storing the data
// in a wide string.
////////////////////////////////////////////////////////////////////////////////
TCustomWideTextClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FText : WideString;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
 
function GetText: WideString;
procedure SetText(const Value: WideString);
property Text: WideString read FText write FText;
public
procedure Clear; override;
function HasData: boolean; override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TTextClipboardFormat = class(TCustomTextClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
property Text;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomDWORDClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TCustomDWORDClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FValue : DWORD;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
 
function GetValueDWORD: DWORD;
procedure SetValueDWORD(Value: DWORD);
function GetValueInteger: integer;
procedure SetValueInteger(Value: integer);
function GetValueLongInt: longInt;
procedure SetValueLongInt(Value: longInt);
function GetValueBoolean: boolean;
procedure SetValueBoolean(Value: boolean);
public
procedure Clear; override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileGroupDescritorClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TFileGroupDescritorClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FFileGroupDescriptor : PFileGroupDescriptor;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
public
function GetClipboardFormat: TClipFormat; override;
destructor Destroy; override;
procedure Clear; override;
function HasData: boolean; override;
property FileGroupDescriptor: PFileGroupDescriptor read FFileGroupDescriptor;
procedure CopyFrom(AFileGroupDescriptor: PFileGroupDescriptor);
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileGroupDescritorWClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Warning: TFileGroupDescriptorW has wrong declaration in ShlObj.pas!
TFileGroupDescriptorW = record
cItems: UINT;
fgd: array[0..0] of TFileDescriptorW;
end;
 
PFileGroupDescriptorW = ^TFileGroupDescriptorW;
 
TFileGroupDescritorWClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FFileGroupDescriptor : PFileGroupDescriptorW;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
public
function GetClipboardFormat: TClipFormat; override;
destructor Destroy; override;
procedure Clear; override;
function HasData: boolean; override;
property FileGroupDescriptor: PFileGroupDescriptorW read FFileGroupDescriptor;
procedure CopyFrom(AFileGroupDescriptor: PFileGroupDescriptorW);
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileContentsClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Note: File contents must be zero terminated, so we descend from
// TCustomTextClipboardFormat instead of TCustomStringClipboardFormat.
////////////////////////////////////////////////////////////////////////////////
TFileContentsClipboardFormat = class(TCustomTextClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
constructor Create; override;
property Data;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileContentsStreamClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TFileContentsStreamClipboardFormat = class(TClipboardFormat)
private
FStreams: TStreamList;
protected
public
constructor Create; override;
destructor Destroy; override;
function GetClipboardFormat: TClipFormat; override;
function GetData(DataObject: IDataObject): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property Streams: TStreamList read FStreams;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileContentsStreamOnDemandClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Yeah, it's a long name, but I like my names descriptive.
////////////////////////////////////////////////////////////////////////////////
TVirtualFileStreamDataFormat = class;
TFileContentsStreamOnDemandClipboardFormat = class;
 
TOnGetStreamEvent = procedure(Sender: TFileContentsStreamOnDemandClipboardFormat;
Index: integer; out AStream: IStream) of object;
 
TFileContentsStreamOnDemandClipboardFormat = class(TClipboardFormat)
private
FOnGetStream: TOnGetStreamEvent;
FGotData: boolean;
FDataRequested: boolean;
protected
function DoSetData(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean; override;
public
constructor Create; override;
destructor Destroy; override;
function GetClipboardFormat: TClipFormat; override;
function GetData(DataObject: IDataObject): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
function Assign(Source: TCustomDataFormat): boolean; override;
 
function GetStream(Index: integer): IStream;
 
property OnGetStream: TOnGetStreamEvent read FOnGetStream write FOnGetStream;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileContentsStorageClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TFileContentsStorageClipboardFormat = class(TClipboardFormat)
private
FStorages : TStorageInterfaceList;
protected
public
constructor Create; override;
destructor Destroy; override;
function GetClipboardFormat: TClipFormat; override;
function GetData(DataObject: IDataObject): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property Storages: TStorageInterfaceList read FStorages;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TPreferredDropEffectClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TPreferredDropEffectClipboardFormat = class(TCustomDWORDClipboardFormat)
public
class function GetClassClipboardFormat: TClipFormat;
function GetClipboardFormat: TClipFormat; override;
function HasData: boolean; override;
property Value: longInt read GetValueLongInt write SetValueLongInt;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TPerformedDropEffectClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TPerformedDropEffectClipboardFormat = class(TCustomDWORDClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
property Value: longInt read GetValueLongInt write SetValueLongInt;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TLogicalPerformedDropEffectClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Microsoft's latest (so far) "logical" solution to the never ending attempts
// of reporting back to the source which operation actually took place. Sigh!
////////////////////////////////////////////////////////////////////////////////
TLogicalPerformedDropEffectClipboardFormat = class(TCustomDWORDClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
property Value: longInt read GetValueLongInt write SetValueLongInt;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TPasteSuccededClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TPasteSuccededClipboardFormat = class(TCustomDWORDClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
property Value: longInt read GetValueLongInt write SetValueLongInt;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TInDragLoopClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TInShellDragLoopClipboardFormat = class(TCustomDWORDClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
property InShellDragLoop: boolean read GetValueBoolean write SetValueBoolean;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TTargetCLSIDClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TTargetCLSIDClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FCLSID: TCLSID;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
public
function GetClipboardFormat: TClipFormat; override;
procedure Clear; override;
function HasData: boolean; override;
property CLSID: TCLSID read FCLSID write FCLSID;
end;
 
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TTextDataFormat
//
////////////////////////////////////////////////////////////////////////////////
TTextDataFormat = class(TCustomDataFormat)
private
FText : string;
protected
procedure SetText(const Value: string);
public
function Assign(Source: TClipboardFormat): boolean; override;
function AssignTo(Dest: TClipboardFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property Text: string read FText write SetText;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDataStreamDataFormat
//
////////////////////////////////////////////////////////////////////////////////
TDataStreamDataFormat = class(TCustomDataFormat)
private
FStreams : TStreamList;
public
constructor Create(AOwner: TDragDropComponent); override;
destructor Destroy; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property Streams: TStreamList read FStreams;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TVirtualFileStreamDataFormat
//
////////////////////////////////////////////////////////////////////////////////
TVirtualFileStreamDataFormat = class(TCustomDataFormat)
private
FFileDescriptors: TMemoryList;
FFileNames: TStrings;
FFileContentsClipboardFormat: TFileContentsStreamOnDemandClipboardFormat;
FFileGroupDescritorClipboardFormat: TFileGroupDescritorClipboardFormat;
FHasContents: boolean;
protected
procedure SetFileNames(const Value: TStrings);
function GetOnGetStream: TOnGetStreamEvent;
procedure SetOnGetStream(const Value: TOnGetStreamEvent);
public
constructor Create(AOwner: TDragDropComponent); override;
destructor Destroy; override;
 
function Assign(Source: TClipboardFormat): boolean; override;
function AssignTo(Dest: TClipboardFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property FileDescriptors: TMemoryList read FFileDescriptors;
property FileNames: TStrings read FFileNames write SetFileNames;
property FileContentsClipboardFormat: TFileContentsStreamOnDemandClipboardFormat
read FFileContentsClipboardFormat;
property FileGroupDescritorClipboardFormat: TFileGroupDescritorClipboardFormat
read FFileGroupDescritorClipboardFormat;
property OnGetStream: TOnGetStreamEvent read GetOnGetStream write SetOnGetStream;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TFeedbackDataFormat
//
////////////////////////////////////////////////////////////////////////////////
// Data used for communication between source and target.
// Only used by the drop source.
////////////////////////////////////////////////////////////////////////////////
TFeedbackDataFormat = class(TCustomDataFormat)
private
FPreferredDropEffect: longInt;
FPerformedDropEffect: longInt;
FLogicalPerformedDropEffect: longInt;
FPasteSucceded: longInt;
FInShellDragLoop: boolean;
FGotInShellDragLoop: boolean;
FTargetCLSID: TCLSID;
protected
procedure SetInShellDragLoop(const Value: boolean);
procedure SetPasteSucceded(const Value: longInt);
procedure SetPerformedDropEffect(const Value: longInt);
procedure SetPreferredDropEffect(const Value: longInt);
procedure SetTargetCLSID(const Value: TCLSID);
procedure SetLogicalPerformedDropEffect(const Value: Integer);
public
function Assign(Source: TClipboardFormat): boolean; override;
function AssignTo(Dest: TClipboardFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property PreferredDropEffect: longInt read FPreferredDropEffect
write SetPreferredDropEffect;
property PerformedDropEffect: longInt read FPerformedDropEffect
write SetPerformedDropEffect;
property LogicalPerformedDropEffect: longInt read FLogicalPerformedDropEffect
write SetLogicalPerformedDropEffect;
property PasteSucceded: longInt read FPasteSucceded write SetPasteSucceded;
property InShellDragLoop: boolean read FInShellDragLoop
write SetInShellDragLoop;
property TargetCLSID: TCLSID read FTargetCLSID write SetTargetCLSID;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TGenericClipboardFormat & TGenericDataFormat
//
////////////////////////////////////////////////////////////////////////////////
// TGenericDataFormat is not used internally by the library, but can be used to
// add support for new formats with a minimum of custom code.
// Even though TGenericDataFormat represents the data as a string, it can be
// used to transfer any kind of data.
// TGenericClipboardFormat is used internally by TGenericDataFormat but can also
// be used by other TCustomDataFormat descendants or as a base class for new
// clipboard formats.
// Note that you should not register TGenericClipboardFormat as compatible with
// TGenericDataFormat.
// To use TGenericDataFormat, all you need to do is instantiate it against
// the desired component and register your custom clipboard formats:
//
// var
// MyCustomData: TGenericDataFormat;
//
// MyCustomData := TGenericDataFormat.Create(DropTextTarget1);
// MyCustomData.AddFormat('MyCustomFormat');
//
////////////////////////////////////////////////////////////////////////////////
TGenericDataFormat = class(TCustomDataFormat)
private
FData : string;
protected
function GetSize: integer;
procedure DoSetData(const Value: string);
public
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
procedure AddFormat(const AFormat: string);
procedure SetDataHere(const AData; ASize: integer);
function GetDataHere(var AData; ASize: integer): integer;
property Data: string read FData write DoSetData;
property Size: integer read GetSize;
end;
 
TGenericClipboardFormat = class(TCustomStringClipboardFormat)
private
FFormat: string;
protected
procedure SetClipboardFormatName(const Value: string); override;
function GetClipboardFormatName: string; override;
function GetClipboardFormat: TClipFormat; override;
public
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property Data;
end;
 
 
 
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
implementation
 
uses
DropSource,
DropTarget,
SysUtils;
 
////////////////////////////////////////////////////////////////////////////////
//
// TStreamList
//
////////////////////////////////////////////////////////////////////////////////
constructor TStreamList.Create;
begin
inherited Create;
FStreams := TStringList.Create;
end;
 
destructor TStreamList.Destroy;
begin
Clear;
FStreams.Free;
inherited Destroy;
end;
 
procedure TStreamList.Changing;
begin
if (Assigned(OnChanging)) then
OnChanging(Self);
end;
 
function TStreamList.GetStream(Index: integer): TStream;
begin
Result := TStream(FStreams.Objects[Index]);
end;
 
function TStreamList.Add(Stream: TStream): integer;
begin
Result := AddNamed(Stream, '');
end;
 
function TStreamList.AddNamed(Stream: TStream; Name: string): integer;
begin
Changing;
Result := FStreams.AddObject(Name, Stream);
end;
 
function TStreamList.GetCount: integer;
begin
Result := FStreams.Count;
end;
 
procedure TStreamList.Assign(Value: TStreamList);
begin
Clear;
FStreams.Assign(Value.Names);
// Transfer ownership of objects
Value.FStreams.Clear;
end;
 
procedure TStreamList.Delete(Index: integer);
begin
Changing;
FStreams.Delete(Index);
end;
 
procedure TStreamList.Clear;
var
i : integer;
begin
Changing;
for i := 0 to FStreams.Count-1 do
if (FStreams.Objects[i] <> nil) then
FStreams.Objects[i].Free;
FStreams.Clear;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TInterfaceList
//
////////////////////////////////////////////////////////////////////////////////
constructor TInterfaceList.Create;
begin
inherited Create;
FList := TStringList.Create;
end;
 
destructor TInterfaceList.Destroy;
begin
Clear;
FList.Free;
inherited Destroy;
end;
 
function TInterfaceList.Add(Item: IUnknown): integer;
begin
Result := AddNamed(Item, '');
end;
 
function TInterfaceList.AddNamed(Item: IUnknown; Name: string): integer;
begin
Changing;
with FList do
begin
Result := AddObject(Name, nil);
Objects[Result] := TObject(Item);
Item._AddRef;
end;
end;
 
procedure TInterfaceList.Changing;
begin
if (Assigned(OnChanging)) then
OnChanging(Self);
end;
 
procedure TInterfaceList.Clear;
var
i : Integer;
p : pointer;
begin
Changing;
with FList do
begin
for i := 0 to Count - 1 do
begin
p := Objects[i];
IUnknown(p) := nil;
end;
Clear;
end;
end;
 
procedure TInterfaceList.Assign(Value: TInterfaceList);
var
i : Integer;
begin
Changing;
for i := 0 to Value.Count - 1 do
AddNamed(Value.Items[i], Value.Names[i]);
end;
 
procedure TInterfaceList.Delete(Index: integer);
var
p : pointer;
begin
Changing;
with FList do
begin
p := Objects[Index];
IUnknown(p) := nil;
Delete(Index);
end;
end;
 
function TInterfaceList.GetCount: integer;
begin
Result := FList.Count;
end;
 
function TInterfaceList.GetName(Index: integer): string;
begin
Result := FList[Index];
end;
 
function TInterfaceList.GetItem(Index: integer): IUnknown;
var
p : pointer;
begin
p := FList.Objects[Index];
Result := IUnknown(p);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TStorageInterfaceList
//
////////////////////////////////////////////////////////////////////////////////
function TStorageInterfaceList.GetStorage(Index: integer): IStorage;
begin
Result := IStorage(Items[Index]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TMemoryList
//
////////////////////////////////////////////////////////////////////////////////
function TMemoryList.Add(Item: Pointer): Integer;
begin
Result := FList.Add(Item);
end;
 
procedure TMemoryList.Clear;
var
i: integer;
begin
for i := FList.Count-1 downto 0 do
Delete(i);
end;
 
constructor TMemoryList.Create;
begin
inherited Create;
FList := TList.Create;
end;
 
procedure TMemoryList.Delete(Index: Integer);
begin
Freemem(FList[Index]);
FList.Delete(Index);
end;
 
destructor TMemoryList.Destroy;
begin
FList.Free;
inherited Destroy;
end;
 
function TMemoryList.Get(Index: Integer): Pointer;
begin
Result := FList[Index];
end;
 
function TMemoryList.GetCount: Integer;
begin
Result := FList.Count;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFixedStreamAdapter
//
////////////////////////////////////////////////////////////////////////////////
function TFixedStreamAdapter.CopyTo(stm: IStream; cb: Largeint; out cbRead: Largeint;
out cbWritten: Largeint): HResult;
const
MaxBufSize = 1024 * 1024; // 1mb
var
Buffer: Pointer;
BufSize, BurstReadSize, BurstWriteSize: Integer;
BytesRead, BytesWritten, BurstWritten: LongInt;
begin
Result := S_OK;
BytesRead := 0;
BytesWritten := 0;
try
if (cb < 0) then
begin
// Note: The folowing is a workaround for a design bug in either explorer
// or the clipboard. See comment in TCustomSimpleClipboardFormat.DoSetData
// for an explanation.
if (Stream.Position = Stream.Size) then
Stream.Position := 0;
 
cb := Stream.Size - Stream.Position;
end;
if cb > MaxBufSize then
BufSize := MaxBufSize
else
BufSize := Integer(cb);
GetMem(Buffer, BufSize);
try
while cb > 0 do
begin
if cb > BufSize then
BurstReadSize := BufSize
else
BurstReadSize := cb;
 
BurstWriteSize := Stream.Read(Buffer^, BurstReadSize);
if (BurstWriteSize = 0) then
break;
Inc(BytesRead, BurstWriteSize);
BurstWritten := 0;
Result := stm.Write(Buffer, BurstWriteSize, @BurstWritten);
Inc(BytesWritten, BurstWritten);
if (Result = S_OK) and (Integer(BurstWritten) <> BurstWriteSize) then
Result := E_FAIL;
if Result <> S_OK then
Exit;
Dec(cb, BurstWritten);
end;
finally
FreeMem(Buffer);
if (@cbWritten <> nil) then
cbWritten := BytesWritten;
if (@cbRead <> nil) then
cbRead := BytesRead;
end;
except
Result := E_UNEXPECTED;
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomSimpleClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TCustomSimpleClipboardFormat.Create;
begin
CreateFormat(TYMED_HGLOBAL or TYMED_ISTREAM);
end;
 
function TCustomSimpleClipboardFormat.DoGetData(ADataObject: IDataObject;
const AMedium: TStgMedium): boolean;
var
Stream : IStream;
StatStg : TStatStg;
Size : integer;
begin
// Get size from HGlobal.
if (AMedium.tymed and TYMED_HGLOBAL <> 0) then
begin
Size := GlobalSize(AMedium.HGlobal);
Result := True;
end else
// Get size from IStream.
if (AMedium.tymed and TYMED_ISTREAM <> 0) then
begin
Stream := IStream(AMedium.stm);
Result := (Stream <> nil) and (Stream.Stat(StatStg, STATFLAG_NONAME) = S_OK);
Size := StatStg.cbSize;
Stream := nil; // Not really nescessary.
end else
begin
Size := 0;
Result := False;
end;
 
if (Result) and (Size > 0) then
begin
// Read the given amount of data.
Result := DoGetDataSized(ADataObject, AMedium, Size);
end;
end;
 
function TCustomSimpleClipboardFormat.DoGetDataSized(ADataObject: IDataObject;
const AMedium: TStgMedium; Size: integer): boolean;
var
Buffer: pointer;
Stream: IStream;
Remaining: longInt;
Chunk: longInt;
pChunk: PChar;
begin
if (Size > 0) then
begin
(*
** In this method we prefer TYMED_HGLOBAL over TYMED_ISTREAM and thus check
** for TYMED_HGLOBAL first.
*)
 
// Read data from HGlobal
if (AMedium.tymed and TYMED_HGLOBAL <> 0) then
begin
// Use global memory as buffer
Buffer := GlobalLock(AMedium.HGlobal);
try
// Read data from buffer into object
Result := (Buffer <> nil) and (ReadData(Buffer, Size));
finally
GlobalUnlock(AMedium.HGlobal);
end;
end else
// Read data from IStream
if (AMedium.tymed and TYMED_ISTREAM <> 0) then
begin
// Allocate buffer
GetMem(Buffer, Size);
try
// Read data from stream into buffer
Stream := IStream(AMedium.stm);
if (Stream <> nil) then
begin
Stream.Seek(0, STREAM_SEEK_SET, PLargeuint(nil)^);
Result := True;
Remaining := Size;
pChunk := Buffer;
while (Result) and (Remaining > 0) do
begin
Result := (Stream.Read(pChunk, Remaining, @Chunk) = S_OK);
if (Chunk = 0) then
break;
inc(pChunk, Chunk);
dec(Remaining, Chunk);
end;
Stream := nil; // Not really nescessary.
end else
Result := False;
// Transfer data from buffer into object.
Result := Result and (ReadData(Buffer, Size));
finally
FreeMem(Buffer);
end;
end else
Result := False;
end else
Result := False;
end;
 
function TCustomSimpleClipboardFormat.ReadDataInto(ADataObject: IDataObject;
const AMedium: TStgMedium; Buffer: pointer; Size: integer): boolean;
var
Stream: IStream;
p: pointer;
Remaining: longInt;
Chunk: longInt;
begin
Result := (Buffer <> nil) and (Size > 0);
if (Result) then
begin
// Read data from HGlobal
if (AMedium.tymed and TYMED_HGLOBAL <> 0) then
begin
p := GlobalLock(AMedium.HGlobal);
try
Result := (p <> nil);
if (Result) then
Move(p^, Buffer^, Size);
finally
GlobalUnlock(AMedium.HGlobal);
end;
end else
// Read data from IStream
if (AMedium.tymed and TYMED_ISTREAM <> 0) then
begin
Stream := IStream(AMedium.stm);
if (Stream <> nil) then
begin
Stream.Seek(0, STREAM_SEEK_SET, PLargeuint(nil)^);
Remaining := Size;
while (Result) and (Remaining > 0) do
begin
Result := (Stream.Read(Buffer, Remaining, @Chunk) = S_OK);
if (Chunk = 0) then
break;
inc(PChar(Buffer), Chunk);
dec(Remaining, Chunk);
end;
end else
Result := False;
end else
Result := False;
end;
end;
 
function TCustomSimpleClipboardFormat.DoSetData(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean;
var
p: pointer;
Size: integer;
Stream: TMemoryStream;
// Warning: TStreamAdapter.CopyTo is broken!
StreamAdapter: TStreamAdapter;
begin
Result := False;
 
Size := GetSize;
if (Size <= 0) then
exit;
 
if (FormatEtcIn.tymed and TYMED_ISTREAM <> 0) then
begin
 
Stream := TMemoryStream.Create;
StreamAdapter := TFixedStreamAdapter.Create(Stream, soOwned);
 
try
Stream.Size := Size;
Result := WriteData(Stream.Memory, Size);
// Note: Conflicting information on which of the following two are correct:
//
// 1) Stream.Position := Size;
//
// 2) Stream.Position := 0;
//
// #1 is required for clipboard operations to succeed; The clipboard uses
// a Seek(0, STREAM_SEEK_CUR) to determine the size of the stream.
//
// #2 is required for shell operations to succeed; The shell uses a
// Read(-1) to read all of the stream.
//
// This library uses a Stream.Stat to determine the size of the stream and
// then reads from start to end of stream.
//
// Since we use #1 (see below), we work around #2 in
// TFixedStreamAdapter.CopyTo.
if (Result) then
begin
Stream.Position := Size;
IStream(AMedium.stm) := StreamAdapter as IStream;
end;
except
Result := False;
end;
 
if (not Result) then
begin
StreamAdapter.Free;
AMedium.stm := nil;
end else
AMedium.tymed := TYMED_ISTREAM;
 
end else
if (FormatEtcIn.tymed and TYMED_HGLOBAL <> 0) then
begin
 
AMedium.hGlobal := GlobalAlloc(GMEM_SHARE or GHND, Size);
if (AMedium.hGlobal = 0) then
exit;
 
try
p := GlobalLock(AMedium.hGlobal);
try
Result := (p <> nil) and WriteData(p, Size);
finally
GlobalUnlock(AMedium.hGlobal);
end;
except
Result := False;
end;
 
if (not Result) then
begin
GlobalFree(AMedium.hGlobal);
AMedium.hGlobal := 0;
end else
AMedium.tymed := TYMED_HGLOBAL;
 
end else
Result := False;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomStringClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
procedure TCustomStringClipboardFormat.Clear;
begin
FData := '';
end;
 
function TCustomStringClipboardFormat.HasData: boolean;
begin
Result := (FData <> '');
end;
 
 
function TCustomStringClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
SetLength(FData, Size);
Move(Value^, PChar(FData)^, Size);
 
// IE adds a lot of trailing zeroes which is included in the string length.
// To avoid confusion, we trim all trailing zeroes but the last (which is
// managed automatically by Delphi).
// Note that since this work around, if applied generally, would mean that we
// couldn't use this class to handle arbitrary binary data (which might
// include zeroes), we are required to explicitly enable it in the classes
// where we need it (e.g. all TCustomTextClipboardFormat descedants).
if (FTrimZeroes) then
SetLength(FData, Length(PChar(FData)));
 
Result := True;
end;
 
function TCustomStringClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
begin
// Transfer string including terminating zero if requested.
Result := (Size <= Length(FData)+1);
if (Result) then
Move(PChar(FData)^, Value^, Size);
end;
 
function TCustomStringClipboardFormat.GetSize: integer;
begin
Result := Length(FData);
end;
 
function TCustomStringClipboardFormat.GetString: string;
begin
Result := FData;
end;
 
procedure TCustomStringClipboardFormat.SetString(const Value: string);
begin
FData := Value;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomStringListClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TCustomStringListClipboardFormat.Create;
begin
inherited Create;
FLines := TStringList.Create
end;
 
destructor TCustomStringListClipboardFormat.Destroy;
begin
FLines.Free;
inherited Destroy;
end;
 
procedure TCustomStringListClipboardFormat.Clear;
begin
FLines.Clear;
end;
 
function TCustomStringListClipboardFormat.HasData: boolean;
begin
Result := (FLines.Count > 0);
end;
 
function TCustomStringListClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
var
s : string;
begin
SetLength(s, Size+1);
Move(Value^, PChar(s)^, Size);
s[Size] := #0;
FLines.Text := s;
Result := True;
end;
 
function TCustomStringListClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
var
s : string;
begin
s := FLines.Text;
Result := (Size = Length(s)+1);
if (Result) then
Move(PChar(s)^, Value^, Size);
end;
 
function TCustomStringListClipboardFormat.GetSize: integer;
begin
Result := Length(FLines.Text)+1;
end;
 
function TCustomStringListClipboardFormat.GetLines: TStrings;
begin
Result := FLines;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TCustomTextClipboardFormat.Create;
begin
inherited Create;
TrimZeroes := True;
end;
 
function TCustomTextClipboardFormat.GetSize: integer;
begin
Result := inherited GetSize;
// Unless the data is already zero terminated, we add a byte to include
// the string's implicit terminating zero.
if (Data[Result] <> #0) then
inc(Result);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomWideTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
procedure TCustomWideTextClipboardFormat.Clear;
begin
FText := '';
end;
 
function TCustomWideTextClipboardFormat.HasData: boolean;
begin
Result := (FText <> '');
end;
 
function TCustomWideTextClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
SetLength(FText, Size div 2);
Move(Value^, PWideChar(FText)^, Size);
Result := True;
end;
 
function TCustomWideTextClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
begin
Result := (Size <= (Length(FText)+1)*2);
if (Result) then
Move(PWideChar(FText)^, Value^, Size);
end;
 
function TCustomWideTextClipboardFormat.GetSize: integer;
begin
Result := Length(FText)*2;
// Unless the data is already zero terminated, we add two bytes to include
// the string's implicit terminating zero.
if (FText[Result] <> #0) then
inc(Result, 2);
end;
 
function TCustomWideTextClipboardFormat.GetText: WideString;
begin
Result := FText;
end;
 
procedure TCustomWideTextClipboardFormat.SetText(const Value: WideString);
begin
FText := Value;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
function TTextClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := CF_TEXT;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomDWORDClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
function TCustomDWORDClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
FValue := PDWORD(Value)^;
Result := True;
end;
 
function TCustomDWORDClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
begin
Result := (Size = SizeOf(DWORD));
if (Result) then
PDWORD(Value)^ := FValue;
end;
 
function TCustomDWORDClipboardFormat.GetSize: integer;
begin
Result := SizeOf(DWORD);
end;
 
procedure TCustomDWORDClipboardFormat.Clear;
begin
FValue := 0;
end;
 
function TCustomDWORDClipboardFormat.GetValueDWORD: DWORD;
begin
Result := FValue;
end;
 
procedure TCustomDWORDClipboardFormat.SetValueDWORD(Value: DWORD);
begin
FValue := Value;
end;
 
function TCustomDWORDClipboardFormat.GetValueInteger: integer;
begin
Result := integer(FValue);
end;
 
procedure TCustomDWORDClipboardFormat.SetValueInteger(Value: integer);
begin
FValue := DWORD(Value);
end;
 
function TCustomDWORDClipboardFormat.GetValueLongInt: longInt;
begin
Result := longInt(FValue);
end;
 
procedure TCustomDWORDClipboardFormat.SetValueLongInt(Value: longInt);
begin
FValue := DWORD(Value);
end;
 
function TCustomDWORDClipboardFormat.GetValueBoolean: boolean;
begin
Result := (FValue <> 0);
end;
 
procedure TCustomDWORDClipboardFormat.SetValueBoolean(Value: boolean);
begin
FValue := ord(Value);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileGroupDescritorClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_FILEGROUPDESCRIPTOR: TClipFormat = 0;
 
function TFileGroupDescritorClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_FILEGROUPDESCRIPTOR = 0) then
CF_FILEGROUPDESCRIPTOR := RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
Result := CF_FILEGROUPDESCRIPTOR;
end;
 
destructor TFileGroupDescritorClipboardFormat.Destroy;
begin
Clear;
inherited Destroy;
end;
 
procedure TFileGroupDescritorClipboardFormat.Clear;
begin
if (FFileGroupDescriptor <> nil) then
begin
FreeMem(FFileGroupDescriptor);
FFileGroupDescriptor := nil;
end;
end;
 
function TFileGroupDescritorClipboardFormat.HasData: boolean;
begin
Result := (FFileGroupDescriptor <> nil) and (FFileGroupDescriptor^.cItems <> 0);
end;
 
procedure TFileGroupDescritorClipboardFormat.CopyFrom(AFileGroupDescriptor: PFileGroupDescriptor);
var
Size : integer;
begin
Clear;
if (AFileGroupDescriptor <> nil) then
begin
Size := SizeOf(UINT) + AFileGroupDescriptor^.cItems * SizeOf(TFileDescriptor);
GetMem(FFileGroupDescriptor, Size);
Move(AFileGroupDescriptor^, FFileGroupDescriptor^, Size);
end;
end;
 
function TFileGroupDescritorClipboardFormat.GetSize: integer;
begin
if (FFileGroupDescriptor <> nil) then
Result := SizeOf(UINT) + FFileGroupDescriptor^.cItems * SizeOf(TFileDescriptor)
else
Result := 0;
end;
 
function TFileGroupDescritorClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
// Validate size against count
Result :=
(Size - SizeOf(UINT)) DIV SizeOf(TFileDescriptor) = integer(PFileGroupDescriptor(Value)^.cItems);
if (Result) then
CopyFrom(PFileGroupDescriptor(Value));
end;
 
function TFileGroupDescritorClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
begin
// Validate size against count
Result := (FFileGroupDescriptor <> nil) and
((Size - SizeOf(UINT)) DIV SizeOf(TFileDescriptor) = integer(FFileGroupDescriptor^.cItems));
 
if (Result) then
Move(FFileGroupDescriptor^, Value^, Size);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileGroupDescritorWClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_FILEGROUPDESCRIPTORW: TClipFormat = 0;
 
function TFileGroupDescritorWClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_FILEGROUPDESCRIPTORW = 0) then
CF_FILEGROUPDESCRIPTORW := RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
Result := CF_FILEGROUPDESCRIPTORW;
end;
 
destructor TFileGroupDescritorWClipboardFormat.Destroy;
begin
Clear;
inherited Destroy;
end;
 
procedure TFileGroupDescritorWClipboardFormat.Clear;
begin
if (FFileGroupDescriptor <> nil) then
begin
FreeMem(FFileGroupDescriptor);
FFileGroupDescriptor := nil;
end;
end;
 
function TFileGroupDescritorWClipboardFormat.HasData: boolean;
begin
Result := (FFileGroupDescriptor <> nil) and (FFileGroupDescriptor^.cItems <> 0);
end;
 
procedure TFileGroupDescritorWClipboardFormat.CopyFrom(AFileGroupDescriptor: PFileGroupDescriptorW);
var
Size : integer;
begin
Clear;
if (AFileGroupDescriptor <> nil) then
begin
Size := SizeOf(UINT) + AFileGroupDescriptor^.cItems * SizeOf(TFileDescriptorW);
GetMem(FFileGroupDescriptor, Size);
Move(AFileGroupDescriptor^, FFileGroupDescriptor^, Size);
end;
end;
 
function TFileGroupDescritorWClipboardFormat.GetSize: integer;
begin
if (FFileGroupDescriptor <> nil) then
Result := SizeOf(UINT) + FFileGroupDescriptor^.cItems * SizeOf(TFileDescriptorW)
else
Result := 0;
end;
 
function TFileGroupDescritorWClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
// Validate size against count
Result :=
(Size - SizeOf(UINT)) DIV SizeOf(TFileDescriptorW) = integer(PFileGroupDescriptor(Value)^.cItems);
if (Result) then
CopyFrom(PFileGroupDescriptorW(Value));
end;
 
function TFileGroupDescritorWClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
begin
// Validate size against count
Result := (FFileGroupDescriptor <> nil) and
((Size - SizeOf(UINT)) DIV SizeOf(TFileDescriptorW) = integer(FFileGroupDescriptor^.cItems));
 
if (Result) then
Move(FFileGroupDescriptor^, Value^, Size);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileContentsClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_FILECONTENTS: TClipFormat = 0;
 
constructor TFileContentsClipboardFormat.Create;
begin
inherited Create;
FFormatEtc.lindex := 0;
end;
 
function TFileContentsClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_FILECONTENTS = 0) then
CF_FILECONTENTS := RegisterClipboardFormat(CFSTR_FILECONTENTS);
Result := CF_FILECONTENTS;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileContentsStreamClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TFileContentsStreamClipboardFormat.Create;
begin
CreateFormat(TYMED_ISTREAM);
FStreams := TStreamList.Create;
end;
 
destructor TFileContentsStreamClipboardFormat.Destroy;
begin
Clear;
FStreams.Free;
inherited Destroy;
end;
 
function TFileContentsStreamClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_FILECONTENTS = 0) then
CF_FILECONTENTS := RegisterClipboardFormat(CFSTR_FILECONTENTS);
Result := CF_FILECONTENTS;
end;
 
procedure TFileContentsStreamClipboardFormat.Clear;
begin
FStreams.Clear;
end;
 
function TFileContentsStreamClipboardFormat.HasData: boolean;
begin
Result := (FStreams.Count > 0);
end;
 
function TFileContentsStreamClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
Result := True;
if (Dest is TDataStreamDataFormat) then
begin
TDataStreamDataFormat(Dest).Streams.Assign(Streams);
end else
Result := inherited AssignTo(Dest);
end;
 
{$IFOPT R+}
{$DEFINE R_PLUS}
{$RANGECHECKS OFF}
{$ENDIF}
function TFileContentsStreamClipboardFormat.GetData(DataObject: IDataObject): boolean;
var
FGD: TFileGroupDescritorClipboardFormat;
Count: integer;
Medium: TStgMedium;
Stream: IStream;
Name: string;
MemStream: TMemoryStream;
StatStg: TStatStg;
Size: longInt;
Remaining: longInt;
pChunk: PChar;
begin
Result := False;
 
Clear;
FGD := TFileGroupDescritorClipboardFormat.Create;
try
if (FGD.GetData(DataObject)) then
begin
// Multiple objects, retrieve one at a time
Count := FGD.FileGroupDescriptor^.cItems;
FFormatEtc.lindex := 0;
end else
begin
// Single object, retrieve "all" at once
Count := 0;
FFormatEtc.lindex := -1;
Name := '';
end;
while (FFormatEtc.lindex < Count) do
begin
if (DataObject.GetData(FormatEtc, Medium) <> S_OK) then
break;
try
inc(FFormatEtc.lindex);
if (Medium.tymed <> TYMED_ISTREAM) then
continue;
Stream := IStream(Medium.stm);
Stream.Stat(StatStg, STATFLAG_NONAME);
MemStream := TMemoryStream.Create;
try
Remaining := StatStg.cbSize;
MemStream.Size := Remaining;
pChunk := MemStream.Memory;
while (Remaining > 0) do
begin
if (Stream.Read(pChunk, Remaining, @Size) <> S_OK) or
(Size = 0) then
break;
inc(pChunk, Size);
dec(Remaining, Size);
end;
 
if (FFormatEtc.lindex > 0) then
Name := FGD.FileGroupDescriptor^.fgd[FFormatEtc.lindex-1].cFileName;
Streams.AddNamed(MemStream, Name);
except
MemStream.Free;
raise;
end;
Stream := nil;
Result := True;
finally
ReleaseStgMedium(Medium);
end;
end;
finally
FGD.Free;
end;
end;
{$IFDEF R_PLUS}
{$RANGECHECKS ON}
{$UNDEF R_PLUS}
{$ENDIF}
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileContentsStreamOnDemandClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TFileContentsStreamOnDemandClipboardFormat.Create;
begin
CreateFormat(TYMED_ISTREAM);
end;
 
destructor TFileContentsStreamOnDemandClipboardFormat.Destroy;
begin
Clear;
inherited Destroy;
end;
 
function TFileContentsStreamOnDemandClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_FILECONTENTS = 0) then
CF_FILECONTENTS := RegisterClipboardFormat(CFSTR_FILECONTENTS);
Result := CF_FILECONTENTS;
end;
 
procedure TFileContentsStreamOnDemandClipboardFormat.Clear;
begin
FGotData := False;
FDataRequested := False;
end;
 
function TFileContentsStreamOnDemandClipboardFormat.HasData: boolean;
begin
Result := FGotData or FDataRequested;
end;
 
function TFileContentsStreamOnDemandClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
if (Dest is TVirtualFileStreamDataFormat) then
begin
Result := True
end else
Result := inherited AssignTo(Dest);
end;
 
function TFileContentsStreamOnDemandClipboardFormat.Assign(
Source: TCustomDataFormat): boolean;
begin
if (Source is TVirtualFileStreamDataFormat) then
begin
// Acknowledge that we can offer the requested data, but defer the actual
// data transfer.
FDataRequested := True;
Result := True
end else
Result := inherited Assign(Source);
end;
 
function TFileContentsStreamOnDemandClipboardFormat.DoSetData(
const FormatEtcIn: TFormatEtc; var AMedium: TStgMedium): boolean;
var
Stream : IStream;
begin
if (Assigned(FOnGetStream)) and (FormatEtcIn.tymed and TYMED_ISTREAM <> 0) and
(FormatEtcIn.lindex <> -1) then
begin
FOnGetStream(Self, FormatEtcIn.lindex, Stream);
 
if (Stream <> nil) then
begin
IStream(AMedium.stm) := Stream;
AMedium.tymed := TYMED_ISTREAM;
Result := True;
end else
Result := False;
 
end else
Result := False;
end;
 
function TFileContentsStreamOnDemandClipboardFormat.GetData(DataObject: IDataObject): boolean;
begin
// Flag that data has been offered to us, but defer the actual data transfer.
FGotData := True;
Result := True;
end;
 
function TFileContentsStreamOnDemandClipboardFormat.GetStream(Index: integer): IStream;
var
Medium : TStgMedium;
begin
Result := nil;
FFormatEtc.lindex := Index;
// Get an IStream interface from the source.
if ((DataFormat.Owner as TCustomDroptarget).DataObject.GetData(FormatEtc,
Medium) = S_OK) and (Medium.tymed = TYMED_ISTREAM) then
try
Result := IStream(Medium.stm);
finally
ReleaseStgMedium(Medium);
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileContentsStorageClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TFileContentsStorageClipboardFormat.Create;
begin
CreateFormat(TYMED_ISTORAGE);
FStorages := TStorageInterfaceList.Create;
end;
 
destructor TFileContentsStorageClipboardFormat.Destroy;
begin
Clear;
FStorages.Free;
inherited Destroy;
end;
 
function TFileContentsStorageClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_FILECONTENTS = 0) then
CF_FILECONTENTS := RegisterClipboardFormat(CFSTR_FILECONTENTS);
Result := CF_FILECONTENTS;
end;
 
procedure TFileContentsStorageClipboardFormat.Clear;
begin
FStorages.Clear;
end;
 
function TFileContentsStorageClipboardFormat.HasData: boolean;
begin
Result := (FStorages.Count > 0);
end;
 
function TFileContentsStorageClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
(*
Result := True;
if (Dest is TDataStreamDataFormat) then
begin
TDataStreamDataFormat(Dest).Streams.Assign(Streams);
end else
*)
Result := inherited AssignTo(Dest);
end;
 
{$IFOPT R+}
{$DEFINE R_PLUS}
{$RANGECHECKS OFF}
{$ENDIF}
function TFileContentsStorageClipboardFormat.GetData(DataObject: IDataObject): boolean;
var
FGD : TFileGroupDescritorClipboardFormat;
Count : integer;
Medium : TStgMedium;
Storage : IStorage;
Name : string;
begin
Result := False;
 
Clear;
FGD := TFileGroupDescritorClipboardFormat.Create;
try
if (FGD.GetData(DataObject)) then
begin
// Multiple objects, retrieve one at a time
Count := FGD.FileGroupDescriptor^.cItems;
FFormatEtc.lindex := 0;
end else
begin
// Single object, retrieve "all" at once
Count := 0;
FFormatEtc.lindex := -1;
Name := '';
end;
while (FFormatEtc.lindex < Count) do
begin
if (DataObject.GetData(FormatEtc, Medium) <> S_OK) then
break;
try
inc(FFormatEtc.lindex);
if (Medium.tymed <> TYMED_ISTORAGE) then
continue;
Storage := IStorage(Medium.stg);
if (FFormatEtc.lindex > 0) then
Name := FGD.FileGroupDescriptor^.fgd[FFormatEtc.lindex-1].cFileName;
Storages.AddNamed(Storage, Name);
Storage := nil;
Result := True;
finally
ReleaseStgMedium(Medium);
end;
end;
finally
FGD.Free;
end;
end;
{$IFDEF R_PLUS}
{$RANGECHECKS ON}
{$UNDEF R_PLUS}
{$ENDIF}
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TPreferredDropEffectClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_PREFERREDDROPEFFECT: TClipFormat = 0;
 
// GetClassClipboardFormat is used by TCustomDropTarget.GetPreferredDropEffect
class function TPreferredDropEffectClipboardFormat.GetClassClipboardFormat: TClipFormat;
begin
if (CF_PREFERREDDROPEFFECT = 0) then
CF_PREFERREDDROPEFFECT := RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
Result := CF_PREFERREDDROPEFFECT;
end;
 
function TPreferredDropEffectClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := GetClassClipboardFormat;
end;
 
function TPreferredDropEffectClipboardFormat.HasData: boolean;
begin
Result := True; //(Value <> DROPEFFECT_NONE);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TPerformedDropEffectClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_PERFORMEDDROPEFFECT: TClipFormat = 0;
 
function TPerformedDropEffectClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_PERFORMEDDROPEFFECT = 0) then
CF_PERFORMEDDROPEFFECT := RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
Result := CF_PERFORMEDDROPEFFECT;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TLogicalPerformedDropEffectClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_LOGICALPERFORMEDDROPEFFECT: TClipFormat = 0;
 
function TLogicalPerformedDropEffectClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_LOGICALPERFORMEDDROPEFFECT = 0) then
CF_LOGICALPERFORMEDDROPEFFECT := RegisterClipboardFormat('Logical Performed DropEffect'); // *** DO NOT LOCALIZE ***
Result := CF_LOGICALPERFORMEDDROPEFFECT;
end;
 
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TPasteSuccededClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_PASTESUCCEEDED: TClipFormat = 0;
 
function TPasteSuccededClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_PASTESUCCEEDED = 0) then
CF_PASTESUCCEEDED := RegisterClipboardFormat(CFSTR_PASTESUCCEEDED);
Result := CF_PASTESUCCEEDED;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TInShellDragLoopClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_InDragLoop: TClipFormat = 0;
 
function TInShellDragLoopClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_InDragLoop = 0) then
CF_InDragLoop := RegisterClipboardFormat(CFSTR_InDragLoop);
Result := CF_InDragLoop;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TTargetCLSIDClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
procedure TTargetCLSIDClipboardFormat.Clear;
begin
FCLSID := GUID_NULL;
end;
 
var
CF_TargetCLSID: TClipFormat = 0;
 
function TTargetCLSIDClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_TargetCLSID = 0) then
CF_TargetCLSID := RegisterClipboardFormat('TargetCLSID'); // *** DO NOT LOCALIZE ***
Result := CF_TargetCLSID;
end;
 
function TTargetCLSIDClipboardFormat.GetSize: integer;
begin
Result := SizeOf(TCLSID);
end;
 
function TTargetCLSIDClipboardFormat.HasData: boolean;
begin
Result := not IsEqualCLSID(FCLSID, GUID_NULL);
end;
 
function TTargetCLSIDClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
// Validate size.
Result := (Size = SizeOf(TCLSID));
if (Result) then
FCLSID := PCLSID(Value)^;
end;
 
function TTargetCLSIDClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
begin
// Validate size.
Result := (Size = SizeOf(TCLSID));
if (Result) then
PCLSID(Value)^ := FCLSID;
end;
 
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TTextDataFormat
//
////////////////////////////////////////////////////////////////////////////////
function TTextDataFormat.Assign(Source: TClipboardFormat): boolean;
begin
Result := True;
 
if (Source is TTextClipboardFormat) then
FText := TTextClipboardFormat(Source).Text
else if (Source is TFileContentsClipboardFormat) then
FText := TFileContentsClipboardFormat(Source).Data
else
Result := inherited Assign(Source);
end;
 
function TTextDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
var
FGD: TFileGroupDescriptor;
FGDW: TFileGroupDescriptorW;
resourcestring
// Name of the text scrap file.
sTextScrap = 'Text scrap.txt';
begin
Result := True;
 
if (Dest is TTextClipboardFormat) then
TTextClipboardFormat(Dest).Text := FText
else if (Dest is TFileContentsClipboardFormat) then
TFileContentsClipboardFormat(Dest).Data := FText
else if (Dest is TFileGroupDescritorClipboardFormat) then
begin
FillChar(FGD, SizeOf(FGD), 0);
FGD.cItems := 1;
StrPLCopy(FGD.fgd[0].cFileName, sTextScrap, SizeOf(FGD.fgd[0].cFileName));
TFileGroupDescritorClipboardFormat(Dest).CopyFrom(@FGD);
end else
if (Dest is TFileGroupDescritorWClipboardFormat) then
begin
FillChar(FGDW, SizeOf(FGDW), 0);
FGDW.cItems := 1;
StringToWideChar(sTextScrap, PWideChar(@(FGDW.fgd[0].cFileName)), MAX_PATH);
TFileGroupDescritorWClipboardFormat(Dest).CopyFrom(@FGDW);
end else
Result := inherited AssignTo(Dest);
end;
 
procedure TTextDataFormat.Clear;
begin
Changing;
FText := '';
end;
 
procedure TTextDataFormat.SetText(const Value: string);
begin
Changing;
FText := Value;
end;
 
function TTextDataFormat.HasData: boolean;
begin
Result := (FText <> '');
end;
 
function TTextDataFormat.NeedsData: boolean;
begin
Result := (FText = '');
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDataStreamDataFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TDataStreamDataFormat.Create(AOwner: TDragDropComponent);
begin
inherited Create(AOwner);
FStreams := TStreamList.Create;
FStreams.OnChanging := DoOnChanging;
end;
 
destructor TDataStreamDataFormat.Destroy;
begin
Clear;
FStreams.Free;
inherited Destroy;
end;
 
procedure TDataStreamDataFormat.Clear;
begin
Changing;
FStreams.Clear;
end;
 
function TDataStreamDataFormat.HasData: boolean;
begin
Result := (Streams.Count > 0);
end;
 
function TDataStreamDataFormat.NeedsData: boolean;
begin
Result := (Streams.Count = 0);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFileDescriptorToFilenameStrings
//
////////////////////////////////////////////////////////////////////////////////
// Used internally to convert between FileDescriptors and filenames on-demand.
////////////////////////////////////////////////////////////////////////////////
type
TFileDescriptorToFilenameStrings = class(TStrings)
private
FFileDescriptors: TMemoryList;
protected
function Get(Index: Integer): string; override;
function GetCount: Integer; override;
public
constructor Create(AFileDescriptors: TMemoryList);
procedure Clear; override;
procedure Delete(Index: Integer); override;
procedure Insert(Index: Integer; const S: string); override;
procedure Assign(Source: TPersistent); override;
end;
 
constructor TFileDescriptorToFilenameStrings.Create(AFileDescriptors: TMemoryList);
begin
inherited Create;
FFileDescriptors := AFileDescriptors;
end;
 
function TFileDescriptorToFilenameStrings.Get(Index: Integer): string;
begin
Result := PFileDescriptor(FFileDescriptors[Index]).cFileName;
end;
 
function TFileDescriptorToFilenameStrings.GetCount: Integer;
begin
Result := FFileDescriptors.Count;
end;
 
procedure TFileDescriptorToFilenameStrings.Assign(Source: TPersistent);
var
i: integer;
begin
if Source is TStrings then
begin
BeginUpdate;
try
FFileDescriptors.Clear;
for i := 0 to TStrings(Source).Count-1 do
Add(TStrings(Source)[i]);
finally
EndUpdate;
end;
end else
inherited Assign(Source);
end;
 
procedure TFileDescriptorToFilenameStrings.Clear;
begin
FFileDescriptors.Clear;
end;
 
procedure TFileDescriptorToFilenameStrings.Delete(Index: Integer);
begin
FFileDescriptors.Delete(Index);
end;
 
procedure TFileDescriptorToFilenameStrings.Insert(Index: Integer; const S: string);
var
FD: PFileDescriptor;
begin
if (Index = FFileDescriptors.Count) then
begin
GetMem(FD, SizeOf(TFileDescriptor));
try
FillChar(FD^, SizeOf(TFileDescriptor), 0);
StrPLCopy(FD.cFileName, S, SizeOf(FD.cFileName));
FFileDescriptors.Add(FD);
except
FreeMem(FD);
raise;
end;
end;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TVirtualFileStreamDataFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TVirtualFileStreamDataFormat.Create(AOwner: TDragDropComponent);
begin
inherited Create(AOwner);
FFileDescriptors := TMemoryList.Create;
FFileNames := TFileDescriptorToFilenameStrings.Create(FFileDescriptors);
 
// Add the "file group descriptor" and "file contents" clipboard formats to
// the data format's list of compatible formats.
// Note: This is normally done via TCustomDataFormat.RegisterCompatibleFormat,
// but since this data format and the clipboard format class are specialized
// to be used with each other, it is just as easy for us to add the formats
// manually.
FFileContentsClipboardFormat := TFileContentsStreamOnDemandClipboardFormat.Create;
CompatibleFormats.Add(FFileContentsClipboardFormat);
 
FFileGroupDescritorClipboardFormat := TFileGroupDescritorClipboardFormat.Create;
 
// Normaly TFileGroupDescritorClipboardFormat supports both HGlobal and
// IStream storage medium transfers, but for this demo we only use IStream.
// FFileGroupDescritorClipboardFormat.FormatEtc.tymed := TYMED_ISTREAM;
 
CompatibleFormats.Add(FFileGroupDescritorClipboardFormat);
end;
 
destructor TVirtualFileStreamDataFormat.Destroy;
begin
FFileDescriptors.Free;
FFileNames.Free;
inherited Destroy;
end;
 
procedure TVirtualFileStreamDataFormat.SetFileNames(const Value: TStrings);
begin
FFileNames.Assign(Value);
end;
 
{$IFOPT R+}
{$DEFINE R_PLUS}
{$RANGECHECKS OFF}
{$ENDIF}
function TVirtualFileStreamDataFormat.Assign(Source: TClipboardFormat): boolean;
var
i: integer;
FD: PFileDescriptor;
begin
Result := True;
 
(*
** TFileContentsStreamOnDemandClipboardFormat
*)
if (Source is TFileContentsStreamOnDemandClipboardFormat) then
begin
FHasContents := TFileContentsStreamOnDemandClipboardFormat(Source).HasData;
end else
(*
** TFileGroupDescritorClipboardFormat
*)
if (Source is TFileGroupDescritorClipboardFormat) then
begin
FFileDescriptors.Clear;
for i := 0 to TFileGroupDescritorClipboardFormat(Source).FileGroupDescriptor^.cItems-1 do
begin
GetMem(FD, SizeOf(TFileDescriptor));
try
Move(TFileGroupDescritorClipboardFormat(Source).FileGroupDescriptor^.fgd[i],
FD^, SizeOf(TFileDescriptor));
FFileDescriptors.Add(FD);
except
FreeMem(FD);
raise;
end;
end;
end else
(*
** None of the above...
*)
Result := inherited Assign(Source);
end;
{$IFDEF R_PLUS}
{$RANGECHECKS ON}
{$UNDEF R_PLUS}
{$ENDIF}
 
{$IFOPT R+}
{$DEFINE R_PLUS}
{$RANGECHECKS OFF}
{$ENDIF}
function TVirtualFileStreamDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
var
FGD: PFileGroupDescriptor;
i: integer;
begin
(*
** TFileContentsStreamOnDemandClipboardFormat
*)
if (Dest is TFileContentsStreamOnDemandClipboardFormat) then
begin
// Let the clipboard format handle the transfer.
// No data is actually transferred, but TFileContentsStreamOnDemandClipboardFormat
// needs to set a flag when data is requested.
Result := Dest.Assign(Self);
end else
(*
** TFileGroupDescritorClipboardFormat
*)
if (Dest is TFileGroupDescritorClipboardFormat) then
begin
if (FFileDescriptors.Count > 0) then
begin
GetMem(FGD, SizeOf(UINT) + FFileDescriptors.Count * SizeOf(TFileDescriptor));
try
FGD.cItems := FFileDescriptors.Count;
for i := 0 to FFileDescriptors.Count-1 do
Move(FFileDescriptors[i]^, FGD.fgd[i], SizeOf(TFileDescriptor));
 
TFileGroupDescritorClipboardFormat(Dest).CopyFrom(FGD);
finally
FreeMem(FGD);
end;
Result := True;
end else
Result := False;
end else
(*
** None of the above...
*)
Result := inherited AssignTo(Dest);
end;
{$IFDEF R_PLUS}
{$RANGECHECKS ON}
{$UNDEF R_PLUS}
{$ENDIF}
 
procedure TVirtualFileStreamDataFormat.Clear;
begin
FFileDescriptors.Clear;
FHasContents := False;
end;
 
function TVirtualFileStreamDataFormat.HasData: boolean;
begin
Result := (FFileDescriptors.Count > 0) and
((FHasContents) or Assigned(FFileContentsClipboardFormat.OnGetStream));
end;
 
function TVirtualFileStreamDataFormat.NeedsData: boolean;
begin
Result := (FFileDescriptors.Count = 0) or (not FHasContents);
end;
 
function TVirtualFileStreamDataFormat.GetOnGetStream: TOnGetStreamEvent;
begin
Result := FFileContentsClipboardFormat.OnGetStream;
end;
 
procedure TVirtualFileStreamDataFormat.SetOnGetStream(const Value: TOnGetStreamEvent);
begin
FFileContentsClipboardFormat.OnGetStream := Value;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TFeedbackDataFormat
//
////////////////////////////////////////////////////////////////////////////////
function TFeedbackDataFormat.Assign(Source: TClipboardFormat): boolean;
begin
Result := True;
 
if (Source is TPreferredDropEffectClipboardFormat) then
FPreferredDropEffect := TPreferredDropEffectClipboardFormat(Source).Value
 
else if (Source is TPerformedDropEffectClipboardFormat) then
FPerformedDropEffect := TPerformedDropEffectClipboardFormat(Source).Value
 
else if (Source is TLogicalPerformedDropEffectClipboardFormat) then
FLogicalPerformedDropEffect := TLogicalPerformedDropEffectClipboardFormat(Source).Value
 
else if (Source is TPasteSuccededClipboardFormat) then
FPasteSucceded := TPasteSuccededClipboardFormat(Source).Value
 
else if (Source is TTargetCLSIDClipboardFormat) then
FTargetCLSID := TTargetCLSIDClipboardFormat(Source).CLSID
 
else if (Source is TInShellDragLoopClipboardFormat) then
begin
FInShellDragLoop := TInShellDragLoopClipboardFormat(Source).InShellDragLoop;
FGotInShellDragLoop := True;
end else
Result := inherited Assign(Source);
end;
 
function TFeedbackDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
begin
Result := True;
 
if (Dest is TPreferredDropEffectClipboardFormat) then
TPreferredDropEffectClipboardFormat(Dest).Value := FPreferredDropEffect
 
else if (Dest is TPerformedDropEffectClipboardFormat) then
TPerformedDropEffectClipboardFormat(Dest).Value := FPerformedDropEffect
 
else if (Dest is TLogicalPerformedDropEffectClipboardFormat) then
TLogicalPerformedDropEffectClipboardFormat(Dest).Value := FLogicalPerformedDropEffect
 
else if (Dest is TPasteSuccededClipboardFormat) then
TPasteSuccededClipboardFormat(Dest).Value := FPasteSucceded
 
else if (Dest is TTargetCLSIDClipboardFormat) then
TTargetCLSIDClipboardFormat(Dest).CLSID := FTargetCLSID
 
else if (Dest is TInShellDragLoopClipboardFormat) then
TInShellDragLoopClipboardFormat(Dest).InShellDragLoop := FInShellDragLoop
 
else
Result := inherited AssignTo(Dest);
end;
 
procedure TFeedbackDataFormat.Clear;
begin
Changing;
FPreferredDropEffect := DROPEFFECT_NONE;
FPerformedDropEffect := DROPEFFECT_NONE;
FInShellDragLoop := False;
FGotInShellDragLoop := False;
end;
 
procedure TFeedbackDataFormat.SetInShellDragLoop(const Value: boolean);
begin
Changing;
FInShellDragLoop := Value;
end;
 
procedure TFeedbackDataFormat.SetPasteSucceded(const Value: longInt);
begin
Changing;
FPasteSucceded := Value;
end;
 
procedure TFeedbackDataFormat.SetPerformedDropEffect(
const Value: longInt);
begin
Changing;
FPerformedDropEffect := Value;
end;
 
procedure TFeedbackDataFormat.SetLogicalPerformedDropEffect(
const Value: longInt);
begin
Changing;
FLogicalPerformedDropEffect := Value;
end;
 
procedure TFeedbackDataFormat.SetPreferredDropEffect(
const Value: longInt);
begin
Changing;
FPreferredDropEffect := Value;
end;
 
procedure TFeedbackDataFormat.SetTargetCLSID(const Value: TCLSID);
begin
Changing;
FTargetCLSID := Value;
end;
 
function TFeedbackDataFormat.HasData: boolean;
begin
Result := (FPreferredDropEffect <> DROPEFFECT_NONE) or
(FPerformedDropEffect <> DROPEFFECT_NONE) or
(FPasteSucceded <> DROPEFFECT_NONE) or
(FGotInShellDragLoop);
end;
 
function TFeedbackDataFormat.NeedsData: boolean;
begin
Result := (FPreferredDropEffect = DROPEFFECT_NONE) or
(FPerformedDropEffect = DROPEFFECT_NONE) or
(FPasteSucceded = DROPEFFECT_NONE) or
(not FGotInShellDragLoop);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TGenericClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
procedure TGenericClipboardFormat.SetClipboardFormatName(const Value: string);
begin
FFormat := Value;
if (FFormat <> '') then
ClipboardFormat := RegisterClipboardFormat(PChar(FFormat));
end;
 
function TGenericClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (FFormatEtc.cfFormat = 0) and (FFormat <> '') then
FFormatEtc.cfFormat := RegisterClipboardFormat(PChar(FFormat));
Result := FFormatEtc.cfFormat;
end;
 
function TGenericClipboardFormat.GetClipboardFormatName: string;
begin
Result := FFormat;
end;
 
function TGenericClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
if (Source is TGenericDataFormat) then
begin
Data := TGenericDataFormat(Source).Data;
Result := True;
end else
Result := inherited Assign(Source);
end;
 
function TGenericClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
if (Dest is TGenericDataFormat) then
begin
TGenericDataFormat(Dest).Data := Data;
Result := True;
end else
Result := inherited AssignTo(Dest);
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TGenericDataFormat
//
////////////////////////////////////////////////////////////////////////////////
procedure TGenericDataFormat.AddFormat(const AFormat: string);
var
ClipboardFormat: TGenericClipboardFormat;
begin
ClipboardFormat := TGenericClipboardFormat.Create;
ClipboardFormat.ClipboardFormatName := AFormat;
ClipboardFormat.DataDirections := [ddRead];
CompatibleFormats.Add(ClipboardFormat);
end;
 
procedure TGenericDataFormat.Clear;
begin
Changing;
FData := '';
end;
 
function TGenericDataFormat.HasData: boolean;
begin
Result := (FData <> '');
end;
 
function TGenericDataFormat.NeedsData: boolean;
begin
Result := (FData = '');
end;
 
procedure TGenericDataFormat.DoSetData(const Value: string);
begin
Changing;
FData := Value;
end;
 
procedure TGenericDataFormat.SetDataHere(const AData; ASize: integer);
begin
Changing;
SetLength(FData, ASize);
Move(AData, PChar(FData)^, ASize);
end;
 
function TGenericDataFormat.GetSize: integer;
begin
Result := length(FData);
end;
 
function TGenericDataFormat.GetDataHere(var AData; ASize: integer): integer;
begin
Result := Size;
if (ASize < Result) then
Result := ASize;
Move(PChar(FData)^, AData, Result);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Initialization/Finalization
//
////////////////////////////////////////////////////////////////////////////////
 
initialization
// Data format registration
TTextDataFormat.RegisterDataFormat;
TDataStreamDataFormat.RegisterDataFormat;
TVirtualFileStreamDataFormat.RegisterDataFormat;
 
// Clipboard format registration
TTextDataFormat.RegisterCompatibleFormat(TTextClipboardFormat, 0, csSourceTarget, [ddRead]);
TTextDataFormat.RegisterCompatibleFormat(TFileContentsClipboardFormat, 1, csSourceTarget, [ddRead]);
TTextDataFormat.RegisterCompatibleFormat(TFileGroupDescritorClipboardFormat, 1, [csSource], [ddRead]);
TTextDataFormat.RegisterCompatibleFormat(TFileGroupDescritorWClipboardFormat, 1, [csSource], [ddRead]);
TFeedbackDataFormat.RegisterCompatibleFormat(TPreferredDropEffectClipboardFormat, 0, csSourceTarget, [ddRead]);
TFeedbackDataFormat.RegisterCompatibleFormat(TPerformedDropEffectClipboardFormat, 0, csSourceTarget, [ddWrite]);
TFeedbackDataFormat.RegisterCompatibleFormat(TPasteSuccededClipboardFormat, 0, csSourceTarget, [ddWrite]);
TFeedbackDataFormat.RegisterCompatibleFormat(TInShellDragLoopClipboardFormat, 0, csSourceTarget, [ddRead]);
TFeedbackDataFormat.RegisterCompatibleFormat(TTargetCLSIDClipboardFormat, 0, csSourceTarget, [ddWrite]);
TFeedbackDataFormat.RegisterCompatibleFormat(TLogicalPerformedDropEffectClipboardFormat, 0, csSourceTarget, [ddWrite]);
TDataStreamDataFormat.RegisterCompatibleFormat(TFileContentsStreamClipboardFormat, 0, [csTarget], [ddRead]);
 
finalization
TTextDataFormat.UnregisterDataFormat;
TDataStreamDataFormat.UnregisterDataFormat;
TFeedbackDataFormat.UnregisterDataFormat;
TVirtualFileStreamDataFormat.UnregisterDataFormat;
 
TTextClipboardFormat.UnregisterClipboardFormat;
TFileGroupDescritorClipboardFormat.UnregisterClipboardFormat;
TFileGroupDescritorWClipboardFormat.UnregisterClipboardFormat;
TFileContentsClipboardFormat.UnregisterClipboardFormat;
TFileContentsStreamClipboardFormat.UnregisterClipboardFormat;
TPreferredDropEffectClipboardFormat.UnregisterClipboardFormat;
TPerformedDropEffectClipboardFormat.UnregisterClipboardFormat;
TPasteSuccededClipboardFormat.UnregisterClipboardFormat;
TInShellDragLoopClipboardFormat.UnregisterClipboardFormat;
TTargetCLSIDClipboardFormat.UnregisterClipboardFormat;
TLogicalPerformedDropEffectClipboardFormat.UnregisterClipboardFormat;
 
end.
 
 
/trunk/VCL_DRAGDROP/DragDropGraphics.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDropGraphics.pas
0,0 → 1,988
unit DragDropGraphics;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite.
// Module: DragDropGraphics
// Description: Implements Dragging and Dropping of graphic data.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
interface
 
uses
DragDrop,
DropTarget,
DropSource,
ActiveX,
Windows,
Graphics,
Classes;
 
{$include DragDrop.inc}
 
type
////////////////////////////////////////////////////////////////////////////////
//
// TGDIClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Base class for GDI clipboard formats (TYMED_GDI).
////////////////////////////////////////////////////////////////////////////////
TGDIClipboardFormat = class(TClipboardFormat)
public
constructor Create; override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TPaletteClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Only used internally by TBitmapClipboardFormat - Not registered
////////////////////////////////////////////////////////////////////////////////
TPaletteClipboardFormat = class(TGDIClipboardFormat)
private
FPalette : hPalette;
public
function GetClipboardFormat: TClipFormat; override;
function DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean; override;
function DoSetData(const FormatEtcIn: TFormatEtc;
var Medium: TStgMedium): boolean; override;
procedure Clear; override;
property Palette: hPalette read FPalette write FPalette;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomBitmapClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TCustomBitmapClipboardFormat = class(TGDIClipboardFormat)
private
FBitmap : TBitmap;
protected
constructor CreateFormat(Atymed: Longint); override;
public
destructor Destroy; override;
procedure Clear; override;
property Bitmap: TBitmap read FBitmap;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TBitmapClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TBitmapClipboardFormat = class(TCustomBitmapClipboardFormat)
protected
function DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean; override;
function DoSetData(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean; override;
public
function GetClipboardFormat: TClipFormat; override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDIBClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TDIBClipboardFormat = class(TCustomBitmapClipboardFormat)
private
protected
function DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean; override;
function DoSetData(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean; override;
public
constructor Create; override;
function GetClipboardFormat: TClipFormat; override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomMetaFileClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TCustomMetaFileClipboardFormat = class(TClipboardFormat)
private
FMetaFile : TMetaFile;
protected
public
constructor Create; override;
destructor Destroy; override;
procedure Clear; override;
property MetaFile: TMetaFile read FMetaFile;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TMetaFileClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TMetaFileClipboardFormat = class(TCustomMetaFileClipboardFormat)
private
protected
function DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean; override;
public
function GetClipboardFormat: TClipFormat; override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TEnhMetaFileClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TEnhMetaFileClipboardFormat = class(TCustomMetaFileClipboardFormat)
private
protected
function DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean; override;
public
function GetClipboardFormat: TClipFormat; override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TBitmapDataFormat
//
////////////////////////////////////////////////////////////////////////////////
TBitmapDataFormat = class(TCustomDataFormat)
private
FBitmap : TBitmap;
protected
public
constructor Create(AOwner: TDragDropComponent); override;
destructor Destroy; override;
function Assign(Source: TClipboardFormat): boolean; override;
function AssignTo(Dest: TClipboardFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property Bitmap: TBitmap read FBitmap;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TMetaFileDataFormat
//
////////////////////////////////////////////////////////////////////////////////
TMetaFileDataFormat = class(TCustomDataFormat)
private
FMetaFile : TMetaFile;
protected
public
constructor Create(AOwner: TDragDropComponent); override;
destructor Destroy; override;
function Assign(Source: TClipboardFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property MetaFile: TMetaFile read FMetaFile;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropBMPTarget
//
////////////////////////////////////////////////////////////////////////////////
TDropBMPTarget = class(TCustomDropMultiTarget)
private
FBitmapFormat : TBitmapDataFormat;
protected
function GetBitmap: TBitmap;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Bitmap: TBitmap read GetBitmap;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropBMPSource
//
////////////////////////////////////////////////////////////////////////////////
TDropBMPSource = class(TCustomDropMultiSource)
private
FBitmapFormat : TBitmapDataFormat;
protected
procedure SetBitmap(const Value: TBitmap);
function GetBitmap: TBitmap;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Bitmap: TBitmap read GetBitmap write SetBitmap;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropMetaFileTarget
//
////////////////////////////////////////////////////////////////////////////////
TDropMetaFileTarget = class(TCustomDropMultiTarget)
private
FMetaFileFormat : TMetaFileDataFormat;
protected
function GetMetaFile: TMetaFile;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property MetaFile: TMetaFile read GetMetaFile;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropImageTarget
//
////////////////////////////////////////////////////////////////////////////////
TDropImageTarget = class(TCustomDropMultiTarget)
private
FMetaFileFormat : TMetaFileDataFormat;
FBitmapFormat : TBitmapDataFormat;
FPicture : TPicture;
protected
function DoGetData: boolean; override;
procedure ClearData; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Picture: TPicture read FPicture;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc.
//
////////////////////////////////////////////////////////////////////////////////
procedure CopyDIBToBitmap(Bitmap: TBitmap; BitmapInfo: PBitmapInfo; DIBSize: integer);
function GetHGlobalDIBFromBitmap(Bitmap: TBitmap): HGlobal;
 
 
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
implementation
 
uses
SysUtils;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDropBMPTarget,
TDropBMPSource, TDropMetaFileTarget, TDropImageTarget]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc.
//
////////////////////////////////////////////////////////////////////////////////
procedure CopyDIBToBitmap(Bitmap: TBitmap; BitmapInfo: PBitmapInfo; DIBSize: integer);
var
BitmapFileHeader : TBitmapFileHeader;
FileSize : integer;
InfoSize : integer;
Stream : TMemoryStream;
begin
// Write DIB to a stream in the BMP file format
Stream := TMemoryStream.Create;
try
FileSize := sizeof(TBitmapFileHeader) + DIBSize;
InfoSize := sizeof(TBitmapInfoHeader);
if (BitmapInfo^.bmiHeader.biBitCount > 8) then
begin
if ((BitmapInfo^.bmiHeader.biCompression and BI_BITFIELDS) <> 0) then
Inc(InfoSize, 12);
end else
Inc(InfoSize, sizeof(TRGBQuad) * (1 shl BitmapInfo^.bmiHeader.biBitCount));
Stream.SetSize(FileSize);
// Initialize file header
FillChar(BitmapFileHeader, sizeof(TBitmapFileHeader), 0);
with BitmapFileHeader do
begin
bfType := $4D42; // 'BM' = Windows BMP signature
bfSize := FileSize; // File size (not needed)
bfOffBits := sizeof(TBitmapFileHeader) + InfoSize; // Offset of pixel data
end;
// Save file header
Stream.Write(BitmapFileHeader, sizeof(TBitmapFileHeader));
// Save TBitmapInfo structure and pixel data
Stream.Write(BitmapInfo^, DIBSize);
 
// Rewind and load bitmap from stream
Stream.Position := 0;
Bitmap.LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
 
function GetHGlobalDIBFromBitmap(Bitmap: TBitmap): HGlobal;
var
Stream : TMemoryStream;
DIB : pointer;
DIBSize : integer;
begin
Stream := TMemoryStream.Create;
try
// Write bitmap to a stream and extract the DIB data from it.
Bitmap.SaveToStream(Stream);
 
// Calculate size of DIB block.
DIBSize := Stream.Size - SizeOf(TBitmapFileHeader);
 
// Allocate memory for DIB data.
Result := GlobalAlloc(GMEM_MOVEABLE or GMEM_SHARE, DIBSize);
if (Result = 0) then
exit;
 
DIB := GlobalLock(Result);
if DIB = nil then
begin
GlobalFree(Result);
Result := 0;
end else
begin
// Skip BMP file header.
Stream.Seek(SizeOf(TBitmapFileHeader), soFromBeginning);
// Transfer data from stream to global memory.
if (Stream.Read(DIB^, DIBSize) <> DIBSize) then
begin
GlobalUnlock(Result);
GlobalFree(Result);
Result := 0;
end else
GlobalUnlock(Result);
end;
finally
Stream.free;
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TGDIClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TGDIClipboardFormat.Create;
begin
CreateFormat(TYMED_GDI);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TPaletteClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
function TPaletteClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := CF_PALETTE;
end;
 
procedure TPaletteClipboardFormat.Clear;
begin
if (FPalette <> 0) then
begin
DeleteObject(FPalette);
FPalette := 0;
end;
end;
 
function TPaletteClipboardFormat.DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean;
begin
if (AMedium.hBitmap <> 0) then
begin
FPalette := CopyPalette(AMedium.hBitmap);
Result := (FPalette <> 0);
end else
Result := False;
end;
 
function TPaletteClipboardFormat.DoSetData(const FormatEtcIn: TFormatEtc;
var Medium: TStgMedium): boolean;
begin
Result := False;
 
try
Medium.hBitmap := CopyPalette(FPalette);
except
exit;
end;
 
if (Medium.hBitmap <> 0) then
begin
Medium.tymed := TYMED_GDI;
result := True;
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TBitmapClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TCustomBitmapClipboardFormat.CreateFormat(Atymed: Longint);
begin
inherited CreateFormat(Atymed);
 
FBitmap := Graphics.TBitmap.Create;
end;
 
destructor TCustomBitmapClipboardFormat.Destroy;
begin
if (FBitmap <> nil) then
FBitmap.Free;
 
inherited Destroy;
end;
 
procedure TCustomBitmapClipboardFormat.Clear;
begin
FBitmap.Handle := 0;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TBitmapClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
function TBitmapClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := CF_BITMAP;
end;
 
function TBitmapClipboardFormat.DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean;
var
Palette : TPaletteClipboardFormat;
begin
Result := False;
if (AMedium.hBitmap = 0) then
exit;
Palette := TPaletteClipboardFormat.Create;
try
// Attempt to get palette from source. However in case the bitmap is in a
// format which doesn't use palettes, there might not be one available.
// The CF_BITMAP/CF_PALETTE documentation doesn't mention if CF_BITMAP must
// always be accompanied with a CF_PALETTE.
Palette.GetData(ADataObject);
// Let TBitmap do the work for us.
FBitmap.LoadFromClipboardFormat(CF_BITMAP, AMedium.hBitmap, Palette.Palette);
finally
Palette.Free;
end;
Result := True;
end;
 
function TBitmapClipboardFormat.DoSetData(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean;
var
Palette : HPalette;
Format : Word;
hBitmap : THandle;
begin
Result := False;
 
try
Format := CF_BITMAP;
FBitmap.SaveToClipboardFormat(Format, hBitmap, Palette);
AMedium.hBitmap := hBitmap;
except
exit;
end;
 
try
if (Format <> CF_BITMAP) then
begin
DeleteObject(AMedium.hBitmap);
AMedium.hBitmap := 0;
exit;
end;
AMedium.tymed := TYMED_GDI;
finally
DeleteObject(Palette);
end;
Result := True;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDIBClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TDIBClipboardFormat.Create;
begin
// Note: We must override Create since base class Create sets tymed to
// TYMED_GDI.
CreateFormat(TYMED_HGLOBAL);
end;
 
function TDIBClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := CF_DIB;
end;
 
// http://x5.dejanews.com/[ST_rn=ps]/getdoc.xp?AN=382056726.2&CONTEXT=925473183.2090336317&hitnum=0
function TDIBClipboardFormat.DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean;
var
BitmapInfo : PBitmapInfo;
BitmapFileHeader : TBitmapFileHeader;
DIBSize : integer;
FileSize : integer;
InfoSize : integer;
Stream : TMemoryStream;
begin
// Get data source's DIB block
BitmapInfo := GlobalLock(AMedium.HGlobal);
try
Result := (BitmapInfo <> nil);
if (not Result) then
exit;
 
// Write DIB to a stream in the BMP file format
Stream := TMemoryStream.Create;
try
// Get size of data source's DIB block
DIBSize := GlobalSize(AMedium.HGlobal);
// Calculate total bitmap file size
FileSize := sizeof(TBitmapFileHeader) + DIBSize;
// Calculate bitmap header size
InfoSize := sizeof(TBitmapInfoHeader);
if (BitmapInfo^.bmiHeader.biBitCount > 8) then
begin
if ((BitmapInfo^.bmiHeader.biCompression and BI_BITFIELDS) <> 0) then
Inc(InfoSize, 12);
end else
Inc(InfoSize, sizeof(TRGBQuad) * (1 shl BitmapInfo^.bmiHeader.biBitCount));
 
Stream.SetSize(FileSize);
// Initialize file header
FillChar(BitmapFileHeader, sizeof(TBitmapFileHeader), 0);
with BitmapFileHeader do
begin
bfType := $4D42; // 'BM' = Windows BMP signature
bfSize := FileSize; // File size (not needed)
bfOffBits := sizeof(TBitmapFileHeader) + InfoSize; // Offset of pixel data
end;
// Save file header
Stream.Write(BitmapFileHeader, sizeof(TBitmapFileHeader));
// Save TBitmapInfo structure and pixel data
Stream.Write(BitmapInfo^, DIBSize);
 
// Rewind and load bitmap from stream
Stream.Position := 0;
FBitmap.LoadFromStream(Stream);
finally
Stream.Free;
end;
finally
GlobalUnlock(AMedium.HGlobal);
end;
end;
 
function TDIBClipboardFormat.DoSetData(const FormatEtcIn: TFormatEtc;
var AMedium: TStgMedium): boolean;
begin
AMedium.hBitmap := GetHGlobalDIBFromBitmap(FBitmap);
Result := (AMedium.hBitmap <> 0);
if (Result) then
AMedium.tymed := TYMED_HGLOBAL;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomMetaFileClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TCustomMetaFileClipboardFormat.Create;
begin
CreateFormat(TYMED_MFPICT);
FMetaFile := TMetaFile.Create;
end;
 
destructor TCustomMetaFileClipboardFormat.Destroy;
begin
if (FMetaFile <> nil) then
FMetaFile.Free;
inherited Destroy;
end;
 
procedure TCustomMetaFileClipboardFormat.Clear;
begin
FMetaFile.Clear;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TMetaFileClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
function TMetaFileClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := CF_METAFILEPICT;
end;
 
function WMF2EMF(const MetaFile: TMetaFilePict): hEnhMetaFile;
var
Bits : Pointer;
Length : UINT;
RefDC : HDC;
begin
Length := GetMetaFileBitsEx(MetaFile.hMF, 0, nil);
if (Length = 0) then
_RaiseLastWin32Error;
GetMem(Bits, Length);
try
if (GetMetaFileBitsEx(MetaFile.hMF, Length, Bits) < Length) then
_RaiseLastWin32Error;
RefDC := GetDC(0);
try
Result := SetWinMetaFileBits(Length, Bits, RefDC, MetaFile);
finally
ReleaseDC(0, RefDC);
end;
if (Result = 0) then
_RaiseLastWin32Error;
finally
FreeMem(Bits);
end;
end;
 
function TMetaFileClipboardFormat.DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean;
var
pMetaFile : PMetaFilePict;
begin
pMetaFile := GlobalLock(AMedium.hMetaFilePict);
try
Result := (pMetaFile <> nil);
if (Result) then
FMetaFile.Handle := WMF2EMF(pMetaFile^);
finally
GlobalUnlock(AMedium.hMetaFilePict);
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TEnhMetaFileClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
function TEnhMetaFileClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := CF_ENHMETAFILE;
end;
 
function TEnhMetaFileClipboardFormat.DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean;
begin
Result := (AMedium.hEnhMetaFile <> 0);
if (Result) then
FMetaFile.Handle := CopyEnhMetafile(AMedium.hEnhMetaFile, nil);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TBitmapDataFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TBitmapDataFormat.Create(AOwner: TDragDropComponent);
begin
inherited Create(AOwner);
FBitmap := TBitmap.Create;
// TGraphic.OnChange is fired too late (after change), but it's the best
// we can get.
FBitmap.OnChange := DoOnChanging;
end;
 
destructor TBitmapDataFormat.Destroy;
begin
Clear;
FBitmap.Free;
inherited Destroy;
end;
 
function TBitmapDataFormat.Assign(Source: TClipboardFormat): boolean;
begin
Result := True;
 
if (Source is TDIBClipboardFormat) then
FBitmap.Assign(TDIBClipboardFormat(Source).Bitmap)
 
else if (Source is TBitmapClipboardFormat) then
FBitmap.Assign(TBitmapClipboardFormat(Source).Bitmap)
 
// TODO -oanme : Is this nescessary? Palette is extracted in TBitmapClipboardFormat GetData.
else if (Source is TPaletteClipboardFormat) then
FBitmap.Palette := CopyPalette(TPaletteClipboardFormat(Source).Palette)
 
else
Result := inherited Assign(Source);
end;
 
function TBitmapDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
begin
Result := True;
 
if (Dest is TDIBClipboardFormat) then
TDIBClipboardFormat(Dest).Bitmap.Assign(FBitmap)
 
else if (Dest is TBitmapClipboardFormat) then
TBitmapClipboardFormat(Dest).Bitmap.Assign(FBitmap)
 
else if (Dest is TPaletteClipboardFormat) then
TPaletteClipboardFormat(Dest).Palette := CopyPalette(FBitmap.Palette)
 
else
Result := inherited AssignTo(Dest);
end;
 
procedure TBitmapDataFormat.Clear;
begin
Changing;
FBitmap.Handle := 0;
end;
 
function TBitmapDataFormat.HasData: boolean;
begin
Result := (not FBitmap.Empty);
end;
 
function TBitmapDataFormat.NeedsData: boolean;
begin
Result := (FBitmap.Empty);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TMetaFileDataFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TMetaFileDataFormat.Create(AOwner: TDragDropComponent);
begin
inherited Create(AOwner);
FMetaFile := TMetaFile.Create;
// TGraphic.OnChange is fired too late (after change), but it's the best
// we can get.
FMetaFile.OnChange := DoOnChanging;
end;
 
destructor TMetaFileDataFormat.Destroy;
begin
Clear;
FMetaFile.Free;
inherited Destroy;
end;
 
function TMetaFileDataFormat.Assign(Source: TClipboardFormat): boolean;
begin
Result := True;
 
if (Source is TMetaFileClipboardFormat) then
FMetaFile.Assign(TMetaFileClipboardFormat(Source).MetaFile)
 
else if (Source is TEnhMetaFileClipboardFormat) then
FMetaFile.Assign(TEnhMetaFileClipboardFormat(Source).MetaFile)
 
else
Result := inherited Assign(Source);
end;
 
procedure TMetaFileDataFormat.Clear;
begin
Changing;
FMetaFile.Clear;
end;
 
function TMetaFileDataFormat.HasData: boolean;
begin
Result := (FMetaFile.Handle <> 0);
end;
 
function TMetaFileDataFormat.NeedsData: boolean;
begin
Result := (FMetaFile.Handle = 0);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropBMPTarget
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropBMPTarget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FBitmapFormat := TBitmapDataFormat.Create(Self);
end;
 
destructor TDropBMPTarget.Destroy;
begin
FBitmapFormat.Free;
inherited Destroy;
end;
 
function TDropBMPTarget.GetBitmap: TBitmap;
begin
Result := FBitmapFormat.Bitmap;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropBMPSource
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropBMPSource.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
 
DragTypes := [dtCopy]; // Default to Copy
 
FBitmapFormat := TBitmapDataFormat.Create(Self);
end;
 
destructor TDropBMPSource.destroy;
begin
FBitmapFormat.Free;
inherited Destroy;
end;
 
function TDropBMPSource.GetBitmap: TBitmap;
begin
Result := FBitmapFormat.Bitmap;
end;
 
procedure TDropBMPSource.SetBitmap(const Value: TBitmap);
begin
FBitmapFormat.Bitmap.Assign(Value);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropMetaFileTarget
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropMetaFileTarget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FMetaFileFormat := TMetaFileDataFormat.Create(Self);
end;
 
destructor TDropMetaFileTarget.Destroy;
begin
FMetaFileFormat.Free;
inherited Destroy;
end;
 
function TDropMetaFileTarget.GetMetaFile: TMetaFile;
begin
Result := FMetaFileFormat.MetaFile;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropMetaFileTarget
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropImageTarget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FMetaFileFormat := TMetaFileDataFormat.Create(Self);
FBitmapFormat := TBitmapDataFormat.Create(Self);
FPicture := TPicture.Create;
end;
 
destructor TDropImageTarget.Destroy;
begin
FPicture.Free;
FBitmapFormat.Free;
FMetaFileFormat.Free;
inherited Destroy;
end;
 
procedure TDropImageTarget.ClearData;
begin
inherited ClearData;
FPicture.Assign(nil);
end;
 
function TDropImageTarget.DoGetData: boolean;
begin
Result := inherited DoGetData;
if (Result) then
begin
if (FBitmapFormat.HasData) then
FPicture.Assign(FBitmapFormat.Bitmap)
else if (FMetaFileFormat.HasData) then
FPicture.Assign(FMetaFileFormat.MetaFile)
else
Result := False;
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Initialization/Finalization
//
////////////////////////////////////////////////////////////////////////////////
 
initialization
// Data format registration
TBitmapDataFormat.RegisterDataFormat;
TMetaFileDataFormat.RegisterDataFormat;
// Clipboard format registration
TBitmapDataFormat.RegisterCompatibleFormat(TDIBClipboardFormat, 0, csSourceTarget, [ddRead]);
TBitmapDataFormat.RegisterCompatibleFormat(TBitmapClipboardFormat, 1, csSourceTarget, [ddRead]);
TBitmapDataFormat.RegisterCompatibleFormat(TPaletteClipboardFormat, 1, csSourceTarget, [ddRead]);
TMetaFileDataFormat.RegisterCompatibleFormat(TEnhMetaFileClipboardFormat, 0, [csTarget], [ddRead]);
TMetaFileDataFormat.RegisterCompatibleFormat(TMetaFileClipboardFormat, 1, [csTarget], [ddRead]);
 
finalization
// It is not nescessary to unregister *both* the TClipboardFormats and
// the TTargetFormat, but we do it here to demo how the unregister
// methods are used.
 
// Clipboard format unregistration
TDIBClipboardFormat.UnregisterClipboardFormat;
TBitmapClipboardFormat.UnregisterClipboardFormat;
TPaletteClipboardFormat.UnregisterClipboardFormat;
TEnhMetaFileClipboardFormat.UnregisterClipboardFormat;
TMetaFileClipboardFormat.UnregisterClipboardFormat;
 
// Target format unregistration
TBitmapDataFormat.UnregisterDataFormat;
TMetaFileDataFormat.UnregisterDataFormat;
end.
 
/trunk/VCL_DRAGDROP/DragDropHandler.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDropHandler.pas
0,0 → 1,208
unit DragDropHandler;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite.
// Module: DragDropHandler
// Description: Implements Drop and Drop Context Menu Shell Extenxions
// (a.k.a. drag-and-drop handlers).
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
interface
 
uses
DragDrop,
DragDropComObj,
DragDropContext,
Menus,
ShlObj,
ActiveX,
Windows,
Classes;
 
{$include DragDrop.inc}
 
type
////////////////////////////////////////////////////////////////////////////////
//
// TDragDropHandler
//
////////////////////////////////////////////////////////////////////////////////
// A typical drag-and-drop handler session goes like this:
// 1. User right-drags (drags with the right mouse button) and drops one or more
// source files which has a registered drag-and-drop handler.
// 2. The shell loads the drag-and-drop handler module.
// 3. The shell instantiates the registered drag drop handler object as an
// in-process COM server.
// 4. The IShellExtInit.Initialize method is called with the name of the target
// folder and a data object which contains the dragged data.
// The target folder name is stored in the TDragDropHandler.TargetFolder
// property as a string and in the TargetPIDL property as a PIDL.
// 5. The IContextMenu.QueryContextMenu method is called to populate the popup
// menu.
// TDragDropHandler uses the PopupMenu property to populate the drag-and-drop
// context menu.
// 6. If the user chooses one of the context menu items we have supplied, the
// IContextMenu.InvokeCommand method is called.
// TDragDropHandler locates the corresponding TMenuItem and fires the menu
// items OnClick event.
// 7. The shell unloads the drag-and-drop handler module (usually after a few
// seconds).
////////////////////////////////////////////////////////////////////////////////
TDragDropHandler = class(TDropContextMenu, IShellExtInit, IContextMenu)
private
FFolderPIDL: pItemIDList;
protected
function GetFolder: string;
{ IShellExtInit }
function Initialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult; stdcall;
{ IContextMenu }
function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast,
uFlags: UINT): HResult; stdcall;
function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;
function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
pszName: LPSTR; cchMax: UINT): HResult; stdcall;
public
destructor Destroy; override;
function GetFolderPIDL: pItemIDList; // Caller must free PIDL!
property Folder: string read GetFolder;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDragDropHandlerFactory
//
////////////////////////////////////////////////////////////////////////////////
// COM Class factory for TDragDropHandler.
////////////////////////////////////////////////////////////////////////////////
TDragDropHandlerFactory = class(TDropContextMenuFactory)
protected
function HandlerRegSubKey: string; override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc.
//
////////////////////////////////////////////////////////////////////////////////
 
 
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
implementation
 
uses
DragDropFile,
DragDropPIDL,
Registry,
ComObj,
SysUtils;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
 
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDragDropHandler]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Utilities
//
////////////////////////////////////////////////////////////////////////////////
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDragDropHandler
//
////////////////////////////////////////////////////////////////////////////////
destructor TDragDropHandler.Destroy;
begin
if (FFolderPIDL <> nil) then
ShellMalloc.Free(FFolderPIDL);
inherited Destroy;
end;
 
function TDragDropHandler.GetCommandString(idCmd, uType: UINT;
pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult;
begin
Result := inherited GetCommandString(idCmd, uType, pwReserved, pszName, cchMax);
end;
 
function TDragDropHandler.GetFolder: string;
begin
Result := GetFullPathFromPIDL(FFolderPIDL);
end;
 
function TDragDropHandler.GetFolderPIDL: pItemIDList;
begin
Result := CopyPIDL(FFolderPIDL);
end;
 
function TDragDropHandler.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
begin
Result := E_FAIL;
try
Result := inherited InvokeCommand(lpici);
finally
if (Result <> E_FAIL) then
begin
ShellMalloc.Free(FFolderPIDL);
FFolderPIDL := nil;
end;
end;
end;
 
function TDragDropHandler.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,
idCmdLast, uFlags: UINT): HResult;
begin
Result := inherited QueryContextMenu(Menu, indexMenu, idCmdFirst,
idCmdLast, uFlags);
end;
 
function TDragDropHandler.Initialize(pidlFolder: PItemIDList;
lpdobj: IDataObject; hKeyProgID: HKEY): HResult;
begin
if (pidlFolder <> nil) then
begin
// Copy target folder PIDL.
FFolderPIDL := CopyPIDL(pidlFolder);
Result := inherited Initialize(pidlFolder, lpdobj, hKeyProgID);
end else
Result := E_INVALIDARG;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDragDropHandlerFactory
//
////////////////////////////////////////////////////////////////////////////////
function TDragDropHandlerFactory.HandlerRegSubKey: string;
begin
Result := 'DragDropHandlers';
end;
 
end.
/trunk/VCL_DRAGDROP/DragDropInternet.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDropInternet.pas
0,0 → 1,1269
unit DragDropInternet;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite.
// Module: DragDropInternet
// Description: Implements Dragging and Dropping of internet related data.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
interface
 
uses
DragDrop,
DropTarget,
DropSource,
DragDropFormats,
Windows,
Classes,
ActiveX;
 
type
 
////////////////////////////////////////////////////////////////////////////////
//
// TURLClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Implements support for the 'UniformResourceLocator' format.
////////////////////////////////////////////////////////////////////////////////
 
TURLClipboardFormat = class(TCustomTextClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
property URL: string read GetString write SetString;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TNetscapeBookmarkClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Implements support for the 'Netscape Bookmark' format.
////////////////////////////////////////////////////////////////////////////////
TNetscapeBookmarkClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FURL : string;
FTitle : string;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
public
function GetClipboardFormat: TClipFormat; override;
procedure Clear; override;
property URL: string read FURL write FURL;
property Title: string read FTitle write FTitle;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TNetscapeImageClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Implements support for the 'Netscape Image Format' format.
////////////////////////////////////////////////////////////////////////////////
TNetscapeImageClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FURL : string;
FTitle : string;
FImage : string;
FLowRes : string;
FExtra : string;
FHeight : integer;
FWidth : integer;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
public
function GetClipboardFormat: TClipFormat; override;
procedure Clear; override;
property URL: string read FURL write FURL;
property Title: string read FTitle write FTitle;
property Image: string read FImage write FImage;
property LowRes: string read FLowRes write FLowRes;
property Extra: string read FExtra write FExtra;
property Height: integer read FHeight write FHeight;
property Width: integer read FWidth write FWidth;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TVCardClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Implements support for the '+//ISBN 1-887687-00-9::versit::PDI//vCard'
// (vCard) format.
////////////////////////////////////////////////////////////////////////////////
TVCardClipboardFormat = class(TCustomStringListClipboardFormat)
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
public
function GetClipboardFormat: TClipFormat; override;
property Items: TStrings read GetLines;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// THTMLClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Implements support for the 'HTML Format' format.
////////////////////////////////////////////////////////////////////////////////
THTMLClipboardFormat = class(TCustomStringListClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
function HasData: boolean; override;
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property HTML: TStrings read GetLines;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TRFC822ClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TRFC822ClipboardFormat = class(TCustomStringListClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property Text: TStrings read GetLines;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TURLDataFormat
//
////////////////////////////////////////////////////////////////////////////////
// Renderer for URL formats.
////////////////////////////////////////////////////////////////////////////////
TURLDataFormat = class(TCustomDataFormat)
private
FURL : string;
FTitle : string;
procedure SetTitle(const Value: string);
procedure SetURL(const Value: string);
protected
public
function Assign(Source: TClipboardFormat): boolean; override;
function AssignTo(Dest: TClipboardFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property URL: string read FURL write SetURL;
property Title: string read FTitle write SetTitle;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// THTMLDataFormat
//
////////////////////////////////////////////////////////////////////////////////
// Renderer for HTML text data.
////////////////////////////////////////////////////////////////////////////////
THTMLDataFormat = class(TCustomDataFormat)
private
FHTML: TStrings;
procedure SetHTML(const Value: TStrings);
protected
public
constructor Create(AOwner: TDragDropComponent); override;
destructor Destroy; override;
function Assign(Source: TClipboardFormat): boolean; override;
function AssignTo(Dest: TClipboardFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property HTML: TStrings read FHTML write SetHTML;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TOutlookMailDataFormat
//
////////////////////////////////////////////////////////////////////////////////
// Renderer for Microsoft Outlook email formats.
////////////////////////////////////////////////////////////////////////////////
(*
TOutlookMessage = class;
 
TOutlookAttachments = class(TObject)
public
property Attachments[Index: integer]: TOutlookMessage; default;
property Count: integer;
end;
 
TOutlookMessage = class(TObject)
public
property Text: string;
property Stream: IStream;
property Attachments: TOutlookAttachments;
end;
*)
TOutlookMailDataFormat = class(TCustomDataFormat)
private
FStorages : TStorageInterfaceList;
protected
public
constructor Create(AOwner: TDragDropComponent); override;
destructor Destroy; override;
function Assign(Source: TClipboardFormat): boolean; override;
function AssignTo(Dest: TClipboardFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property Storages: TStorageInterfaceList read FStorages;
// property Streams: TStreamInterfaceList;
// property Messages: TOutlookAttachments;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropURLTarget
//
////////////////////////////////////////////////////////////////////////////////
// URL drop target component.
////////////////////////////////////////////////////////////////////////////////
TDropURLTarget = class(TCustomDropMultiTarget)
private
FURLFormat : TURLDataFormat;
protected
function GetTitle: string;
function GetURL: string;
function GetPreferredDropEffect: LongInt; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property URL: string read GetURL;
property Title: string read GetTitle;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropURLSource
//
////////////////////////////////////////////////////////////////////////////////
// URL drop source component.
////////////////////////////////////////////////////////////////////////////////
TDropURLSource = class(TCustomDropMultiSource)
private
FURLFormat : TURLDataFormat;
procedure SetTitle(const Value: string);
procedure SetURL(const Value: string);
protected
function GetTitle: string;
function GetURL: string;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property URL: string read GetURL write SetURL;
property Title: string read GetTitle write SetTitle;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc.
//
////////////////////////////////////////////////////////////////////////////////
function GetURLFromFile(const Filename: string; var URL: string): boolean;
function GetURLFromStream(Stream: TStream; var URL: string): boolean;
function ConvertURLToFilename(const url: string): string;
 
function IsHTML(const s: string): boolean;
function MakeHTML(const s: string): string;
 
 
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
implementation
 
uses
SysUtils,
ShlObj,
DragDropFile,
DragDropPIDL;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDropURLTarget,
TDropURLSource]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Utilities
//
////////////////////////////////////////////////////////////////////////////////
function GetURLFromFile(const Filename: string; var URL: string): boolean;
var
Stream : TStream;
begin
Stream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
try
Result := GetURLFromStream(Stream, URL);
finally
Stream.Free;
end;
end;
 
function GetURLFromString(const s: string; var URL: string): boolean;
var
Stream : TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
Stream.Size := Length(s);
Move(PChar(s)^, Stream.Memory^, Length(s));
Result := GetURLFromStream(Stream, URL);
finally
Stream.Free;
end;
end;
 
const
// *** DO NOT LOCALIZE ***
InternetShortcut = '[InternetShortcut]';
InternetShortcutExt = '.url';
 
function GetURLFromStream(Stream: TStream; var URL: string): boolean;
var
URLfile : TStringList;
i : integer;
s : string;
p : PChar;
begin
Result := False;
URLfile := TStringList.Create;
try
URLFile.LoadFromStream(Stream);
i := 0;
while (i < URLFile.Count-1) do
begin
if (CompareText(URLFile[i], InternetShortcut) = 0) then
begin
inc(i);
while (i < URLFile.Count) do
begin
s := URLFile[i];
p := PChar(s);
if (StrLIComp(p, 'URL=', length('URL=')) = 0) then
begin
inc(p, length('URL='));
URL := p;
Result := True;
exit;
end else
if (p^ = '[') then
exit;
inc(i);
end;
end;
inc(i);
end;
finally
URLFile.Free;
end;
end;
 
function ConvertURLToFilename(const url: string): string;
const
Invalids : set of char
= ['\', '/', ':', '?', '*', '<', '>', ',', '|', '''', '"'];
var
i: integer;
LastInvalid: boolean;
begin
Result := url;
if (AnsiStrLIComp(PChar(lowercase(Result)), 'http://', 7) = 0) then
delete(Result, 1, 7)
else if (AnsiStrLIComp(PChar(lowercase(Result)), 'ftp://', 6) = 0) then
delete(Result, 1, 6)
else if (AnsiStrLIComp(PChar(lowercase(Result)), 'mailto:', 7) = 0) then
delete(Result, 1, 7)
else if (AnsiStrLIComp(PChar(lowercase(Result)), 'file:', 5) = 0) then
delete(Result, 1, 5);
 
if (length(Result) > 120) then
SetLength(Result, 120);
 
// Truncate at first slash
i := pos('/', Result);
if (i > 0) then
SetLength(Result, i-1);
 
// Replace invalids with spaces.
// If string starts with invalids, they are trimmed.
LastInvalid := True;
for i := length(Result) downto 1 do
if (Result[i] in Invalids) then
begin
if (not LastInvalid) then
begin
Result[i] := ' ';
LastInvalid := True;
end else
// Repeating invalids are trimmed.
Delete(Result, i, 1);
end else
LastInvalid := False;
 
if Result = '' then
Result := 'untitled';
 
Result := Result+InternetShortcutExt;
end;
 
function IsHTML(const s: string): boolean;
begin
Result := (pos('<HTML>', Uppercase(s)) > 0);
end;
 
function MakeHTML(const s: string): string;
begin
{ TODO -oanme -cImprovement : Needs to escape special chars in text to HTML conversion. }
{ TODO -oanme -cImprovement : Needs better text to HTML conversion. }
if (not IsHTML(s)) then
Result := '<HTML>'#13#10'<BODY>'#13#10 + s + #13#10'</BODY>'#13#10'</HTML>'
else
Result := s;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TURLClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_URL: TClipFormat = 0;
 
function TURLClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_URL = 0) then
CF_URL := RegisterClipboardFormat(CFSTR_SHELLURL);
Result := CF_URL;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TNetscapeBookmarkClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_NETSCAPEBOOKMARK: TClipFormat = 0;
 
function TNetscapeBookmarkClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_NETSCAPEBOOKMARK = 0) then
CF_NETSCAPEBOOKMARK := RegisterClipboardFormat('Netscape Bookmark'); // *** DO NOT LOCALIZE ***
Result := CF_NETSCAPEBOOKMARK;
end;
 
function TNetscapeBookmarkClipboardFormat.GetSize: integer;
begin
Result := 0;
if (FURL <> '') then
begin
inc(Result, 1024);
if (FTitle <> '') then
inc(Result, 1024);
end;
end;
 
function TNetscapeBookmarkClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
// Note: No check for missing string terminator!
FURL := PChar(Value);
if (Size > 1024) then
begin
inc(PChar(Value), 1024);
FTitle := PChar(Value);
end;
Result := True;
end;
 
function TNetscapeBookmarkClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
begin
StrLCopy(Value, PChar(FURL), Size);
dec(Size, 1024);
if (Size > 0) and (FTitle <> '') then
begin
inc(PChar(Value), 1024);
StrLCopy(Value, PChar(FTitle), Size);
end;
Result := True;
end;
 
procedure TNetscapeBookmarkClipboardFormat.Clear;
begin
FURL := '';
FTitle := '';
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TNetscapeImageClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_NETSCAPEIMAGE: TClipFormat = 0;
 
function TNetscapeImageClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_NETSCAPEIMAGE = 0) then
CF_NETSCAPEIMAGE := RegisterClipboardFormat('Netscape Image Format');
Result := CF_NETSCAPEIMAGE;
end;
 
type
TNetscapeImageRec = record
Size ,
_Unknown1 ,
Width ,
Height ,
HorMargin ,
VerMargin ,
Border ,
OfsLowRes ,
OfsTitle ,
OfsURL ,
OfsExtra : DWORD
end;
PNetscapeImageRec = ^TNetscapeImageRec;
 
function TNetscapeImageClipboardFormat.GetSize: integer;
begin
Result := SizeOf(TNetscapeImageRec);
inc(Result, Length(FImage)+1);
 
if (FLowRes <> '') then
inc(Result, Length(FLowRes)+1);
if (FTitle <> '') then
inc(Result, Length(FTitle)+1);
if (FUrl <> '') then
inc(Result, Length(FUrl)+1);
if (FExtra <> '') then
inc(Result, Length(FExtra)+1);
end;
 
function TNetscapeImageClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
Result := (Size > SizeOf(TNetscapeImageRec));
if (Result) then
begin
FWidth := PNetscapeImageRec(Value)^.Width;
FHeight := PNetscapeImageRec(Value)^.Height;
FImage := PChar(Value) + SizeOf(TNetscapeImageRec);
if (PNetscapeImageRec(Value)^.OfsLowRes <> 0) then
FLowRes := PChar(Value) + PNetscapeImageRec(Value)^.OfsLowRes;
if (PNetscapeImageRec(Value)^.OfsTitle <> 0) then
FTitle := PChar(Value) + PNetscapeImageRec(Value)^.OfsTitle;
if (PNetscapeImageRec(Value)^.OfsURL <> 0) then
FUrl := PChar(Value) + PNetscapeImageRec(Value)^.OfsUrl;
if (PNetscapeImageRec(Value)^.OfsExtra <> 0) then
FExtra := PChar(Value) + PNetscapeImageRec(Value)^.OfsExtra;
end;
end;
 
function TNetscapeImageClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
var
NetscapeImageRec : PNetscapeImageRec;
begin
Result := (Size > SizeOf(TNetscapeImageRec));
if (Result) then
begin
NetscapeImageRec := PNetscapeImageRec(Value);
NetscapeImageRec^.Width := FWidth;
NetscapeImageRec^.Height := FHeight;
inc(PChar(Value), SizeOf(TNetscapeImageRec));
dec(Size, SizeOf(TNetscapeImageRec));
StrLCopy(Value, PChar(FImage), Size);
dec(Size, Length(FImage)+1);
if (Size <= 0) then
exit;
if (FLowRes <> '') then
begin
StrLCopy(Value, PChar(FLowRes), Size);
NetscapeImageRec^.OfsLowRes := integer(Value) - integer(NetscapeImageRec);
dec(Size, Length(FLowRes)+1);
inc(PChar(Value), Length(FLowRes)+1);
if (Size <= 0) then
exit;
end;
if (FTitle <> '') then
begin
StrLCopy(Value, PChar(FTitle), Size);
NetscapeImageRec^.OfsTitle := integer(Value) - integer(NetscapeImageRec);
dec(Size, Length(FTitle)+1);
inc(PChar(Value), Length(FTitle)+1);
if (Size <= 0) then
exit;
end;
if (FUrl <> '') then
begin
StrLCopy(Value, PChar(FUrl), Size);
NetscapeImageRec^.OfsUrl := integer(Value) - integer(NetscapeImageRec);
dec(Size, Length(FUrl)+1);
inc(PChar(Value), Length(FUrl)+1);
if (Size <= 0) then
exit;
end;
if (FExtra <> '') then
begin
StrLCopy(Value, PChar(FExtra), Size);
NetscapeImageRec^.OfsExtra := integer(Value) - integer(NetscapeImageRec);
dec(Size, Length(FExtra)+1);
inc(PChar(Value), Length(FExtra)+1);
if (Size <= 0) then
exit;
end;
end;
end;
 
procedure TNetscapeImageClipboardFormat.Clear;
begin
FURL := '';
FTitle := '';
FImage := '';
FLowRes := '';
FExtra := '';
FHeight := 0;
FWidth := 0;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TVCardClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_VCARD: TClipFormat = 0;
 
function TVCardClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_VCARD = 0) then
CF_VCARD := RegisterClipboardFormat('+//ISBN 1-887687-00-9::versit::PDI//vCard'); // *** DO NOT LOCALIZE ***
Result := CF_VCARD;
end;
 
function TVCardClipboardFormat.GetSize: integer;
var
i : integer;
begin
if (Items.Count > 0) then
begin
Result := 22; // Length('begin:vcard'+#13+'end:vcard'+#0);
for i := 0 to Items.Count-1 do
inc(Result, Length(Items[i])+1);
end else
Result := 0;
end;
 
function TVCardClipboardFormat.ReadData(Value: pointer; Size: integer): boolean;
var
i : integer;
s : string;
begin
Result := inherited ReadData(Value, Size);
if (Result) then
begin
// Zap vCard header and trailer
if (Items.Count > 0) and (CompareText(Items[0], 'begin:vcard') = 0) then
Items.Delete(0);
if (Items.Count > 0) and (CompareText(Items[Items.Count-1], 'end:vcard') = 0) then
Items.Delete(Items.Count-1);
// Convert to item/value list
for i := 0 to Items.Count-1 do
if (pos(':', Items[i]) > 0) then
begin
s := Items[i];
s[pos(':', Items[i])] := '=';
Items[i] := s;
end;
end;
end;
 
function DOSStringToUnixString(dos: string): string;
var
s, d : PChar;
l : integer;
begin
SetLength(Result, Length(dos)+1);
s := PChar(dos);
d := PChar(Result);
l := 1;
while (s^ <> #0) do
begin
// Ignore LF
if (s^ <> #10) then
begin
d^ := s^;
inc(l);
inc(d);
end;
inc(s);
end;
SetLength(Result, l);
end;
 
function TVCardClipboardFormat.WriteData(Value: pointer; Size: integer): boolean;
var
s : string;
begin
Result := (Items.Count > 0);
if (Result) then
begin
s := DOSStringToUnixString('begin:vcard'+#13+Items.Text+#13+'end:vcard');
StrLCopy(Value, PChar(s), Size);
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// THTMLClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_HTML: TClipFormat = 0;
 
function THTMLClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_HTML = 0) then
CF_HTML := RegisterClipboardFormat('HTML Format');
Result := CF_HTML;
end;
 
function THTMLClipboardFormat.HasData: boolean;
begin
Result := inherited HasData and IsHTML(HTML.Text);
end;
 
function THTMLClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
Result := True;
if (Source is TTextDataFormat) then
HTML.Text := MakeHTML(TTextDataFormat(Source).Text)
else
Result := inherited Assign(Source);
end;
 
function THTMLClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
Result := True;
if (Dest is TTextDataFormat) then
TTextDataFormat(Dest).Text := HTML.Text
else
Result := inherited AssignTo(Dest);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TRFC822ClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_RFC822: TClipFormat = 0;
 
function TRFC822ClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_RFC822 = 0) then
CF_RFC822 := RegisterClipboardFormat('Internet Message (rfc822/rfc1522)'); // *** DO NOT LOCALIZE ***
Result := CF_RFC822;
end;
 
function TRFC822ClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
Result := True;
if (Source is TTextDataFormat) then
Text.Text := TTextDataFormat(Source).Text
else
Result := inherited Assign(Source);
end;
 
function TRFC822ClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
Result := True;
if (Dest is TTextDataFormat) then
TTextDataFormat(Dest).Text := Text.Text
else
Result := inherited AssignTo(Dest);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TURLDataFormat
//
////////////////////////////////////////////////////////////////////////////////
function TURLDataFormat.Assign(Source: TClipboardFormat): boolean;
var
s : string;
begin
Result := False;
(*
** TURLClipboardFormat
*)
if (Source is TURLClipboardFormat) then
begin
if (FURL = '') then
FURL := TURLClipboardFormat(Source).URL;
Result := True;
end else
(*
** TTextClipboardFormat
*)
if (Source is TTextClipboardFormat) then
begin
if (FURL = '') then
begin
s := TTextClipboardFormat(Source).Text;
// Convert from text if the string looks like an URL
if (pos('://', s) > 1) then
begin
FURL := s;
Result := True;
end;
end;
end else
(*
** TFileClipboardFormat
*)
if (Source is TFileClipboardFormat) then
begin
if (FURL = '') then
begin
s := TFileClipboardFormat(Source).Files[0];
// Convert from Internet Shortcut file format.
if (CompareText(ExtractFileExt(s), InternetShortcutExt) = 0) and
(GetURLFromFile(s, FURL)) then
begin
if (FTitle = '') then
FTitle := ChangeFileExt(ExtractFileName(s), '');
Result := True;
end;
end;
end else
(*
** TFileContentsClipboardFormat
*)
if (Source is TFileContentsClipboardFormat) then
begin
if (FURL = '') then
begin
s := TFileContentsClipboardFormat(Source).Data;
Result := GetURLFromString(s, FURL);
end;
end else
(*
** TFileGroupDescritorClipboardFormat
*)
if (Source is TFileGroupDescritorClipboardFormat) then
begin
if (FTitle = '') then
begin
if (TFileGroupDescritorClipboardFormat(Source).FileGroupDescriptor^.cItems > 0) then
begin
// Extract the title of an Internet Shortcut
s := TFileGroupDescritorClipboardFormat(Source).FileGroupDescriptor^.fgd[0].cFileName;
if (CompareText(ExtractFileExt(s), InternetShortcutExt) = 0) then
begin
FTitle := ChangeFileExt(s, '');
Result := True;
end;
end;
end;
end else
(*
** TNetscapeBookmarkClipboardFormat
*)
if (Source is TNetscapeBookmarkClipboardFormat) then
begin
if (FURL = '') then
FURL := TNetscapeBookmarkClipboardFormat(Source).URL;
if (FTitle = '') then
FTitle := TNetscapeBookmarkClipboardFormat(Source).Title;
Result := True;
end else
(*
** TNetscapeImageClipboardFormat
*)
if (Source is TNetscapeImageClipboardFormat) then
begin
if (FURL = '') then
FURL := TNetscapeImageClipboardFormat(Source).URL;
if (FTitle = '') then
FTitle := TNetscapeImageClipboardFormat(Source).Title;
Result := True;
end else
Result := inherited Assign(Source);
end;
 
function TURLDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
var
FGD : TFileGroupDescriptor;
s : string;
begin
Result := True;
(*
** TURLClipboardFormat
*)
if (Dest is TURLClipboardFormat) then
begin
TURLClipboardFormat(Dest).URL := FURL;
end else
(*
** TTextClipboardFormat
*)
if (Dest is TTextClipboardFormat) then
begin
TTextClipboardFormat(Dest).Text := FURL;
end else
(*
** TFileContentsClipboardFormat
*)
if (Dest is TFileContentsClipboardFormat) then
begin
TFileContentsClipboardFormat(Dest).Data := InternetShortcut + #13#10 +
'URL='+FURL + #13#10;
end else
(*
** TFileGroupDescritorClipboardFormat
*)
if (Dest is TFileGroupDescritorClipboardFormat) then
begin
FillChar(FGD, SizeOf(FGD), 0);
FGD.cItems := 1;
if (FTitle = '') then
s := FURL
else
s := FTitle;
StrLCopy(@FGD.fgd[0].cFileName[0], PChar(ConvertURLToFilename(s)),
SizeOf(FGD.fgd[0].cFileName));
FGD.fgd[0].dwFlags := FD_LINKUI;
TFileGroupDescritorClipboardFormat(Dest).CopyFrom(@FGD);
end else
(*
** TNetscapeBookmarkClipboardFormat
*)
if (Dest is TNetscapeBookmarkClipboardFormat) then
begin
TNetscapeBookmarkClipboardFormat(Dest).URL := FURL;
TNetscapeBookmarkClipboardFormat(Dest).Title := FTitle;
end else
(*
** TNetscapeImageClipboardFormat
*)
if (Dest is TNetscapeImageClipboardFormat) then
begin
TNetscapeImageClipboardFormat(Dest).URL := FURL;
TNetscapeImageClipboardFormat(Dest).Title := FTitle;
end else
Result := inherited AssignTo(Dest);
end;
 
procedure TURLDataFormat.Clear;
begin
Changing;
FURL := '';
FTitle := '';
end;
 
procedure TURLDataFormat.SetTitle(const Value: string);
begin
Changing;
FTitle := Value;
end;
 
procedure TURLDataFormat.SetURL(const Value: string);
begin
Changing;
FURL := Value;
end;
 
function TURLDataFormat.HasData: boolean;
begin
Result := (FURL <> '') or (FTitle <> '');
end;
 
function TURLDataFormat.NeedsData: boolean;
begin
Result := (FURL = '') or (FTitle = '');
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// THTMLDataFormat
//
////////////////////////////////////////////////////////////////////////////////
function THTMLDataFormat.Assign(Source: TClipboardFormat): boolean;
begin
Result := True;
 
if (Source is THTMLClipboardFormat) then
FHTML.Assign(THTMLClipboardFormat(Source).HTML)
 
else
Result := inherited Assign(Source);
end;
 
function THTMLDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
begin
Result := True;
 
if (Dest is THTMLClipboardFormat) then
THTMLClipboardFormat(Dest).HTML.Assign(FHTML)
 
else
Result := inherited AssignTo(Dest);
end;
 
procedure THTMLDataFormat.Clear;
begin
Changing;
FHTML.Clear;
end;
 
constructor THTMLDataFormat.Create(AOwner: TDragDropComponent);
begin
inherited Create(AOwner);
FHTML := TStringList.Create;
end;
 
destructor THTMLDataFormat.Destroy;
begin
FHTML.Free;
inherited Destroy;
end;
 
function THTMLDataFormat.HasData: boolean;
begin
Result := (FHTML.Count > 0);
end;
 
function THTMLDataFormat.NeedsData: boolean;
begin
Result := (FHTML.Count = 0);
end;
 
procedure THTMLDataFormat.SetHTML(const Value: TStrings);
begin
FHTML.Assign(Value);
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TOutlookMailDataFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TOutlookMailDataFormat.Create(AOwner: TDragDropComponent);
begin
inherited Create(AOwner);
FStorages := TStorageInterfaceList.Create;
FStorages.OnChanging := DoOnChanging;
end;
 
destructor TOutlookMailDataFormat.Destroy;
begin
Clear;
FStorages.Free;
inherited Destroy;
end;
 
procedure TOutlookMailDataFormat.Clear;
begin
Changing;
FStorages.Clear;
end;
 
function TOutlookMailDataFormat.Assign(Source: TClipboardFormat): boolean;
begin
Result := True;
 
if (Source is TFileContentsStorageClipboardFormat) then
FStorages.Assign(TFileContentsStorageClipboardFormat(Source).Storages)
 
else
Result := inherited Assign(Source);
end;
 
function TOutlookMailDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
begin
Result := True;
 
if (Dest is TFileContentsStorageClipboardFormat) then
TFileContentsStorageClipboardFormat(Dest).Storages.Assign(FStorages)
 
else
Result := inherited AssignTo(Dest);
end;
 
function TOutlookMailDataFormat.HasData: boolean;
begin
Result := (FStorages.Count > 0);
end;
 
function TOutlookMailDataFormat.NeedsData: boolean;
begin
Result := (FStorages.Count = 0);
end;
 
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropURLTarget
//
////////////////////////////////////////////////////////////////////////////////
 
constructor TDropURLTarget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
DragTypes := [dtCopy, dtLink];
GetDataOnEnter := True;
 
FURLFormat := TURLDataFormat.Create(Self);
end;
 
destructor TDropURLTarget.Destroy;
begin
FURLFormat.Free;
inherited Destroy;
end;
 
function TDropURLTarget.GetTitle: string;
begin
Result := FURLFormat.Title;
end;
 
function TDropURLTarget.GetURL: string;
begin
Result := FURLFormat.URL;
end;
 
function TDropURLTarget.GetPreferredDropEffect: LongInt;
begin
Result := GetPreferredDropEffect;
if (Result = DROPEFFECT_NONE) then
Result := DROPEFFECT_LINK;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropURLSource
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropURLSource.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
DragTypes := [dtCopy, dtLink];
PreferredDropEffect := DROPEFFECT_LINK;
 
FURLFormat := TURLDataFormat.Create(Self);
end;
 
destructor TDropURLSource.Destroy;
begin
FURLFormat.Free;
inherited Destroy;
end;
 
function TDropURLSource.GetTitle: string;
begin
Result := FURLFormat.Title;
end;
 
procedure TDropURLSource.SetTitle(const Value: string);
begin
FURLFormat.Title := Value;
end;
 
function TDropURLSource.GetURL: string;
begin
Result := FURLFormat.URL;
end;
 
procedure TDropURLSource.SetURL(const Value: string);
begin
FURLFormat.URL := Value;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Initialization/Finalization
//
////////////////////////////////////////////////////////////////////////////////
initialization
// Data format registration
TURLDataFormat.RegisterDataFormat;
THTMLDataFormat.RegisterDataFormat;
// Clipboard format registration
TURLDataFormat.RegisterCompatibleFormat(TNetscapeBookmarkClipboardFormat, 0, csSourceTarget, [ddRead]);
TURLDataFormat.RegisterCompatibleFormat(TNetscapeImageClipboardFormat, 1, csSourceTarget, [ddRead]);
TURLDataFormat.RegisterCompatibleFormat(TFileContentsClipboardFormat, 2, csSourceTarget, [ddRead]);
TURLDataFormat.RegisterCompatibleFormat(TFileGroupDescritorClipboardFormat, 2, csSourceTarget, [ddRead]);
TURLDataFormat.RegisterCompatibleFormat(TURLClipboardFormat, 2, csSourceTarget, [ddRead]);
TURLDataFormat.RegisterCompatibleFormat(TTextClipboardFormat, 3, csSourceTarget, [ddRead]);
TURLDataFormat.RegisterCompatibleFormat(TFileClipboardFormat, 4, [csTarget], [ddRead]);
 
THTMLDataFormat.RegisterCompatibleFormat(THTMLClipboardFormat, 0, csSourceTarget, [ddRead]);
 
TTextDataFormat.RegisterCompatibleFormat(TRFC822ClipboardFormat, 1, csSourceTarget, [ddRead]);
TTextDataFormat.RegisterCompatibleFormat(THTMLClipboardFormat, 2, csSourceTarget, [ddRead]);
 
finalization
// Clipboard format unregistration
TNetscapeBookmarkClipboardFormat.UnregisterClipboardFormat;
TNetscapeImageClipboardFormat.UnregisterClipboardFormat;
TURLClipboardFormat.UnregisterClipboardFormat;
TVCardClipboardFormat.UnregisterClipboardFormat;
THTMLClipboardFormat.UnregisterClipboardFormat;
TRFC822ClipboardFormat.UnregisterClipboardFormat;
 
// Target format unregistration
TURLDataFormat.UnregisterDataFormat;
end.
 
/trunk/VCL_DRAGDROP/DragDropPIDL.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDropPIDL.pas
0,0 → 1,1029
unit DragDropPIDL;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Module: DragDropPIDL
// Description: Implements Dragging & Dropping of PIDLs (files and folders).
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
interface
 
uses
DragDrop,
DropTarget,
DropSource,
DragDropFormats,
DragDropFile,
Windows,
ActiveX,
Classes,
ShlObj;
 
{$include DragDrop.inc}
 
type
////////////////////////////////////////////////////////////////////////////////
//
// TPIDLClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
// Supports the 'Shell IDList Array' format.
////////////////////////////////////////////////////////////////////////////////
TPIDLClipboardFormat = class(TCustomSimpleClipboardFormat)
private
FPIDLs: TStrings; // Used internally to store PIDLs. We use strings to simplify cleanup.
FFilenames: TStrings;
protected
function ReadData(Value: pointer; Size: integer): boolean; override;
function WriteData(Value: pointer; Size: integer): boolean; override;
function GetSize: integer; override;
public
constructor Create; override;
destructor Destroy; override;
function GetClipboardFormat: TClipFormat; override;
procedure Clear; override;
function HasData: boolean; override;
property PIDLs: TStrings read FPIDLs;
property Filenames: TStrings read FFilenames;
end;
 
 
type
////////////////////////////////////////////////////////////////////////////////
//
// TPIDLDataFormat
//
////////////////////////////////////////////////////////////////////////////////
TPIDLDataFormat = class(TCustomDataFormat)
private
FPIDLs : TStrings;
FFilenames : TStrings;
protected
public
constructor Create(AOwner: TDragDropComponent); override;
destructor Destroy; override;
function Assign(Source: TClipboardFormat): boolean; override;
function AssignTo(Dest: TClipboardFormat): boolean; override;
procedure Clear; override;
function HasData: boolean; override;
function NeedsData: boolean; override;
property PIDLs: TStrings read FPIDLs;
property Filenames: TStrings read FFilenames;
end;
 
 
type
////////////////////////////////////////////////////////////////////////////////
//
// TDropPIDLTarget
//
////////////////////////////////////////////////////////////////////////////////
TDropPIDLTarget = class(TCustomDropMultiTarget)
private
FPIDLDataFormat : TPIDLDataFormat;
FFileMapDataFormat : TFileMapDataFormat;
function GetFilenames: TStrings;
protected
function GetPIDLs: TStrings;
function GetPIDLCount: integer;
function GetMappedNames: TStrings;
property PIDLs: TStrings read GetPIDLs;
function DoGetPIDL(Index: integer): pItemIdList;
function GetPreferredDropEffect: LongInt; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; Override;
 
// Note: It is the callers responsibility to cleanup
// the returned PIDLs from the following 3 methods:
// - GetFolderPidl
// - GetRelativeFilePidl
// - GetAbsoluteFilePidl
// Use the CoTaskMemFree procedure to free the PIDLs.
function GetFolderPIDL: pItemIdList;
function GetRelativeFilePIDL(Index: integer): pItemIdList;
function GetAbsoluteFilePIDL(Index: integer): pItemIdList;
property PIDLCount: integer read GetPIDLCount; // Includes folder pidl in count
 
// If you just want the filenames (not PIDLs) then use ...
property Filenames: TStrings read GetFilenames;
// MappedNames is only needed if files need to be renamed after a drag or
// e.g. dragging from 'Recycle Bin'.
property MappedNames: TStrings read GetMappedNames;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropPIDLSource
//
////////////////////////////////////////////////////////////////////////////////
TDropPIDLSource = class(TCustomDropMultiSource)
private
FPIDLDataFormat : TPIDLDataFormat;
FFileMapDataFormat : TFileMapDataFormat;
protected
function GetMappedNames: TStrings;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure CopyFolderPIDLToList(pidl: PItemIDList);
procedure CopyFilePIDLToList(pidl: PItemIDList);
property MappedNames: TStrings read GetMappedNames;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// PIDL utility functions
//
////////////////////////////////////////////////////////////////////////////////
 
//: GetPIDLsFromData extracts a PIDL list from a memory block and stores the
// PIDLs in a string list.
function GetPIDLsFromData(Data: pointer; Size: integer; PIDLs: TStrings): boolean;
 
//: GetPIDLsFromHGlobal extracts a PIDL list from a global memory block and
// stores the PIDLs in a string list.
function GetPIDLsFromHGlobal(const HGlob: HGlobal; PIDLs: TStrings): boolean;
 
//: GetPIDLsFromFilenames converts a list of files to PIDLs and stores the
// PIDLs in a string list. All the PIDLs are relative to a common root.
function GetPIDLsFromFilenames(const Files: TStrings; PIDLs: TStrings): boolean;
 
//: GetRootFolderPIDL finds the PIDL of the folder which is the parent of a list
// of files. The PIDl is returned as a string. If the files do not share a
// common root, an empty string is returnde.
function GetRootFolderPIDL(const Files: TStrings): string;
 
//: GetFullPIDLFromPath converts a path (filename and path) to a folder/filename
// PIDL pair.
function GetFullPIDLFromPath(Path: string): pItemIDList;
 
//: GetFullPathFromPIDL converts a folder/filename PIDL pair to a full path.
function GetFullPathFromPIDL(PIDL: pItemIDList): string;
 
//: PIDLToString converts a single PIDL to a string.
function PIDLToString(pidl: PItemIDList): string;
 
//: StringToPIDL converts a PIDL string to a PIDL.
function StringToPIDL(const PIDL: string): PItemIDList;
 
//: JoinPIDLStrings merges two PIDL strings into one.
function JoinPIDLStrings(pidl1, pidl2: string): string;
 
//: ConvertFilesToShellIDList converts a list of files to a PIDL list. The
// files are relative to the folder specified by the Path parameter. The PIDLs
// are returned as a global memory handle.
function ConvertFilesToShellIDList(Path: string; Files: TStrings): HGlobal;
 
//: GetSizeOfPIDL calculates the size of a PIDL list.
function GetSizeOfPIDL(PIDL: pItemIDList): integer;
 
//: CopyPIDL makes a copy of a PIDL.
// It is the callers responsibility to free the returned PIDL.
function CopyPIDL(PIDL: pItemIDList): pItemIDList;
 
{$ifndef BCB}
// Undocumented PIDL utility functions...
// From http://www.geocities.com/SiliconValley/4942/
function ILCombine(pidl1,pidl2:PItemIDList): PItemIDList; stdcall;
function ILFindLastID(pidl: PItemIDList): PItemIDList; stdcall;
function ILClone(pidl: PItemIDList): PItemIDList; stdcall;
function ILRemoveLastID(pidl: PItemIDList): LongBool; stdcall;
function ILIsEqual(pidl1,pidl2: PItemIDList): LongBool; stdcall;
procedure ILFree(Buffer: PItemIDList); stdcall;
 
// Undocumented IMalloc utility functions...
function SHAlloc(BufferSize: ULONG): Pointer; stdcall;
procedure SHFree(Buffer: Pointer); stdcall;
{$endif}
 
////////////////////////////////////////////////////////////////////////////////
//
// PIDL/IShellFolder utility functions
//
////////////////////////////////////////////////////////////////////////////////
 
//: GetShellFolderOfPath retrieves an IShellFolder interface which can be used
// to manage the specified folder.
function GetShellFolderOfPath(FolderPath: string): IShellFolder;
 
//: GetPIDLDisplayName retrieves the display name of the specified PIDL,
// relative to the specified folder.
function GetPIDLDisplayName(Folder: IShellFolder; PIDL: PItemIdList): string;
 
//: GetSubPIDL retrieves the PIDL of the specified file or folder to a PIDL.
// The PIDL is relative to the folder specified by the Folder parameter.
function GetSubPIDL(Folder: IShellFolder; Sub: string): pItemIDList;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
implementation
 
uses
ShellAPI,
SysUtils;
 
resourcestring
sNoFolderPIDL = 'Folder PIDL must be added first';
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDropPIDLTarget,
TDropPIDLSource]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// PIDL utility functions
//
////////////////////////////////////////////////////////////////////////////////
function GetPIDLsFromData(Data: pointer; Size: integer; PIDLs: TStrings): boolean;
var
i : integer;
pOffset : ^UINT;
PIDL : PItemIDList;
begin
PIDLs.Clear;
 
Result := (Data <> nil) and
(Size >= integer(PIDA(Data)^.cidl) * (SizeOf(UINT)+SizeOf(PItemIDList)) + SizeOf(UINT));
if (not Result) then
exit;
 
pOffset := @(PIDA(Data)^.aoffset[0]);
i := PIDA(Data)^.cidl; // Note: Count doesn't include folder PIDL
while (i >= 0) do
begin
PIDL := PItemIDList(UINT(Data)+ pOffset^);
PIDLs.Add(PIDLToString(PIDL));
inc(pOffset);
dec(i);
end;
Result := (PIDLs.Count > 1);
end;
 
function GetPIDLsFromHGlobal(const HGlob: HGlobal; PIDLs: TStrings): boolean;
var
pCIDA : PIDA;
begin
pCIDA := PIDA(GlobalLock(HGlob));
try
Result := GetPIDLsFromData(pCIDA, GlobalSize(HGlob), PIDLs);
finally
GlobalUnlock(HGlob);
end;
end;
 
resourcestring
sBadDesktop = 'Failed to get interface to Desktop';
sBadFilename = 'Invalid filename: %s';
 
(*
** Find the folder which is the parent of all the files in a list.
*)
function GetRootFolderPIDL(const Files: TStrings): string;
var
DeskTopFolder: IShellFolder;
WidePath: WideString;
PIDL: pItemIDList;
PIDLs: TStrings;
s: string;
PIDL1, PIDL2: pItemIDList;
Size, MaxSize: integer;
i: integer;
begin
Result := '';
if (Files.Count = 0) then
exit;
 
if (SHGetDesktopFolder(DeskTopFolder) <> NOERROR) then
raise Exception.Create(sBadDesktop);
 
PIDLs := TStringList.Create;
try
// First convert all paths to PIDLs.
for i := 0 to Files.Count-1 do
begin
WidePath := ExtractFilePath(Files[i]);
if (DesktopFolder.ParseDisplayName(0, nil, PWideChar(WidePath), PULONG(nil)^,
PIDL, PULONG(nil)^) <> NOERROR) then
raise Exception.Create(sBadFilename);
try
PIDLs.Add(PIDLToString(PIDL));
finally
coTaskMemFree(PIDL);
end;
end;
 
Result := PIDLs[0];
MaxSize := Length(Result)-SizeOf(Word);
PIDL := pItemIDList(PChar(Result));
for i := 1 to PIDLs.Count-1 do
begin
s := PIDLs[1];
PIDL1 := PIDL;
PIDL2 := pItemIDList(PChar(s));
Size := 0;
while (Size < MaxSize) and (PIDL1^.mkid.cb <> 0) and (PIDL1^.mkid.cb = PIDL2^.mkid.cb) and (CompareMem(PIDL1, PIDL2, PIDL1^.mkid.cb)) do
begin
inc(Size, PIDL1^.mkid.cb);
inc(integer(PIDL2), PIDL1^.mkid.cb);
inc(integer(PIDL1), PIDL1^.mkid.cb);
end;
if (Size <> MaxSize) then
begin
MaxSize := Size;
SetLength(Result, Size+SizeOf(Word));
PIDL1^.mkid.cb := 0;
end;
if (Size = 0) then
break;
end;
finally
PIDLs.Free;
end;
end;
 
function GetPIDLsFromFilenames(const Files: TStrings; PIDLs: TStrings): boolean;
var
RootPIDL: string;
i: integer;
PIDL: pItemIdList;
FilePIDL: string;
begin
Result := False;
PIDLs.Clear;
if (Files.Count = 0) then
exit;
 
// Get the PIDL of the root folder...
// All the file PIDLs will be relative to this PIDL
RootPIDL := GetRootFolderPIDL(Files);
if (RootPIDL = '') then
exit;
 
Result := True;
 
PIDLS.Add(RootPIDL);
// Add the file PIDLs (all relative to the root)...
for i := 0 to Files.Count-1 do
begin
PIDL := GetFullPIDLFromPath(Files[i]);
if (PIDL = nil) then
begin
Result := False;
PIDLs.Clear;
break;
end;
try
FilePIDL := PIDLToString(PIDL);
finally
coTaskMemFree(PIDL);
end;
// Remove the root PIDL from the file PIDL making it relative to the root.
PIDLS.Add(copy(FilePIDL, Length(RootPIDL)-SizeOf(Word)+1,
Length(FilePIDL)-(Length(RootPIDL)-SizeOf(Word))));
end;
end;
 
function GetSizeOfPIDL(PIDL: pItemIDList): integer;
var
Size: integer;
begin
if (PIDL <> nil) then
begin
Result := SizeOf(PIDL^.mkid.cb);
repeat
Size := PIDL^.mkid.cb;
inc(Result, Size);
inc(integer(PIDL), Size);
until (Size = 0);
end else
Result := 0;
end;
 
function CopyPIDL(PIDL: pItemIDList): pItemIDList;
var
Size: integer;
begin
Size := GetSizeOfPIDL(PIDL);
if (Size > 0) then
begin
Result := ShellMalloc.Alloc(Size);
if (Result <> nil) then
Move(PIDL^, Result^, Size);
end else
Result := nil;
end;
 
function GetFullPIDLFromPath(Path: string): pItemIDList;
var
DeskTopFolder : IShellFolder;
WidePath : WideString;
begin
WidePath := Path;
if (SHGetDesktopFolder(DeskTopFolder) = NOERROR) then
begin
if (DesktopFolder.ParseDisplayName(0, nil, PWideChar(WidePath), PULONG(nil)^,
Result, PULONG(nil)^) <> NOERROR) then
Result := nil;
end else
Result := nil;
end;
 
function GetFullPathFromPIDL(PIDL: pItemIDList): string;
var
Path: array[0..MAX_PATH] of char;
begin
if SHGetPathFromIDList(PIDL, Path) then
Result := Path
else
Result := '';
end;
 
// See "Clipboard Formats for Shell Data Transfers" in Ole.hlp...
// (Needed to drag links (shortcuts).)
type
POffsets = ^TOffsets;
TOffsets = array[0..$FFFF] of UINT;
 
function ConvertFilesToShellIDList(Path: string; Files: TStrings): HGlobal;
var
shf: IShellFolder;
PathPidl, pidl: pItemIDList;
Ida: PIDA;
pOffset: POffsets;
ptrByte: ^Byte;
i, PathPidlSize, IdaSize, PreviousPidlSize: integer;
begin
Result := 0;
shf := GetShellFolderOfPath(path);
if shf = nil then
exit;
// Calculate size of IDA structure ...
// cidl: UINT ; Directory pidl
// offset: UINT ; all file pidl offsets
IdaSize := (Files.Count + 2) * SizeOf(UINT);
 
PathPidl := GetFullPIDLFromPath(path);
if PathPidl = nil then
exit;
try
PathPidlSize := GetSizeOfPidl(PathPidl);
 
//Add to IdaSize space for ALL pidls...
IdaSize := IdaSize + PathPidlSize;
for i := 0 to Files.Count-1 do
begin
pidl := GetSubPidl(shf, files[i]);
try
IdaSize := IdaSize + GetSizeOfPidl(Pidl);
finally
ShellMalloc.Free(pidl);
end;
end;
 
//Allocate memory...
Result := GlobalAlloc(GMEM_SHARE or GMEM_ZEROINIT, IdaSize);
if (Result = 0) then
exit;
try
Ida := GlobalLock(Result);
try
FillChar(Ida^, IdaSize, 0);
 
//Fill in offset and pidl data...
Ida^.cidl := Files.Count; //cidl = file count
pOffset := POffsets(@(Ida^.aoffset));
pOffset^[0] := (Files.Count+2) * sizeof(UINT); //offset of Path pidl
 
ptrByte := pointer(Ida);
inc(ptrByte, pOffset^[0]); //ptrByte now points to Path pidl
Move(PathPidl^, ptrByte^, PathPidlSize); //copy path pidl
 
PreviousPidlSize := PathPidlSize;
for i := 1 to Files.Count do
begin
pidl := GetSubPidl(shf,files[i-1]);
try
pOffset^[i] := pOffset^[i-1] + UINT(PreviousPidlSize); //offset of pidl
PreviousPidlSize := GetSizeOfPidl(Pidl);
 
ptrByte := pointer(Ida);
inc(ptrByte, pOffset^[i]); //ptrByte now points to current file pidl
Move(Pidl^, ptrByte^, PreviousPidlSize); //copy file pidl
//PreviousPidlSize = current pidl size here
finally
ShellMalloc.Free(pidl);
end;
end;
finally
GlobalUnLock(Result);
end;
except
GlobalFree(Result);
raise;
end;
finally
ShellMalloc.Free(PathPidl);
end;
end;
 
function PIDLToString(pidl: PItemIDList): String;
var
PidlLength : integer;
begin
PidlLength := GetSizeOfPidl(pidl);
SetLength(Result, PidlLength);
Move(pidl^, PChar(Result)^, PidlLength);
end;
 
function StringToPIDL(const PIDL: string): PItemIDList;
begin
Result := ShellMalloc.Alloc(Length(PIDL));
if (Result <> nil) then
Move(PChar(PIDL)^, Result^, Length(PIDL));
end;
 
function JoinPIDLStrings(pidl1, pidl2: string): String;
var
PidlLength : integer;
begin
if Length(pidl1) <= 2 then
PidlLength := 0
else
PidlLength := Length(pidl1)-2;
SetLength(Result, PidlLength + Length(pidl2));
if PidlLength > 0 then
Move(PChar(pidl1)^, PChar(Result)^, PidlLength);
Move(PChar(pidl2)^, Result[PidlLength+1], Length(pidl2));
end;
 
{$ifndef BCB}
// BCB appearantly doesn't support ordinal DLL imports. Strange!
function ILCombine(pidl1,pidl2:PItemIDList): PItemIDList; stdcall;
external shell32 index 25;
function ILFindLastID(pidl: PItemIDList): PItemIDList; stdcall;
external shell32 index 16;
function ILClone(pidl: PItemIDList): PItemIDList; stdcall;
external shell32 index 18;
function ILRemoveLastID(pidl: PItemIDList): LongBool; stdcall;
external shell32 index 17;
function ILIsEqual(pidl1,pidl2: PItemIDList): LongBool; stdcall;
external shell32 index 21;
procedure ILFree(Buffer: PItemIDList); stdcall;
external shell32 index 155;
 
function SHAlloc(BufferSize: ULONG): Pointer; stdcall;
external shell32 index 196;
procedure SHFree(Buffer: Pointer); stdcall;
external shell32 index 195;
{$endif}
 
////////////////////////////////////////////////////////////////////////////////
//
// PIDL/IShellFolder utility functions
//
////////////////////////////////////////////////////////////////////////////////
function GetShellFolderOfPath(FolderPath: string): IShellFolder;
var
DeskTopFolder: IShellFolder;
PathPidl: pItemIDList;
WidePath: WideString;
pdwAttributes: ULONG;
begin
Result := nil;
WidePath := FolderPath;
pdwAttributes := SFGAO_FOLDER;
if (SHGetDesktopFolder(DeskTopFolder) <> NOERROR) then
exit;
if (DesktopFolder.ParseDisplayName(0, nil, PWideChar(WidePath), PULONG(nil)^,
PathPidl, pdwAttributes) = NOERROR) then
try
if (pdwAttributes and SFGAO_FOLDER <> 0) then
DesktopFolder.BindToObject(PathPidl, nil, IID_IShellFolder,
// Note: For Delphi 4 and prior, the ppvOut parameter must be a pointer.
pointer(Result));
finally
ShellMalloc.Free(PathPidl);
end;
end;
 
function GetSubPIDL(Folder: IShellFolder; Sub: string): pItemIDList;
var
WidePath: WideString;
begin
WidePath := Sub;
Folder.ParseDisplayName(0, nil, PWideChar(WidePath), PULONG(nil)^, Result,
PULONG(nil)^);
end;
 
function GetPIDLDisplayName(Folder: IShellFolder; PIDL: PItemIdList): string;
var
StrRet: TStrRet;
begin
Result := '';
Folder.GetDisplayNameOf(PIDL, 0, StrRet);
case StrRet.uType of
STRRET_WSTR: Result := WideCharToString(StrRet.pOleStr);
STRRET_OFFSET: Result := PChar(UINT(PIDL)+StrRet.uOffset);
STRRET_CSTR: Result := StrRet.cStr;
end;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TPIDLsToFilenamesStrings
//
////////////////////////////////////////////////////////////////////////////////
// Used internally to convert PIDLs to filenames on-demand.
////////////////////////////////////////////////////////////////////////////////
type
TPIDLsToFilenamesStrings = class(TStrings)
private
FPIDLs: TStrings;
protected
function Get(Index: Integer): string; override;
function GetCount: Integer; override;
procedure Put(Index: Integer; const S: string); override;
procedure PutObject(Index: Integer; AObject: TObject); override;
public
constructor Create(APIDLs: TStrings);
procedure Clear; override;
procedure Delete(Index: Integer); override;
procedure Insert(Index: Integer; const S: string); override;
procedure Assign(Source: TPersistent); override;
end;
 
constructor TPIDLsToFilenamesStrings.Create(APIDLs: TStrings);
begin
inherited Create;
FPIDLs := APIDLs;
end;
 
function TPIDLsToFilenamesStrings.Get(Index: Integer): string;
var
PIDL: string;
Path: array [0..MAX_PATH] of char;
begin
if (Index < 0) or (Index > FPIDLs.Count-2) then
raise Exception.create('Filename index out of range');
PIDL := JoinPIDLStrings(FPIDLs[0], FPIDLs[Index+1]);
if SHGetPathFromIDList(PItemIDList(PChar(PIDL)), Path) then
Result := Path
else
Result := '';
end;
 
function TPIDLsToFilenamesStrings.GetCount: Integer;
begin
if FPIDLs.Count < 2 then
Result := 0
else
Result := FPIDLs.Count-1;
end;
 
procedure TPIDLsToFilenamesStrings.Assign(Source: TPersistent);
begin
if Source is TStrings then
begin
BeginUpdate;
try
GetPIDLsFromFilenames(TStrings(Source), FPIDLs);
finally
EndUpdate;
end;
end else
inherited Assign(Source);
end;
 
// Inherited abstract methods which do not need implementation...
procedure TPIDLsToFilenamesStrings.Put(Index: Integer; const S: string);
begin
end;
 
procedure TPIDLsToFilenamesStrings.PutObject(Index: Integer; AObject: TObject);
begin
end;
 
procedure TPIDLsToFilenamesStrings.Clear;
begin
end;
 
procedure TPIDLsToFilenamesStrings.Delete(Index: Integer);
begin
end;
 
procedure TPIDLsToFilenamesStrings.Insert(Index: Integer; const S: string);
begin
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TPIDLClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TPIDLClipboardFormat.Create;
begin
inherited Create;
FPIDLs := TStringList.Create;
FFilenames := TPIDLsToFilenamesStrings.Create(FPIDLs);
end;
 
destructor TPIDLClipboardFormat.Destroy;
begin
FFilenames.Free;
FPIDLs.Free;
inherited Destroy;
end;
 
var
CF_IDLIST: TClipFormat = 0;
 
function TPIDLClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_IDLIST = 0) then
CF_IDLIST := RegisterClipboardFormat(CFSTR_SHELLIDLIST);
Result := CF_IDLIST;
end;
 
procedure TPIDLClipboardFormat.Clear;
begin
FPIDLs.Clear;
end;
 
function TPIDLClipboardFormat.HasData: boolean;
begin
Result := (FPIDLs.Count > 0);
end;
 
function TPIDLClipboardFormat.GetSize: integer;
var
i : integer;
begin
Result := (FPIDLs.Count+1) * SizeOf(UINT);
for i := 0 to FPIDLs.Count-1 do
inc(Result, Length(FPIDLs[i]));
end;
 
function TPIDLClipboardFormat.ReadData(Value: pointer;
Size: integer): boolean;
begin
Result := GetPIDLsFromData(Value, Size, FPIDLs);
end;
 
function TPIDLClipboardFormat.WriteData(Value: pointer;
Size: integer): boolean;
var
i : integer;
pCIDA : PIDA;
Offset : integer;
pOffset : ^UINT;
PIDL : PItemIDList;
begin
pCIDA := PIDA(Value);
pCIDA^.cidl := FPIDLs.Count-1; // Don't count folder PIDL
pOffset := @(pCIDA^.aoffset[0]); // Points to aoffset[0]
Offset := (FPIDLs.Count+1)*SizeOf(UINT); // Size of CIDA structure
PIDL := PItemIDList(integer(pCIDA) + Offset); // PIDLs are stored after CIDA structure.
 
for i := 0 to FPIDLs.Count-1 do
begin
pOffset^ := Offset; // Store relative offset of PIDL into aoffset[i]
// Copy the PIDL
Move(PChar(FPIDLs[i])^, PIDL^, length(FPIDLs[i]));
// Move on to next PIDL
inc(Offset, length(FPIDLs[i]));
inc(pOffset);
inc(integer(PIDL), length(FPIDLs[i]));
end;
 
Result := True;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TPIDLDataFormat
//
////////////////////////////////////////////////////////////////////////////////
constructor TPIDLDataFormat.Create(AOwner: TDragDropComponent);
begin
inherited Create(AOwner);
FPIDLs := TStringList.Create;
TStringList(FPIDLs).OnChanging := DoOnChanging;
FFilenames := TPIDLsToFilenamesStrings.Create(FPIDLs);
end;
 
destructor TPIDLDataFormat.Destroy;
begin
FFilenames.Free;
FPIDLs.Free;
inherited Destroy;
end;
 
function TPIDLDataFormat.Assign(Source: TClipboardFormat): boolean;
begin
Result := True;
 
if (Source is TPIDLClipboardFormat) then
FPIDLs.Assign(TPIDLClipboardFormat(Source).PIDLs)
 
else if (Source is TFileClipboardFormat) then
Result := GetPIDLsFromFilenames(TFileClipboardFormat(Source).Files, FPIDLs)
 
else
Result := inherited Assign(Source);
end;
 
function TPIDLDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
begin
Result := True;
 
if (Dest is TPIDLClipboardFormat) then
TPIDLClipboardFormat(Dest).PIDLs.Assign(FPIDLs)
 
else if (Dest is TFileClipboardFormat) then
TFileClipboardFormat(Dest).Files.Assign(Filenames)
 
else
Result := inherited Assign(Dest);
end;
 
procedure TPIDLDataFormat.Clear;
begin
FPIDLs.Clear;
end;
 
function TPIDLDataFormat.HasData: boolean;
begin
Result := (FPIDLs.Count > 0);
end;
 
function TPIDLDataFormat.NeedsData: boolean;
begin
Result := (FPIDLs.Count = 0);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropPIDLTarget
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropPIDLTarget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FPIDLDataFormat := TPIDLDataFormat.Create(Self);
FFileMapDataFormat := TFileMapDataFormat.Create(Self);
end;
 
destructor TDropPIDLTarget.Destroy;
begin
FPIDLDataFormat.Free;
FFileMapDataFormat.Free;
inherited Destroy;
end;
 
function TDropPIDLTarget.GetPIDLs: TStrings;
begin
Result := FPIDLDataFormat.PIDLs;
end;
 
function TDropPIDLTarget.DoGetPIDL(Index: integer): pItemIdList;
var
PIDL : string;
begin
PIDL := PIDLs[Index];
Result := ShellMalloc.Alloc(Length(PIDL));
if (Result <> nil) then
Move(PChar(PIDL)^, Result^, Length(PIDL));
end;
 
function TDropPIDLTarget.GetFolderPidl: pItemIdList;
begin
Result := DoGetPIDL(0);
end;
 
function TDropPIDLTarget.GetRelativeFilePidl(Index: integer): pItemIdList;
begin
Result := nil;
if (index < 1) then
exit;
Result := DoGetPIDL(Index);
end;
 
function TDropPIDLTarget.GetAbsoluteFilePidl(Index: integer): pItemIdList;
var
PIDL : string;
begin
Result := nil;
if (index < 1) then
exit;
PIDL := JoinPIDLStrings(PIDLs[0], PIDLs[Index]);
Result := ShellMalloc.Alloc(Length(PIDL));
if (Result <> nil) then
Move(PChar(PIDL)^, Result^, Length(PIDL));
end;
 
function TDropPIDLTarget.GetPIDLCount: integer;
begin
// Note: Includes folder PIDL in count!
Result := FPIDLDataFormat.PIDLs.Count;
end;
 
function TDropPIDLTarget.GetFilenames: TStrings;
begin
Result := FPIDLDataFormat.Filenames;
end;
 
function TDropPIDLTarget.GetMappedNames: TStrings;
begin
Result := FFileMapDataFormat.FileMaps;
end;
 
function TDropPIDLTarget.GetPreferredDropEffect: LongInt;
begin
Result := inherited GetPreferredDropEffect;
if (Result = DROPEFFECT_NONE) then
Result := DROPEFFECT_COPY;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropPIDLSource
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropPIDLSource.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FPIDLDataFormat := TPIDLDataFormat.Create(Self);
FFileMapDataFormat := TFileMapDataFormat.Create(Self);
end;
 
destructor TDropPIDLSource.Destroy;
begin
FPIDLDataFormat.Free;
FFileMapDataFormat.Free;
inherited Destroy;
end;
 
procedure TDropPIDLSource.CopyFolderPIDLToList(pidl: PItemIDList);
begin
//Note: Once the PIDL has been copied into the list it can be 'freed'.
FPIDLDataFormat.Clear;
FFileMapDataFormat.Clear;
FPIDLDataFormat.PIDLs.Add(PIDLToString(pidl));
end;
 
procedure TDropPIDLSource.CopyFilePIDLToList(pidl: PItemIDList);
begin
// Note: Once the PIDL has been copied into the list it can be 'freed'.
// Make sure that folder pidl has been added.
if (FPIDLDataFormat.PIDLs.Count < 1) then
raise Exception.Create(sNoFolderPIDL);
FPIDLDataFormat.PIDLs.Add(PIDLToString(pidl));
end;
 
function TDropPIDLSource.GetMappedNames: TStrings;
begin
Result := FFileMapDataFormat.FileMaps;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Initialization/Finalization
//
////////////////////////////////////////////////////////////////////////////////
 
initialization
// Data format registration
TPIDLDataFormat.RegisterDataFormat;
// Clipboard format registration
TPIDLDataFormat.RegisterCompatibleFormat(TPIDLClipboardFormat, 0, csSourceTarget, [ddRead]);
TPIDLDataFormat.RegisterCompatibleFormat(TFileClipboardFormat, 1, csSourceTarget, [ddRead]);
 
finalization
TPIDLDataFormat.UnregisterDataFormat;
 
end.
/trunk/VCL_DRAGDROP/DragDropText.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DragDropText.pas
0,0 → 1,442
unit DragDropText;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite.
// Module: DragDropText
// Description: Implements Dragging and Dropping of different text formats.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
interface
 
uses
DragDrop,
DropTarget,
DropSource,
DragDropFormats,
ActiveX,
Windows,
Classes;
 
type
////////////////////////////////////////////////////////////////////////////////
//
// TRichTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TRichTextClipboardFormat = class(TCustomTextClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
function HasData: boolean; override;
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property Text;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TUnicodeTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TUnicodeTextClipboardFormat = class(TCustomWideTextClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property Text;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TOEMTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TOEMTextClipboardFormat = class(TCustomTextClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property Text;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TCSVClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TCSVClipboardFormat = class(TCustomStringListClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property Lines;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TLocaleClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
TLocaleClipboardFormat = class(TCustomDWORDClipboardFormat)
public
function GetClipboardFormat: TClipFormat; override;
function HasData: boolean; override;
function Assign(Source: TCustomDataFormat): boolean; override;
function AssignTo(Dest: TCustomDataFormat): boolean; override;
property Locale: DWORD read GetValueDWORD;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropTextTarget
//
////////////////////////////////////////////////////////////////////////////////
TDropTextTarget = class(TCustomDropMultiTarget)
private
FTextFormat : TTextDataFormat;
protected
function GetText: string;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Text: string read GetText;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropTextSource
//
////////////////////////////////////////////////////////////////////////////////
TDropTextSource = class(TCustomDropMultiSource)
private
FTextFormat : TTextDataFormat;
protected
function GetText: string;
procedure SetText(const Value: string);
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
published
property Text: string read GetText write SetText;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc.
//
////////////////////////////////////////////////////////////////////////////////
function IsRTF(const s: string): boolean;
function MakeRTF(const s: string): string;
 
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
implementation
 
uses
SysUtils;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDropTextTarget,
TDropTextSource]);
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Utilities
//
////////////////////////////////////////////////////////////////////////////////
function IsRTF(const s: string): boolean;
begin
// This probably isn't a valid test, but it will have to do until I have
// time to research the RTF specifications.
{ TODO -oanme -cImprovement : Need a solid test for RTF format. }
Result := (AnsiStrLIComp(PChar(s), '{\rtf', 5) = 0);
end;
 
{ TODO -oanme -cImprovement : Needs RTF to text conversion. Maybe ITextDocument can be used. }
function MakeRTF(const s: string): string;
begin
{ TODO -oanme -cImprovement : Needs to escape \ in text to RTF conversion. }
{ TODO -oanme -cImprovement : Needs better text to RTF conversion. }
if (not IsRTF(s)) then
Result := '{\rtf1\ansi ' + s + '}'
else
Result := s;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TRichTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_RTF: TClipFormat = 0;
 
function TRichTextClipboardFormat.GetClipboardFormat: TClipFormat;
begin
// Note: The string 'Rich Text Format', is also defined in the RichEdit
// unit as CF_RTF
if (CF_RTF = 0) then
CF_RTF := RegisterClipboardFormat('Rich Text Format'); // *** DO NOT LOCALIZE ***
Result := CF_RTF;
end;
 
function TRichTextClipboardFormat.HasData: boolean;
begin
Result := inherited HasData and IsRTF(Text);
end;
 
function TRichTextClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
if (Source is TTextDataFormat) then
begin
Text := MakeRTF(TTextDataFormat(Source).Text);
Result := True;
end else
Result := inherited Assign(Source);
end;
 
function TRichTextClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
if (Dest is TTextDataFormat) then
begin
TTextDataFormat(Dest).Text := Text;
Result := True;
end else
Result := inherited AssignTo(Dest);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TUnicodeTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
function TUnicodeTextClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := CF_UNICODETEXT;
end;
 
function TUnicodeTextClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
if (Source is TTextDataFormat) then
begin
Text := TTextDataFormat(Source).Text;
Result := True;
end else
Result := inherited Assign(Source);
end;
 
function TUnicodeTextClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
if (Dest is TTextDataFormat) then
begin
TTextDataFormat(Dest).Text := Text;
Result := True;
end else
Result := inherited AssignTo(Dest);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TOEMTextClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
function TOEMTextClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := CF_OEMTEXT;
end;
 
function TOEMTextClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
var
OEMText : string;
begin
if (Source is TTextDataFormat) then
begin
// First convert ANSI string to OEM string...
SetLength(OEMText, Length(TTextDataFormat(Source).Text));
CharToOemBuff(PChar(TTextDataFormat(Source).Text), PChar(OEMText),
Length(TTextDataFormat(Source).Text));
// ...then assign OEM string
Text := OEMText;
Result := True;
end else
Result := inherited Assign(Source);
end;
 
function TOEMTextClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
var
AnsiText : string;
begin
if (Dest is TTextDataFormat) then
begin
// First convert OEM string to ANSI string...
SetLength(AnsiText, Length(Text));
OemToCharBuff(PChar(Text), PChar(AnsiText), Length(Text));
// ...then assign ANSI string
TTextDataFormat(Dest).Text := AnsiText;
Result := True;
end else
Result := inherited AssignTo(Dest);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCSVClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
var
CF_CSV: TClipFormat = 0;
 
function TCSVClipboardFormat.GetClipboardFormat: TClipFormat;
begin
if (CF_CSV = 0) then
CF_CSV := RegisterClipboardFormat('CSV'); // *** DO NOT LOCALIZE ***
Result := CF_CSV;
end;
 
function TCSVClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
if (Source is TTextDataFormat) then
begin
Lines.Text := TTextDataFormat(Source).Text;
Result := True;
end else
Result := inherited AssignTo(Source);
end;
 
function TCSVClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
if (Dest is TTextDataFormat) then
begin
TTextDataFormat(Dest).Text := Lines.Text;
Result := True;
end else
Result := inherited AssignTo(Dest);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TLocaleClipboardFormat
//
////////////////////////////////////////////////////////////////////////////////
function TLocaleClipboardFormat.GetClipboardFormat: TClipFormat;
begin
Result := CF_LOCALE;
end;
 
function TLocaleClipboardFormat.HasData: boolean;
begin
Result := (Locale <> 0);
end;
 
function TLocaleClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
begin
// So far we have no one to play with...
Result := inherited Assign(Source);
end;
 
function TLocaleClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
begin
// So far we have no one to play with...
Result := inherited AssignTo(Dest);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropTextTarget
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropTextTarget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FTextFormat := TTextDataFormat.Create(Self);
end;
 
destructor TDropTextTarget.Destroy;
begin
FTextFormat.Free;
inherited Destroy;
end;
 
function TDropTextTarget.GetText: string;
begin
Result := FTextFormat.Text;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropTextSource
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropTextSource.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
FTextFormat := TTextDataFormat.Create(Self);
end;
 
destructor TDropTextSource.Destroy;
begin
FTextFormat.Free;
inherited Destroy;
end;
 
function TDropTextSource.GetText: string;
begin
Result := FTextFormat.Text;
end;
 
procedure TDropTextSource.SetText(const Value: string);
begin
FTextFormat.Text := Value;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Initialization/Finalization
//
////////////////////////////////////////////////////////////////////////////////
 
initialization
// Clipboard format registration
TTextDataFormat.RegisterCompatibleFormat(TUnicodeTextClipboardFormat, 1, csSourceTarget, [ddRead]);
TTextDataFormat.RegisterCompatibleFormat(TRichTextClipboardFormat, 2, csSourceTarget, [ddRead]);
TTextDataFormat.RegisterCompatibleFormat(TOEMTextClipboardFormat, 2, csSourceTarget, [ddRead]);
TTextDataFormat.RegisterCompatibleFormat(TCSVClipboardFormat, 3, csSourceTarget, [ddRead]);
 
finalization
// Clipboard format unregistration
TUnicodeTextClipboardFormat.UnregisterClipboardFormat;
TRichTextClipboardFormat.UnregisterClipboardFormat;
TOEMTextClipboardFormat.UnregisterClipboardFormat;
TCSVClipboardFormat.UnregisterClipboardFormat;
end.
/trunk/VCL_DRAGDROP/DropBMPSource.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DropBMPSource.pas
0,0 → 1,213
unit DropBMPSource;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Component Names: TDropBMPSource
// Module: DropBMPSource
// Description: Implements Dragging & Dropping of Bitmaps
// FROM your application to another.
// Version: 3.7
// Date: 22-JUL-1999
// Target: Win32, Delphi 3 - Delphi 5, C++ Builder 3, C++ Builder 4
// Authors: Angus Johnson, ajohnson@rpi.net.au
// Anders Melander, anders@melander.dk
// http://www.melander.dk
// Copyright © 1997-99 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
// Acknowledgements:
// Thanks to Dieter Steinwedel for some help with DIBs.
// http://godard.oec.uni-osnabrueck.de/student_home/dsteinwe/delphi/DietersDelphiSite.htm
// -----------------------------------------------------------------------------
 
interface
 
uses
DropSource,
Classes, Graphics, ActiveX;
 
{$include DragDrop.inc}
 
type
TDropBMPSource = class(TDropSource)
private
fBitmap: TBitmap;
procedure SetBitmap(Bmp: TBitmap);
protected
function DoGetData(const FormatEtcIn: TFormatEtc; OUT Medium: TStgMedium):HRESULT; Override;
public
constructor Create(aOwner: TComponent); Override;
destructor Destroy; Override;
function CutOrCopyToClipboard: boolean; Override;
published
property Bitmap: TBitmap Read fBitmap Write SetBitmap;
end;
 
procedure Register;
 
implementation
 
uses
Windows,
SysUtils,
ClipBrd;
 
procedure Register;
begin
RegisterComponents('DragDrop', [TDropBMPSource]);
end;
 
// -----------------------------------------------------------------------------
// Miscellaneous DIB Function
// -----------------------------------------------------------------------------
 
function GetHGlobalDIBFromBitmap(Bitmap: Graphics.TBitmap): HGlobal;
var
Stream: TMemoryStream;
DIB: pointer;
DIBSize: integer;
bfh: TBitmapFileHeader;
begin
Stream := TMemoryStream.Create;
try
//let Graphics.pas do the work...
Bitmap.SaveToStream(Stream);
//BitmapFileHeader will be discarded
DIBSize := Stream.Size - sizeof(TBitmapFileHeader);
Result:=GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT or GMEM_SHARE, DIBSize);
if Result = 0 then exit;
DIB := GlobalLock(Result);
if DIB = nil then
begin
GlobalFree(Result);
Result := 0;
end else
begin
Stream.Seek(0,soFromBeginning);
//skip BitmapFileHeader...
Stream.readbuffer(bfh,sizeof(TBitmapFileHeader));
//copy data...
Stream.readbuffer(DIB^,DIBSize);
GlobalUnlock(Result);
end;
finally
Stream.free;
end;
end;
 
// -----------------------------------------------------------------------------
// TDropBMPSource
// -----------------------------------------------------------------------------
 
constructor TDropBMPSource.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
fBitmap := Graphics.TBitmap.Create;
DragTypes := [dtCopy]; // Default to Copy
 
AddFormatEtc(CF_BITMAP, NIL, DVASPECT_CONTENT, -1, TYMED_GDI);
AddFormatEtc(CF_PALETTE, NIL, DVASPECT_CONTENT, -1, TYMED_GDI);
AddFormatEtc(CF_DIB, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
end;
// -----------------------------------------------------------------------------
 
destructor TDropBMPSource.destroy;
begin
fBitmap.Free;
inherited Destroy;
end;
// -----------------------------------------------------------------------------
 
procedure TDropBMPSource.SetBitmap(Bmp: Graphics.TBitmap);
begin
fBitmap.assign(Bmp);
end;
// -----------------------------------------------------------------------------
 
function TDropBMPSource.CutOrCopyToClipboard: boolean;
var
data: HGlobal;
begin
result := false;
if fBitmap.empty then exit;
try
data := GetHGlobalDIBFromBitmap(fBitmap);
if data = 0 then exit;
Clipboard.SetAsHandle(CF_DIB,data);
result := true;
except
raise Exception.create('Unable to copy BMP to clipboard.');
end;
end;
// -----------------------------------------------------------------------------
 
function TDropBMPSource.DoGetData(const FormatEtcIn: TFormatEtc; OUT Medium: TStgMedium):HRESULT;
var
fmt: WORD;
pal: HPALETTE;
begin
 
Medium.tymed := 0;
Medium.UnkForRelease := nil;
Medium.HGlobal := 0;
//--------------------------------------------------------------------------
if not fBitmap.empty and
(FormatEtcIn.cfFormat = CF_DIB) and
(FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
(FormatEtcIn.tymed and TYMED_HGLOBAL <> 0) then
begin
try
Medium.HGlobal := GetHGlobalDIBFromBitmap(fBitmap);
if Medium.HGlobal <> 0 then
begin
Medium.tymed := TYMED_HGLOBAL;
result := S_OK
end else
result := E_OUTOFMEMORY;
except
result := E_OUTOFMEMORY;
end;
end
//--------------------------------------------------------------------------
else if not fBitmap.empty and
(FormatEtcIn.cfFormat = CF_BITMAP) and
(FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
(FormatEtcIn.tymed and TYMED_GDI <> 0) then
begin
try
//This next line just gets a copy of the bitmap handle...
fBitmap.SaveToClipboardFormat(fmt, THandle(Medium.hBitmap), pal);
if pal <> 0 then DeleteObject(pal);
if Medium.hBitmap <> 0 then
begin
Medium.tymed := TYMED_GDI;
result := S_OK
end else
result := E_OUTOFMEMORY;
except
result := E_OUTOFMEMORY;
end;
end
//--------------------------------------------------------------------------
else if not fBitmap.empty and
(FormatEtcIn.cfFormat = CF_PALETTE) and
(FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
(FormatEtcIn.tymed and TYMED_GDI <> 0) then
begin
try
Medium.hBitmap := CopyPalette(fBitmap.palette);
if Medium.hBitmap <> 0 then
begin
Medium.tymed := TYMED_GDI;
result := S_OK
end else
result := E_OUTOFMEMORY;
except
result := E_OUTOFMEMORY;
end {try}
end else
result := DV_E_FORMATETC;
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
 
end.
/trunk/VCL_DRAGDROP/DropBMPTarget.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DropBMPTarget.pas
0,0 → 1,182
unit DropBMPTarget;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Component Names: TDropBMPSource
// Module: DropBMPSource
// Description: Implements Dragging & Dropping of Bitmaps
// FROM your application to another.
// Version: 3.7
// Date: 22-JUL-1999
// Target: Win32, Delphi 3 - Delphi 5, C++ Builder 3, C++ Builder 4
// Authors: Angus Johnson, ajohnson@rpi.net.au
// Anders Melander, anders@melander.dk
// http://www.melander.dk
// Copyright © 1997-99 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
interface
 
uses
DropSource,
DropTarget,
Windows, Classes, Graphics, ActiveX;
 
{$include DragDrop.inc}
 
type
TDropBMPTarget = class(TDropTarget)
private
fBitmap: TBitmap;
protected
procedure ClearData; override;
function DoGetData: boolean; override;
function HasValidFormats: boolean; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Bitmap: TBitmap Read fBitmap;
end;
 
procedure Register;
procedure CopyDIBToBitmap(Bitmap: TBitmap; BitmapInfo: PBitmapInfo; DIBSize: integer);
 
implementation
 
const
DIBFormatEtc: TFormatEtc = (cfFormat: CF_DIB;
ptd: nil; dwAspect: DVASPECT_CONTENT; lindex: -1; tymed: TYMED_HGLOBAL);
BMPFormatEtc: TFormatEtc = (cfFormat: CF_BITMAP;
ptd: nil; dwAspect: DVASPECT_CONTENT; lindex: -1; tymed: TYMED_GDI);
PalFormatEtc: TFormatEtc = (cfFormat: CF_PALETTE;
ptd: nil; dwAspect: DVASPECT_CONTENT; lindex: -1; tymed: TYMED_GDI);
 
procedure Register;
begin
RegisterComponents('DragDrop', [TDropBMPTarget]);
end;
 
// -----------------------------------------------------------------------------
// Miscellaneous DIB Function
// -----------------------------------------------------------------------------
 
procedure CopyDIBToBitmap(Bitmap: TBitmap; BitmapInfo: PBitmapInfo; DIBSize: integer);
var
BitmapFileHeader : TBitmapFileHeader;
FileSize : integer;
InfoSize : integer;
Stream : TMemoryStream;
begin
// Write DIB to a stream in the BMP file format
Stream := TMemoryStream.Create;
try
FileSize := sizeof(TBitmapFileHeader) + DIBSize;
InfoSize := sizeof(TBitmapInfoHeader);
if (BitmapInfo^.bmiHeader.biBitCount > 8) then
begin
if ((BitmapInfo^.bmiHeader.biCompression and BI_BITFIELDS) <> 0) then
Inc(InfoSize, 12);
end else
Inc(InfoSize, sizeof(TRGBQuad) * (1 shl BitmapInfo^.bmiHeader.biBitCount));
Stream.SetSize(FileSize);
// Initialize file header
FillChar(BitmapFileHeader, sizeof(TBitmapFileHeader), 0);
with BitmapFileHeader do
begin
bfType := $4D42; // 'BM' = Windows BMP signature
bfSize := FileSize; // File size (not needed)
bfOffBits := sizeof(TBitmapFileHeader) + InfoSize; // Offset of pixel data
end;
// Save file header
Stream.Write(BitmapFileHeader, sizeof(TBitmapFileHeader));
// Save TBitmapInfo structure and pixel data
Stream.Write(BitmapInfo^, DIBSize);
 
// Rewind and load bitmap from stream
Stream.Position := 0;
Bitmap.LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
 
// -----------------------------------------------------------------------------
// TDropBMPTarget
// -----------------------------------------------------------------------------
 
constructor TDropBMPTarget.Create( AOwner: TComponent );
begin
inherited Create( AOwner );
fBitmap := TBitmap.Create;
end;
// -----------------------------------------------------------------------------
 
destructor TDropBMPTarget.Destroy;
begin
fBitmap.Free;
inherited Destroy;
end;
// -----------------------------------------------------------------------------
 
function TDropBMPTarget.HasValidFormats: boolean;
begin
result := (DataObject.QueryGetData(DIBFormatEtc) = S_OK) or
(DataObject.QueryGetData(BMPFormatEtc) = S_OK);
end;
// -----------------------------------------------------------------------------
 
procedure TDropBMPTarget.ClearData;
begin
fBitmap.handle := 0;
end;
// -----------------------------------------------------------------------------
 
function TDropBMPTarget.DoGetData: boolean;
var
medium, medium2: TStgMedium;
DIBData: pointer;
begin
result := false;
//--------------------------------------------------------------------------
if (DataObject.GetData(DIBFormatEtc, medium) = S_OK) then
begin
if (medium.tymed = TYMED_HGLOBAL) then
begin
DIBData := GlobalLock(medium.HGlobal);
try
CopyDIBToBitmap(fBitmap, DIBData, GlobalSize(Medium.HGlobal));
result := true;
finally
GlobalUnlock(medium.HGlobal);
end;
end;
ReleaseStgMedium(medium);
end
//--------------------------------------------------------------------------
else if (DataObject.GetData(BMPFormatEtc, medium) = S_OK) then
begin
try
if (medium.tymed <> TYMED_GDI) then exit;
if (DataObject.GetData(PalFormatEtc, medium2) = S_OK) then
begin
try
fBitmap.LoadFromClipboardFormat(CF_BITMAP, Medium.hBitmap, Medium2.hBitmap);
finally
ReleaseStgMedium(medium2);
end;
end
else
fBitmap.LoadFromClipboardFormat(CF_BITMAP, Medium.hBitmap, 0);
result := true;
finally
ReleaseStgMedium(medium);
end;
end
//--------------------------------------------------------------------------
else
result := false;
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
 
end.
/trunk/VCL_DRAGDROP/DropComboTarget.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DropComboTarget.pas
0,0 → 1,192
unit DropComboTarget;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Module: DropComboTarget
// Description: Implements a swiss-army-knife drop target component.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
interface
 
uses
DragDrop,
DropTarget,
DragDropFormats,
DragDropInternet,
DragDropGraphics,
DragDropFile,
DragDropText,
Classes,
Graphics,
ActiveX;
 
type
// Note: mfCustom is used to support DataFormatAdapters.
TComboFormatType = (mfText, mfFile, mfURL, mfBitmap, mfMetaFile, mfData, mfCustom);
TComboFormatTypes = set of TComboFormatType;
 
const
AllComboFormats = [mfText, mfFile, mfURL, mfBitmap, mfMetaFile, mfData];
 
type
////////////////////////////////////////////////////////////////////////////////
//
// TDropComboTarget
//
////////////////////////////////////////////////////////////////////////////////
TDropComboTarget = class(TCustomDropMultiTarget)
private
FFileFormat : TFileDataFormat;
FFileMapFormat : TFileMapDataFormat;
FURLFormat : TURLDataFormat;
FBitmapFormat : TBitmapDataFormat;
FMetaFileFormat : TMetaFileDataFormat;
FTextFormat : TTextDataFormat;
FDataFormat : TDataStreamDataFormat;
FFormats : TComboFormatTypes;
protected
procedure DoAcceptFormat(const DataFormat: TCustomDataFormat;
var Accept: boolean); override;
function GetFiles: TStrings;
function GetTitle: string;
function GetURL: string;
function GetBitmap: TBitmap;
function GetMetaFile: TMetaFile;
function GetText: string;
function GetFileMaps: TStrings;
function GetStreams: TStreamList;
public
constructor Create(AOwner: TComponent); override;
property Files: TStrings read GetFiles;
property FileMaps: TStrings read GetFileMaps;
property URL: string read GetURL;
property Title: string read GetTitle;
property Bitmap: TBitmap read GetBitmap;
property MetaFile: TMetaFile read GetMetaFile;
property Text: string read GetText;
property Data: TStreamList read GetStreams;
published
property OnAcceptFormat;
property Formats: TComboFormatTypes read FFormats write FFormats default AllComboFormats;
end;
 
(*
** *** WARNING ***
**
** The TDropMultiTarget component has been renamed to TDropComboTarget and
** will be removed shortly. See the readme.txt file for instruction on how to
** replace TDropMultiTarget with TDropComboTarget.
*)
TDropMultiTarget = class(TDropComboTarget);
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
implementation
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDropComboTarget]);
RegisterNoIcon([TDropMultiTarget]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropComboTarget
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropComboTarget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FFileFormat := TFileDataFormat.Create(Self);
FURLFormat := TURLDataFormat.Create(Self);
FBitmapFormat := TBitmapDataFormat.Create(Self);
FMetaFileFormat := TMetaFileDataFormat.Create(Self);
FTextFormat := TTextDataFormat.Create(Self);
FFileMapFormat := TFileMapDataFormat.Create(Self);
FDataFormat := TDataStreamDataFormat.Create(Self);
FFormats := AllComboFormats;
end;
 
procedure TDropComboTarget.DoAcceptFormat(const DataFormat: TCustomDataFormat;
var Accept: boolean);
begin
if (Accept) then
begin
if (DataFormat is TFileDataFormat) or (DataFormat is TFileMapDataFormat) then
Accept := (mfFile in FFormats)
else if (DataFormat is TURLDataFormat) then
Accept := (mfURL in FFormats)
else if (DataFormat is TBitmapDataFormat) then
Accept := (mfBitmap in FFormats)
else if (DataFormat is TMetaFileDataFormat) then
Accept := (mfMetaFile in FFormats)
else if (DataFormat is TTextDataFormat) then
Accept := (mfText in FFormats)
else if (DataFormat is TDataStreamDataFormat) then
Accept := (mfData in FFormats)
else
Accept := (mfCustom in FFormats)
end;
 
if (Accept) then
inherited DoAcceptFormat(DataFormat, Accept);
 
end;
 
function TDropComboTarget.GetBitmap: TBitmap;
begin
Result := FBitmapFormat.Bitmap;
end;
 
function TDropComboTarget.GetFileMaps: TStrings;
begin
Result := FFileMapFormat.FileMaps;
end;
 
function TDropComboTarget.GetFiles: TStrings;
begin
Result := FFileFormat.Files;
end;
 
function TDropComboTarget.GetMetaFile: TMetaFile;
begin
Result := FMetaFileFormat.MetaFile;
end;
 
function TDropComboTarget.GetStreams: TStreamList;
begin
Result := FDataFormat.Streams;
end;
 
function TDropComboTarget.GetText: string;
begin
Result := FTextFormat.Text;
end;
 
function TDropComboTarget.GetTitle: string;
begin
Result := FURLFormat.Title;
end;
 
function TDropComboTarget.GetURL: string;
begin
Result := FURLFormat.URL;
end;
 
end.
/trunk/VCL_DRAGDROP/DropFileSource3.pas
0,0 → 1,195
unit DropFileSource3;
 
// -----------------------------------------------------------------------------
//
// *** NOT FOR RELEASE ***
//
// *** INTERNAL USE ONLY ***
//
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Module: DropFileSource3
// Description: Test case for deprecated TDropSource class.
// Version: 4.0
// Date: 25-JUN-2000
// Target: Win32, Delphi 3-6 and C++ Builder 3-5
// Authors: Angus Johnson, ajohnson@rpi.net.au
// Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2000 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
 
interface
 
uses
DragDrop,
DragDropPIDL,
DragDropFormats,
DragDropFile,
DropSource3,
ActiveX, Classes;
 
{$include DragDrop.inc}
 
type
TDropFileSourceX = class(TDropSource)
private
fFiles: TStrings;
fMappedNames: TStrings;
FFileClipboardFormat: TFileClipboardFormat;
FPIDLClipboardFormat: TPIDLClipboardFormat;
FPreferredDropEffectClipboardFormat: TPreferredDropEffectClipboardFormat;
FFilenameMapClipboardFormat: TFilenameMapClipboardFormat;
FFilenameMapWClipboardFormat: TFilenameMapWClipboardFormat;
 
procedure SetFiles(files: TStrings);
procedure SetMappedNames(names: TStrings);
protected
function DoGetData(const FormatEtcIn: TFormatEtc;
out Medium: TStgMedium):HRESULT; override;
function CutOrCopyToClipboard: boolean; override;
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
published
property Files: TStrings read fFiles write SetFiles;
//MappedNames is only needed if files need to be renamed during a drag op
//eg dragging from 'Recycle Bin'.
property MappedNames: TStrings read fMappedNames write SetMappedNames;
end;
 
procedure Register;
 
implementation
 
uses
Windows,
ShlObj,
SysUtils,
ClipBrd;
 
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDropFileSourceX]);
end;
 
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
 
constructor TDropFileSourceX.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
fFiles := TStringList.Create;
fMappedNames := TStringList.Create;
 
FFileClipboardFormat := TFileClipboardFormat.Create;
FPIDLClipboardFormat := TPIDLClipboardFormat.Create;
FPreferredDropEffectClipboardFormat := TPreferredDropEffectClipboardFormat.Create;
FFilenameMapClipboardFormat := TFilenameMapClipboardFormat.Create;
FFilenameMapWClipboardFormat := TFilenameMapWClipboardFormat.Create;
 
AddFormatEtc(FFileClipboardFormat.GetClipboardFormat, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
AddFormatEtc(FPIDLClipboardFormat.GetClipboardFormat, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
AddFormatEtc(FPreferredDropEffectClipboardFormat.GetClipboardFormat, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
AddFormatEtc(FFilenameMapClipboardFormat.GetClipboardFormat, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
AddFormatEtc(FFilenameMapWClipboardFormat.GetClipboardFormat, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
end;
// -----------------------------------------------------------------------------
 
destructor TDropFileSourceX.destroy;
begin
FFileClipboardFormat.Free;
FPIDLClipboardFormat.Free;
FPreferredDropEffectClipboardFormat.Free;
FFilenameMapClipboardFormat.Free;
FFilenameMapWClipboardFormat.Free;
fFiles.Free;
fMappedNames.free;
inherited Destroy;
end;
// -----------------------------------------------------------------------------
 
procedure TDropFileSourceX.SetFiles(files: TStrings);
begin
fFiles.assign(files);
end;
// -----------------------------------------------------------------------------
 
procedure TDropFileSourceX.SetMappedNames(names: TStrings);
begin
fMappedNames.assign(names);
end;
// -----------------------------------------------------------------------------
 
function TDropFileSourceX.CutOrCopyToClipboard: boolean;
var
FormatEtcIn: TFormatEtc;
Medium: TStgMedium;
begin
FormatEtcIn.cfFormat := CF_HDROP;
FormatEtcIn.dwAspect := DVASPECT_CONTENT;
FormatEtcIn.tymed := TYMED_HGLOBAL;
if (Files.count = 0) then result := false
else if GetData(formatetcIn,Medium) = S_OK then
begin
Clipboard.SetAsHandle(CF_HDROP,Medium.hGlobal);
result := true;
end else result := false;
end;
// -----------------------------------------------------------------------------
 
function TDropFileSourceX.DoGetData(const FormatEtcIn: TFormatEtc;
out Medium: TStgMedium):HRESULT;
begin
Medium.tymed := 0;
Medium.UnkForRelease := NIL;
Medium.hGlobal := 0;
 
result := E_UNEXPECTED;
if fFiles.count = 0 then
exit;
 
//--------------------------------------------------------------------------
if FFileClipboardFormat.AcceptFormat(FormatEtcIn) then
begin
FFileClipboardFormat.Files.Assign(FFiles);
if FFileClipboardFormat.SetDataToMedium(FormatEtcIn, Medium) then
result := S_OK;
end else
//--------------------------------------------------------------------------
if FFilenameMapClipboardFormat.AcceptFormat(FormatEtcIn) then
begin
FFilenameMapClipboardFormat.FileMaps.Assign(fMappedNames);
if FFilenameMapClipboardFormat.SetDataToMedium(FormatEtcIn, Medium) then
result := S_OK;
end else
//--------------------------------------------------------------------------
if FFilenameMapWClipboardFormat.AcceptFormat(FormatEtcIn) then
begin
FFilenameMapWClipboardFormat.FileMaps.Assign(fMappedNames);
if FFilenameMapWClipboardFormat.SetDataToMedium(FormatEtcIn, Medium) then
result := S_OK;
end else
//--------------------------------------------------------------------------
if FPIDLClipboardFormat.AcceptFormat(FormatEtcIn) then
begin
FPIDLClipboardFormat.Filenames.Assign(FFiles);
if FPIDLClipboardFormat.SetDataToMedium(FormatEtcIn, Medium) then
result := S_OK;
end else
//--------------------------------------------------------------------------
//This next format does not work for Win95 but should for Win98, WinNT ...
//It stops the shell from prompting (with a popup menu) for the choice of
//Copy/Move/Shortcut when performing a file 'Shortcut' onto Desktop or Explorer.
if FPreferredDropEffectClipboardFormat.AcceptFormat(FormatEtcIn) then
begin
FPreferredDropEffectClipboardFormat.Value := FeedbackEffect;
if FPreferredDropEffectClipboardFormat.SetDataToMedium(FormatEtcIn, Medium) then
result := S_OK;
end else
result := DV_E_FORMATETC;
end;
 
end.
/trunk/VCL_DRAGDROP/DropHandler.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DropHandler.pas
0,0 → 1,182
unit DropHandler;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite.
// Module: DropHandler
// Description: Implements Drop Handler Shell Extensions.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
interface
 
uses
DragDrop,
DropTarget,
DragDropFile,
DragDropComObj,
ActiveX,
Windows,
Classes;
 
type
////////////////////////////////////////////////////////////////////////////////
//
// TDropHandler
//
////////////////////////////////////////////////////////////////////////////////
// Based on Angus Johnson's DropHandler demo.
////////////////////////////////////////////////////////////////////////////////
// A typical drop handler session goes like this:
// 1. User drags one or more source files over a target file which has a
// registered drop handler.
// 2. The shell loads the drop handler module.
// 3. The shell instantiates the registered drop handler object as an in-process
// COM server.
// 4. The IPersistFile.Load method is called with the name of the target file.
// The target file name is stored in the TDropHandler.TargetFile property.
// 5. The IDropTarget.Enter method is called. This causes a TDropHandler.OnEnter
// event to be fired.
// 6. One of two things can happen next:
// a) The user drops the source files on the target file.
// The IDropTarget.Drop method is called. This causes a
// TDropHandler.OnDrop event to be fired.
// The names of the dropped files are stored in the TDropHandler.Files
// string list property.
// b) The user drags the source files away from the target file.
// The IDropTarget.Leave method is called. This causes a
// TDropHandler.OnLeave event to be fired.
// 7. The shell unloads the drop handler module (usually after a few seconds).
////////////////////////////////////////////////////////////////////////////////
TDropHandler = class(TDropFileTarget, IPersistFile)
private
FTargetFile: string;
protected
// IPersistFile implementation
function GetClassID(out classID: TCLSID): HResult; stdcall;
function IsDirty: HResult; stdcall;
function Load(pszFileName: POleStr; dwMode: Longint): HResult; stdcall;
function Save(pszFileName: POleStr; fRemember: BOOL): HResult; stdcall;
function SaveCompleted(pszFileName: POleStr): HResult; stdcall;
function GetCurFile(out pszFileName: POleStr): HResult; stdcall;
public
property TargetFile: string read FTargetFile;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropHandlerFactory
//
////////////////////////////////////////////////////////////////////////////////
// COM Class factory for TDropHandler.
////////////////////////////////////////////////////////////////////////////////
TDropHandlerFactory = class(TShellExtFactory)
protected
public
procedure UpdateRegistry(Register: Boolean); override;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc.
//
////////////////////////////////////////////////////////////////////////////////
 
 
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
implementation
 
uses
ComObj;
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
 
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDropHandler]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Utilities
//
////////////////////////////////////////////////////////////////////////////////
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropHandler
//
////////////////////////////////////////////////////////////////////////////////
function TDropHandler.GetClassID(out classID: TCLSID): HResult;
begin
result := E_NOTIMPL;
end;
 
function TDropHandler.GetCurFile(out pszFileName: POleStr): HResult;
begin
result := E_NOTIMPL;
end;
 
function TDropHandler.IsDirty: HResult;
begin
result := S_FALSE;
end;
 
function TDropHandler.Load(pszFileName: POleStr; dwMode: Integer): HResult;
begin
FTargetFile := WideCharToString(pszFileName);
result := S_OK;
end;
 
function TDropHandler.Save(pszFileName: POleStr; fRemember: BOOL): HResult;
begin
result := E_NOTIMPL;
end;
 
function TDropHandler.SaveCompleted(pszFileName: POleStr): HResult;
begin
result := E_NOTIMPL;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropHandlerFactory
//
////////////////////////////////////////////////////////////////////////////////
procedure TDropHandlerFactory.UpdateRegistry(Register: Boolean);
begin
if Register then
begin
inherited UpdateRegistry(Register);
CreateRegKey(FileClass+'\shellex\DropHandler', '', GUIDToString(ClassID));
end else
begin
RegDeleteKey(HKEY_CLASSES_ROOT, PChar(FileClass));
inherited UpdateRegistry(Register);
end;
end;
 
end.
/trunk/VCL_DRAGDROP/DropPIDLSource.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DropPIDLSource.pas
0,0 → 1,360
unit DropPIDLSource;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Component Names: TDropPIDLSource
// Module: DropPIDLSource
// Description: Implements Dragging & Dropping of PIDLs
// FROM your application to another.
// Version: 3.7
// Date: 22-JUL-1999
// Target: Win32, Delphi 3 - Delphi 5, C++ Builder 3, C++ Builder 4
// Authors: Angus Johnson, ajohnson@rpi.net.au
// Anders Melander, anders@melander.dk
// http://www.melander.dk
// Copyright © 1997-99 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
interface
 
uses
DropSource,
Classes, ActiveX, ShlObj;
 
{$include DragDrop.inc}
 
type
TDropPIDLSource = class(TDropSource)
private
fPIDLs: TStrings; //NOTE: contains folder PIDL as well as file PIDLs
fMappedNames: TStrings;
function GetFilename(index: integer): string; //used internally
procedure SetMappedNames(names: TStrings);
protected
function DoGetData(const FormatEtcIn: TFormatEtc;
OUT Medium: TStgMedium):HRESULT; Override;
function CutOrCopyToClipboard: boolean; Override;
public
constructor Create(aOwner: TComponent); Override;
destructor Destroy; Override;
procedure CopyFolderPidlToList(pidl: PItemIDList);
procedure CopyFilePidlToList(pidl: PItemIDList);
property MappedNames: TStrings read fMappedNames write SetMappedNames;
end;
 
procedure Register;
 
//Exposed as also used by DropPIDLTarget...
function PidlToString(pidl: PItemIDList): String;
function JoinPidlStrings(pidl1,pidl2: string): String;
 
implementation
 
uses
Windows,
SysUtils,
ClipBrd;
 
procedure Register;
begin
RegisterComponents('DragDrop', [TDropPIDLSource]);
end;
 
// -----------------------------------------------------------------------------
// Miscellaneous Functions...
// -----------------------------------------------------------------------------
 
function GetSizeOfPidl(pidl: PItemIDList): integer;
var
i: integer;
begin
result := SizeOf(Word);
repeat
i := pSHItemID(pidl)^.cb;
inc(result,i);
inc(longint(pidl),i);
until i = 0;
end;
// -----------------------------------------------------------------------------
 
function PidlToString(pidl: PItemIDList): String;
var
PidlLength: integer;
begin
PidlLength := GetSizeOfPidl(pidl);
setlength(result,PidlLength);
Move(pidl^,pchar(result)^,PidlLength);
end;
// -----------------------------------------------------------------------------
 
function JoinPidlStrings(pidl1,pidl2: string): String;
var
PidlLength: integer;
begin
if Length(pidl1) <= 2 then PidlLength := 0
else PidlLength := Length(pidl1)-2;
setlength(result,PidlLength+length(pidl2));
if PidlLength > 0 then Move(pidl1[1],result[1],PidlLength);
Move(pidl2[1],result[PidlLength+1],length(pidl2));
end;
 
// -----------------------------------------------------------------------------
// TDropPIDLSource
// -----------------------------------------------------------------------------
constructor TDropPIDLSource.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
fPIDLs := TStringList.create;
fMappedNames := TStringList.Create;
AddFormatEtc(CF_HDROP, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
AddFormatEtc(CF_IDLIST, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
AddFormatEtc(CF_PREFERREDDROPEFFECT, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
AddFormatEtc(CF_FILENAMEMAP, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
AddFormatEtc(CF_FILENAMEMAPW, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
end;
// -----------------------------------------------------------------------------
 
destructor TDropPIDLSource.Destroy;
begin
fPIDLs.free;
fMappedNames.free;
inherited Destroy;
end;
// -----------------------------------------------------------------------------
 
//this function is used internally by DoGetData()...
function TDropPIDLSource.GetFilename(index: integer): string;
var
PidlStr: string;
buff: array [0..MAX_PATH] of char;
begin
if (index < 1) or (index >= fPIDLs.count) then result := ''
else
begin
PidlStr := JoinPidlStrings(fPIDLs[0], fPIDLs[index]);
SHGetPathFromIDList(PItemIDList(pChar(PidlStr)),buff);
result := buff;
end;
end;
// -----------------------------------------------------------------------------
 
//Note: Once the PIDL has been copied into the list it can be 'freed'.
procedure TDropPIDLSource.CopyFolderPidlToList(pidl: PItemIDList);
begin
fPIDLs.clear;
fMappedNames.clear;
fPIDLs.add(PidlToString(pidl));
end;
// -----------------------------------------------------------------------------
 
//Note: Once the PIDL has been copied into the list it can be 'freed'.
procedure TDropPIDLSource.CopyFilePidlToList(pidl: PItemIDList);
begin
if fPIDLs.count < 1 then exit; //no folder pidl has been added!
fPIDLs.add(PidlToString(pidl));
end;
// -----------------------------------------------------------------------------
 
procedure TDropPIDLSource.SetMappedNames(names: TStrings);
begin
fMappedNames.assign(names);
end;
// -----------------------------------------------------------------------------
 
function TDropPIDLSource.CutOrCopyToClipboard: boolean;
var
FormatEtcIn: TFormatEtc;
Medium: TStgMedium;
begin
FormatEtcIn.cfFormat := CF_IDLIST;
FormatEtcIn.dwAspect := DVASPECT_CONTENT;
FormatEtcIn.tymed := TYMED_HGLOBAL;
if (fPIDLs.count < 2) then result := false
else if GetData(formatetcIn,Medium) = S_OK then
begin
Clipboard.SetAsHandle(CF_IDLIST,Medium.hGlobal);
result := true;
end else result := false;
end;
// -----------------------------------------------------------------------------
 
function TDropPIDLSource.DoGetData(const FormatEtcIn: TFormatEtc;
OUT Medium: TStgMedium):HRESULT;
var
i, MemSpace, CidaSize, Offset, StrLength: integer;
pCIDA: PIDA;
pInt: ^UINT;
pOffset: PChar;
DropEffect: ^DWORD;
dropfiles: pDropFiles;
fFiles: string;
pFileList: PChar;
pFileW: PWideChar;
begin
Medium.tymed := 0;
Medium.UnkForRelease := NIL;
Medium.hGlobal := 0;
if fPIDLs.count < 2 then result := E_UNEXPECTED
//--------------------------------------------------------------------------
else if (FormatEtcIn.cfFormat = CF_HDROP) and
(FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
(FormatEtcIn.tymed and TYMED_HGLOBAL <> 0) then
begin
fFiles := '';
for i := 1 to fPIDLs.Count-1 do
AppendStr(fFiles,GetFilename(i)+#0);
AppendStr(fFiles,#0);
 
Medium.hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_ZEROINIT,
SizeOf(TDropFiles)+length(fFiles));
if (Medium.hGlobal = 0) then
result:=E_OUTOFMEMORY
else
begin
Medium.tymed := TYMED_HGLOBAL;
dropfiles := GlobalLock(Medium.hGlobal);
try
dropfiles^.pfiles := SizeOf(TDropFiles);
dropfiles^.fwide := False;
longint(pFileList) := longint(dropfiles)+SizeOf(TDropFiles);
move(fFiles[1],pFileList^,length(fFiles));
finally
GlobalUnlock(Medium.hGlobal);
end;
result := S_OK;
end;
end
//--------------------------------------------------------------------------
else if (FormatEtcIn.cfFormat = CF_FILENAMEMAP) and
(FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
(FormatEtcIn.tymed and TYMED_HGLOBAL <> 0) and
//make sure there is a Mapped Name for each filename...
(fMappedNames.Count = fPidls.Count-1) then
begin
strlength := 0;
for i := 0 to fMappedNames.Count-1 do
Inc(strlength, Length(fMappedNames[i])+1);
 
Medium.hGlobal :=
GlobalAlloc(GMEM_SHARE or GMEM_ZEROINIT, strlength+1);
if (Medium.hGlobal = 0) then
result:=E_OUTOFMEMORY
else
begin
Medium.tymed := TYMED_HGLOBAL;
pFileList := GlobalLock(Medium.hGlobal);
try
for i := 0 to fMappedNames.Count-1 do
begin
StrPCopy(pFileList,fMappedNames[i]);
Inc(pFileList, Length(fMappedNames[i])+1);
end;
pFileList^ := #0;
finally
GlobalUnlock(Medium.hGlobal);
end;
result := S_OK;
end;
end
//--------------------------------------------------------------------------
else if (FormatEtcIn.cfFormat = CF_FILENAMEMAPW) and
(FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
(FormatEtcIn.tymed and TYMED_HGLOBAL <> 0) and
//make sure there is a Mapped Name for each filename...
(fMappedNames.Count = fPidls.Count-1) then
begin
strlength := 2;
for i := 0 to fMappedNames.Count-1 do
Inc(strlength, (Length(fMappedNames[i])+1)*2);
 
Medium.hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_ZEROINIT, strlength);
if (Medium.hGlobal = 0) then
result:=E_OUTOFMEMORY
else
begin
Medium.tymed := TYMED_HGLOBAL;
pFileW := GlobalLock(Medium.hGlobal);
try
for i := 0 to fMappedNames.Count-1 do
begin
StringToWideChar(fMappedNames[i],
pFileW, (length(fMappedNames[i])+1)*2);
Inc(pFileW, Length(fMappedNames[i])+1);
end;
pFileW^ := #0;
finally
GlobalUnlock(Medium.hGlobal);
end;
result := S_OK;
end;
end
//--------------------------------------------------------------------------
else if (FormatEtcIn.cfFormat = CF_IDLIST) and
(FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
(FormatEtcIn.tymed and TYMED_HGLOBAL <> 0) then
begin
CidaSize := sizeof(UINT)*(1+fPIDLs.Count); //size of CIDA structure
MemSpace := CidaSize;
for i := 0 to fPIDLs.Count-1 do
Inc(MemSpace, Length(fPIDLs[i]));
Medium.hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_ZEROINIT, MemSpace);
 
if (Medium.hGlobal = 0) then
result := E_OUTOFMEMORY
else
begin
medium.tymed := TYMED_HGLOBAL;
pCIDA := PIDA(GlobalLock(Medium.hGlobal));
try
pCIDA^.cidl := fPIDLs.count-1; //don't count folder
pInt := @(pCIDA^.aoffset); //points to aoffset[0];
pOffset := pChar(pCIDA);
//move pOffset to point to the Folder PIDL location
inc(pOffset,CidaSize);
offset := CidaSize;
for i := 0 to fPIDLs.Count-1 do
begin
pInt^ := offset; //store 'offset' into aoffset[i]
//copy the PIDL into pOffset
Move(pointer(fPIDLs[i])^,pOffset^,length(fPIDLs[i]));
//increase 'offset' by the size of the last pidl
inc(offset,length(fPIDLs[i]));
inc(pInt); //increment the aoffset pointer
//move pOffset ready for the next PIDL
inc(pOffset,length(fPIDLs[i]));
end;
finally
GlobalUnlock(Medium.hGlobal);
end;
result := S_OK;
end;
end
//--------------------------------------------------------------------------
else if (FormatEtcIn.cfFormat = CF_PREFERREDDROPEFFECT) and
(FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
(FormatEtcIn.tymed and TYMED_HGLOBAL <> 0) then
begin
Medium.tymed := TYMED_HGLOBAL;
Medium.hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_ZEROINIT, SizeOf(DWORD));
if Medium.hGlobal = 0 then
result:=E_OUTOFMEMORY
else
begin
DropEffect := GlobalLock(Medium.hGlobal);
try
DropEffect^ := DWORD(FeedbackEffect);
finally
GlobalUnLock(Medium.hGlobal);
end;
result := S_OK;
end;
end
//--------------------------------------------------------------------------
else
result := DV_E_FORMATETC;
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
 
end.
/trunk/VCL_DRAGDROP/DropPIDLTarget.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DropPIDLTarget.pas
0,0 → 1,368
unit DropPIDLTarget;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Component Names: TDropPIDLTarget
// Module: DropPIDLTarget
// Description: Implements Dragging & Dropping of PIDLs
// TO your application from another.
// Version: 3.7
// Date: 22-JUL-1999
// Target: Win32, Delphi 3 - Delphi 5, C++ Builder 3, C++ Builder 4
// Authors: Angus Johnson, ajohnson@rpi.net.au
// Anders Melander, anders@melander.dk
// http://www.melander.dk
// Copyright © 1997-99 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
 
interface
 
uses
DropSource, DropTarget,
Classes, ActiveX, ShlObj;
 
{$include DragDrop.inc}
 
type
TDropPIDLTarget = class(TDropTarget)
private
PIDLFormatEtc,
fFileNameMapFormatEtc,
fFileNameMapWFormatEtc: TFormatEtc;
fPIDLs: TStrings; // Used internally to store PIDLs. I use strings to simplify cleanup.
fFiles: TStrings; // List of filenames (paths)
fMappedNames: TStrings;
function GetPidlCount: integer;
protected
procedure ClearData; override;
function DoGetData: boolean; override;
function HasValidFormats: boolean; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; Override;
 
function GetFolderPidl: pItemIdList;
function GetRelativeFilePidl(index: integer): pItemIdList;
function GetAbsoluteFilePidl(index: integer): pItemIdList;
function PasteFromClipboard: longint; Override;
property PidlCount: integer read GetPidlCount; //includes folder pidl in count
//If you just want the filenames (not PIDLs) then use ...
property Filenames: TStrings read fFiles;
//MappedNames is only needed if files need to be renamed after a drag op
//eg dragging from 'Recycle Bin'.
property MappedNames: TStrings read fMappedNames;
end;
 
procedure Register;
 
implementation
 
uses
DropPIDLSource,
Windows,
SysUtils,
ClipBrd;
 
procedure Register;
begin
RegisterComponents('DragDrop', [TDropPIDLTarget]);
end;
 
// -----------------------------------------------------------------------------
// Miscellaneous Functions...
// -----------------------------------------------------------------------------
 
function GetPidlsFromHGlobal(const HGlob: HGlobal; var Pidls: TStrings): boolean;
var
i: integer;
pInt: ^UINT;
pCIDA: PIDA;
begin
result := false;
pCIDA := PIDA(GlobalLock(HGlob));
try
pInt := @(pCIDA^.aoffset[0]);
for i := 0 to pCIDA^.cidl do
begin
Pidls.add(PidlToString(pointer(UINT(pCIDA)+ pInt^)));
inc(pInt);
end;
if Pidls.count > 1 then result := true;
finally
GlobalUnlock(HGlob);
end;
end;
 
{By implementing the following TStrings class, component processing is reduced.}
// -----------------------------------------------------------------------------
// TPIDLTargetStrings
// -----------------------------------------------------------------------------
 
type
TPIDLTargetStrings = class(TStrings)
private
DropPIDLTarget: TDropPIDLTarget;
protected
function Get(Index: Integer): string; override;
function GetCount: Integer; override;
procedure Put(Index: Integer; const S: string); override;
procedure PutObject(Index: Integer; AObject: TObject); override;
public
procedure Clear; override;
procedure Delete(Index: Integer); override;
procedure Insert(Index: Integer; const S: string); override;
end;
 
// -----------------------------------------------------------------------------
 
function TPIDLTargetStrings.Get(Index: Integer): string;
var
PidlStr: string;
buff: array [0..MAX_PATH] of char;
begin
with DropPIDLTarget do
begin
if (Index < 0) or (Index > fPIDLs.count-2) then
raise Exception.create('Filename index out of range');
PidlStr := JoinPidlStrings(fPIDLs[0], fPIDLs[Index+1]);
if SHGetPathFromIDList(PItemIDList(pChar(PidlStr)),buff) then
result := buff else
result := '';
end;
end;
// -----------------------------------------------------------------------------
 
function TPIDLTargetStrings.GetCount: Integer;
begin
with DropPIDLTarget do
if fPIDLs.count < 2 then
result := 0 else
result := fPIDLs.count-1;
end;
// -----------------------------------------------------------------------------
 
//Overriden abstract methods which do not need implementation...
 
procedure TPIDLTargetStrings.Put(Index: Integer; const S: string);
begin
end;
// -----------------------------------------------------------------------------
 
procedure TPIDLTargetStrings.PutObject(Index: Integer; AObject: TObject);
begin
end;
// -----------------------------------------------------------------------------
 
procedure TPIDLTargetStrings.Clear;
begin
end;
// -----------------------------------------------------------------------------
 
procedure TPIDLTargetStrings.Delete(Index: Integer);
begin
end;
// -----------------------------------------------------------------------------
 
procedure TPIDLTargetStrings.Insert(Index: Integer; const S: string);
begin
end;
 
// -----------------------------------------------------------------------------
// TDropPIDLTarget
// -----------------------------------------------------------------------------
 
constructor TDropPIDLTarget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fPIDLs := TStringList.create;
fFiles := TPIDLTargetStrings.create;
TPIDLTargetStrings(fFiles).DropPIDLTarget := self;
fMappedNames := TStringList.Create;
//SHGetMalloc(fShellMalloc);
with PIDLFormatEtc do
begin
cfFormat := CF_IDLIST;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := -1;
tymed := TYMED_HGLOBAL;
end;
with fFileNameMapFormatEtc do
begin
cfFormat := CF_FILENAMEMAP;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := -1;
tymed := TYMED_HGLOBAL;
end;
with fFileNameMapWFormatEtc do
begin
cfFormat := CF_FILENAMEMAPW;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := -1;
tymed := TYMED_HGLOBAL;
end;
end;
// -----------------------------------------------------------------------------
 
destructor TDropPIDLTarget.Destroy;
begin
fPIDLs.free;
fFiles.free;
fMappedNames.free;
inherited Destroy;
end;
// -----------------------------------------------------------------------------
 
function TDropPIDLTarget.HasValidFormats: boolean;
begin
result := (DataObject.QueryGetData(PIDLFormatEtc) = S_OK);
end;
// -----------------------------------------------------------------------------
 
procedure TDropPIDLTarget.ClearData;
begin
fPIDLs.clear;
fMappedNames.clear;
end;
// -----------------------------------------------------------------------------
 
function TDropPIDLTarget.DoGetData: boolean;
var
medium: TStgMedium;
pFilename: pChar;
pFilenameW: PWideChar;
sFilename: String;
begin
ClearData;
result := false;
 
//--------------------------------------------------------------------------
if (DataObject.GetData(PIDLFormatEtc, medium) = S_OK) then
begin
try
if (medium.tymed <> TYMED_HGLOBAL) then exit;
result := GetPidlsFromHGlobal(medium.HGlobal,fPIDLs);
finally
ReleaseStgMedium(medium);
end;
 
if not result then exit;
//Now check for FileNameMapping as well ...
//--------------------------------------------------------------------------
if (DataObject.GetData(fFileNameMapFormatEtc, medium) = S_OK) then
begin
try
if (medium.tymed = TYMED_HGLOBAL) then
begin
pFilename := GlobalLock(medium.HGlobal);
try
while true do
begin
sFilename := pFilename;
if sFilename = '' then break;
fMappedNames.add(sFilename);
inc(pFilename, length(sFilename)+1);
end;
if Filenames.count <> fMappedNames.count then
fMappedNames.clear;
finally
GlobalUnlock(medium.HGlobal);
end;
end;
finally
ReleaseStgMedium(medium);
end;
end
//WideChar support for WinNT...
else if (DataObject.GetData(fFileNameMapWFormatEtc, medium) = S_OK) then
try
if (medium.tymed = TYMED_HGLOBAL) then
begin
pFilenameW := GlobalLock(medium.HGlobal);
try
while true do
begin
sFilename := WideCharToString(pFilenameW);
if sFilename = '' then break;
fMappedNames.add(sFilename);
inc(pFilenameW, length(sFilename)+1);
end;
if fFiles.count <> fMappedNames.count then
fMappedNames.clear;
finally
GlobalUnlock(medium.HGlobal);
end;
end;
finally
ReleaseStgMedium(medium);
end;
 
end;
end;
// -----------------------------------------------------------------------------
 
//Note: It is the component user's responsibility to cleanup
//the returned PIDLs from the following 3 methods.
//Use - CoTaskMemFree() - to free the PIDLs.
function TDropPIDLTarget.GetFolderPidl: pItemIdList;
begin
result :=nil;
if fPIDLs.count = 0 then exit;
result := ShellMalloc.alloc(length(fPIDLs[0]));
if result <> nil then
move(pChar(fPIDLs[0])^,result^,length(fPIDLs[0]));
end;
// -----------------------------------------------------------------------------
 
function TDropPIDLTarget.GetRelativeFilePidl(index: integer): pItemIdList;
begin
result :=nil;
if (index < 1) or (index >= fPIDLs.count) then exit;
result := ShellMalloc.alloc(length(fPIDLs[index]));
if result <> nil then
move(pChar(fPIDLs[index])^,result^,length(fPIDLs[index]));
end;
// -----------------------------------------------------------------------------
 
function TDropPIDLTarget.GetAbsoluteFilePidl(index: integer): pItemIdList;
var
s: string;
begin
result :=nil;
if (index < 1) or (index >= fPIDLs.count) then exit;
s := JoinPidlStrings(fPIDLs[0], fPIDLs[index]);
result := ShellMalloc.alloc(length(s));
if result <> nil then
move(pChar(s)^,result^,length(s));
end;
// -----------------------------------------------------------------------------
 
function TDropPIDLTarget.PasteFromClipboard: longint;
var
Global: HGlobal;
Preferred: longint;
begin
result := DROPEFFECT_NONE;
if not ClipBoard.HasFormat(CF_IDLIST) then exit;
Global := Clipboard.GetAsHandle(CF_IDLIST);
fPIDLs.clear;
if not GetPidlsFromHGlobal(Global,fPidls) then exit;
Preferred := inherited PasteFromClipboard;
//if no Preferred DropEffect then return copy else return Preferred ...
if (Preferred = DROPEFFECT_NONE) then
result := DROPEFFECT_COPY else
result := Preferred;
end;
// -----------------------------------------------------------------------------
 
function TDropPIDLTarget.GetPidlCount: integer;
begin
result := fPidls.count; //Note: includes folder pidl in count!
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
 
end.
/trunk/VCL_DRAGDROP/DropSource.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DropSource.pas
0,0 → 1,1301
unit DropSource;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Module: DropSource
// Description: Implements Dragging & Dropping of data
// FROM your application to another.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
// General changes:
// - Some component glyphs has changed.
//
// TDropSource changes:
// - CutToClipboard and CopyToClipboard now uses OleSetClipboard.
// This means that descendant classes no longer needs to override the
// CutOrCopyToClipboard method.
// - New OnGetData event.
// - Changed to use new V4 architecture:
// * All clipboard format support has been removed from TDropSource, it has
// been renamed to TCustomDropSource and the old TDropSource has been
// modified to descend from TCustomDropSource and has moved to the
// DropSource3 unit. TDropSource is now supported for backwards
// compatibility only and will be removed in a future version.
// * A new TCustomDropMultiSource, derived from TCustomDropSource, uses the
// new architecture (with TClipboardFormat and TDataFormat) and is the new
// base class for all the drop source components.
// - TInterfacedComponent moved to DragDrop unit.
// -----------------------------------------------------------------------------
// TODO -oanme -cCheckItOut : OleQueryLinkFromData
// TODO -oanme -cDocumentation : CutToClipboard and CopyToClipboard alters the value of PreferredDropEffect.
// TODO -oanme -cDocumentation : Clipboard must be flushed or emptied manually after CutToClipboard and CopyToClipboard. Automatic flush is not guaranteed.
// TODO -oanme -cDocumentation : Delete-on-paste. Why and How.
// TODO -oanme -cDocumentation : Optimized move. Why and How.
// TODO -oanme -cDocumentation : OnPaste event is only fired if target sets the "Paste Succeeded" clipboard format. Explorer does this for delete-on-paste move operations.
// TODO -oanme -cDocumentation : DragDetectPlus. Why and How.
// -----------------------------------------------------------------------------
 
interface
 
uses
DragDrop,
DragDropFormats,
ActiveX,
Controls,
Windows,
Classes;
 
{$include DragDrop.inc}
 
type
TDragResult = (drDropCopy, drDropMove, drDropLink, drCancel,
drOutMemory, drAsync, drUnknown);
 
TDropEvent = procedure(Sender: TObject; DragType: TDragType;
var ContinueDrop: Boolean) of object;
 
//: TAfterDropEvent is fired after the target has finished processing a
// successfull drop.
// The Optimized parameter is True if the target either performed an operation
// other than a move or performed an "optimized move". In either cases, the
// source isn't required to delete the source data.
// If the Optimized parameter is False, the target performed an "unoptimized
// move" operation and the source is required to delete the source data to
// complete the move operation.
TAfterDropEvent = procedure(Sender: TObject; DragResult: TDragResult;
Optimized: Boolean) of object;
 
TFeedbackEvent = procedure(Sender: TObject; Effect: LongInt;
var UseDefaultCursors: Boolean) of object;
 
//: The TDropDataEvent event is fired when the target requests data from the
// drop source or offers data to the drop source.
// The Handled flag should be set if the event handler satisfied the request.
TDropDataEvent = procedure(Sender: TObject; const FormatEtc: TFormatEtc;
out Medium: TStgMedium; var Handled: Boolean) of object;
 
//: TPasteEvent is fired when the target sends a "Paste Succeeded" value
// back to the drop source after a clipboard transfer.
// The DeleteOnPaste parameter is True if the source is required to delete
// the source data. This will only occur after a CutToClipboard operation
// (corresponds to a move drag/drop).
TPasteEvent = procedure(Sender: TObject; Action: TDragResult;
DeleteOnPaste: boolean) of object;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomDropSource
//
////////////////////////////////////////////////////////////////////////////////
// Abstract base class for all Drop Source components.
// Implements the IDropSource and IDataObject interfaces.
////////////////////////////////////////////////////////////////////////////////
TCustomDropSource = class(TDragDropComponent, IDropSource, IDataObject,
IAsyncOperation)
private
FDragTypes: TDragTypes;
FFeedbackEffect: LongInt;
// Events...
FOnDrop: TDropEvent;
FOnAfterDrop: TAfterDropEvent;
FOnFeedback: TFeedBackEvent;
FOnGetData: TDropDataEvent;
FOnSetData: TDropDataEvent;
FOnPaste: TPasteEvent;
// Drag images...
FImages: TImageList;
FShowImage: boolean;
FImageIndex: integer;
FImageHotSpot: TPoint;
FDragSourceHelper: IDragSourceHelper;
// Async transfer...
FAllowAsync: boolean;
FRequestAsync: boolean;
FIsAsync: boolean;
 
protected
property FeedbackEffect: LongInt read FFeedbackEffect write FFeedbackEffect;
 
// IDropSource implementation
function QueryContinueDrag(fEscapePressed: bool;
grfKeyState: LongInt): HRESULT; stdcall;
function GiveFeedback(dwEffect: LongInt): HRESULT; stdcall;
 
// IDataObject implementation
function GetData(const FormatEtcIn: TFormatEtc;
out Medium: TStgMedium):HRESULT; stdcall;
function GetDataHere(const FormatEtc: TFormatEtc;
out Medium: TStgMedium):HRESULT; stdcall;
function QueryGetData(const FormatEtc: TFormatEtc): HRESULT; stdcall;
function GetCanonicalFormatEtc(const FormatEtc: TFormatEtc;
out FormatEtcout: TFormatEtc): HRESULT; stdcall;
function SetData(const FormatEtc: TFormatEtc; var Medium: TStgMedium;
fRelease: Bool): HRESULT; stdcall;
function EnumFormatEtc(dwDirection: LongInt;
out EnumFormatEtc: IEnumFormatEtc): HRESULT; stdcall;
function dAdvise(const FormatEtc: TFormatEtc; advf: LongInt;
const advsink: IAdviseSink; out dwConnection: LongInt): HRESULT; stdcall;
function dUnadvise(dwConnection: LongInt): HRESULT; stdcall;
function EnumdAdvise(out EnumAdvise: IEnumStatData): HRESULT; stdcall;
 
// IAsyncOperation implementation
function EndOperation(hResult: HRESULT; const pbcReserved: IBindCtx;
dwEffects: Cardinal): HRESULT; stdcall;
function GetAsyncMode(out fDoOpAsync: LongBool): HRESULT; stdcall;
function InOperation(out pfInAsyncOp: LongBool): HRESULT; stdcall;
function SetAsyncMode(fDoOpAsync: LongBool): HRESULT; stdcall;
function StartOperation(const pbcReserved: IBindCtx): HRESULT; stdcall;
 
// Abstract methods
function DoGetData(const FormatEtcIn: TFormatEtc;
out Medium: TStgMedium): HRESULT; virtual; abstract;
function DoSetData(const FormatEtc: TFormatEtc;
var Medium: TStgMedium): HRESULT; virtual;
function HasFormat(const FormatEtc: TFormatEtc): boolean; virtual; abstract;
function GetEnumFormatEtc(dwDirection: LongInt): IEnumFormatEtc; virtual; abstract;
 
// Data format event sink
procedure DataChanging(Sender: TObject); virtual;
 
// Clipboard
function CutOrCopyToClipboard: boolean; virtual;
procedure DoOnPaste(Action: TDragResult; DeleteOnPaste: boolean); virtual;
 
// Property access
procedure SetShowImage(Value: boolean);
procedure SetImages(const Value: TImageList);
procedure SetImageIndex(const Value: integer);
procedure SetPoint(Index: integer; Value: integer);
function GetPoint(Index: integer): integer;
function GetPerformedDropEffect: longInt; virtual;
function GetLogicalPerformedDropEffect: longInt; virtual;
procedure SetPerformedDropEffect(const Value: longInt); virtual;
function GetPreferredDropEffect: longInt; virtual;
procedure SetPreferredDropEffect(const Value: longInt); virtual;
function GetInShellDragLoop: boolean; virtual;
function GetTargetCLSID: TCLSID; virtual;
procedure SetInShellDragLoop(const Value: boolean); virtual;
function GetLiveDataOnClipboard: boolean;
procedure SetAllowAsync(const Value: boolean);
 
// Component management
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
 
property DragSourceHelper: IDragSourceHelper read FDragSourceHelper;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function Execute: TDragResult; virtual;
function CutToClipboard: boolean; virtual;
function CopyToClipboard: boolean; virtual;
procedure FlushClipboard; virtual;
procedure EmptyClipboard; virtual;
 
property PreferredDropEffect: longInt read GetPreferredDropEffect
write SetPreferredDropEffect;
property PerformedDropEffect: longInt read GetPerformedDropEffect
write SetPerformedDropEffect;
property LogicalPerformedDropEffect: longInt read GetLogicalPerformedDropEffect;
property InShellDragLoop: boolean read GetInShellDragLoop
write SetInShellDragLoop;
property TargetCLSID: TCLSID read GetTargetCLSID;
property LiveDataOnClipboard: boolean read GetLiveDataOnClipboard;
property AsyncTransfer: boolean read FIsAsync;
 
published
property DragTypes: TDragTypes read FDragTypes write FDragTypes;
// Events
property OnFeedback: TFeedbackEvent read FOnFeedback write FOnFeedback;
property OnDrop: TDropEvent read FOnDrop write FOnDrop;
property OnAfterDrop: TAfterDropEvent read FOnAfterDrop write FOnAfterDrop;
property OnGetData: TDropDataEvent read FOnGetData write FOnGetData;
property OnSetData: TDropDataEvent read FOnSetData write FOnSetData;
property OnPaste: TPasteEvent read FOnPaste write FOnPaste;
 
// Drag Images...
property Images: TImageList read FImages write SetImages;
property ImageIndex: integer read FImageIndex write SetImageIndex;
property ShowImage: boolean read FShowImage write SetShowImage;
property ImageHotSpotX: integer index 1 read GetPoint write SetPoint;
property ImageHotSpotY: integer index 2 read GetPoint write SetPoint;
// Async transfer...
property AllowAsyncTransfer: boolean read FAllowAsync write SetAllowAsync;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomDropMultiSource
//
////////////////////////////////////////////////////////////////////////////////
// Drop target base class which can accept multiple formats.
////////////////////////////////////////////////////////////////////////////////
TCustomDropMultiSource = class(TCustomDropSource)
private
FFeedbackDataFormat: TFeedbackDataFormat;
FRawDataFormat: TRawDataFormat;
 
protected
function DoGetData(const FormatEtcIn: TFormatEtc;
out Medium: TStgMedium):HRESULT; override;
function DoSetData(const FormatEtc: TFormatEtc;
var Medium: TStgMedium): HRESULT; override;
function HasFormat(const FormatEtc: TFormatEtc): boolean; override;
function GetEnumFormatEtc(dwDirection: LongInt): IEnumFormatEtc; override;
 
function GetPerformedDropEffect: longInt; override;
function GetLogicalPerformedDropEffect: longInt; override;
function GetPreferredDropEffect: longInt; override;
procedure SetPerformedDropEffect(const Value: longInt); override;
procedure SetPreferredDropEffect(const Value: longInt); override;
function GetInShellDragLoop: boolean; override;
procedure SetInShellDragLoop(const Value: boolean); override;
function GetTargetCLSID: TCLSID; override;
 
procedure DoOnSetData(DataFormat: TCustomDataFormat;
ClipboardFormat: TClipboardFormat);
 
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property DataFormats;
// TODO : Add support for delayed rendering with OnRenderData event.
published
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropEmptySource
//
////////////////////////////////////////////////////////////////////////////////
// Do-nothing source for use with TDataFormatAdapter and such
////////////////////////////////////////////////////////////////////////////////
TDropEmptySource = class(TCustomDropMultiSource);
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropSourceThread
//
////////////////////////////////////////////////////////////////////////////////
// Executes a drop source operation from a thread.
// TDropSourceThread is an alternative to the Windows 2000 Asynchronous Data
// Transfer support.
////////////////////////////////////////////////////////////////////////////////
type
TDropSourceThread = class(TThread)
private
FDropSource: TCustomDropSource;
FDragResult: TDragResult;
protected
procedure Execute; override;
public
constructor Create(ADropSource: TCustomDropSource; AFreeOnTerminate: Boolean);
property DragResult: TDragResult read FDragResult;
property Terminated;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// Utility functions
//
////////////////////////////////////////////////////////////////////////////////
function DropEffectToDragResult(DropEffect: longInt): TDragResult;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
 
(*******************************************************************************
**
** IMPLEMENTATION
**
*******************************************************************************)
implementation
 
uses
CommCtrl,
ComObj,
Graphics;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDropEmptySource]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Utility functions
//
////////////////////////////////////////////////////////////////////////////////
function DropEffectToDragResult(DropEffect: longInt): TDragResult;
begin
case DropEffect of
DROPEFFECT_NONE:
Result := drCancel;
DROPEFFECT_COPY:
Result := drDropCopy;
DROPEFFECT_MOVE:
Result := drDropMove;
DROPEFFECT_LINK:
Result := drDropLink;
else
Result := drUnknown; // This is probably an error condition
end;
end;
 
// -----------------------------------------------------------------------------
// TCustomDropSource
// -----------------------------------------------------------------------------
 
constructor TCustomDropSource.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
DragTypes := [dtCopy]; //default to Copy.
 
// Note: Normally we would call _AddRef or coLockObjectExternal(Self) here to
// make sure that the component wasn't deleted prematurely (e.g. after a call
// to RegisterDragDrop), but since our ancestor class TInterfacedComponent
// disables reference counting, we do not need to do so.
 
FImageHotSpot := Point(16,16);
FImages := nil;
end;
 
destructor TCustomDropSource.Destroy;
begin
// TODO -oanme -cImprovement : Maybe FlushClipboard would be more appropiate?
EmptyClipboard;
inherited Destroy;
end;
 
// -----------------------------------------------------------------------------
 
function TCustomDropSource.GetCanonicalFormatEtc(const FormatEtc: TFormatEtc;
out FormatEtcout: TFormatEtc): HRESULT;
begin
Result := DATA_S_SAMEFORMATETC;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.SetData(const FormatEtc: TFormatEtc;
var Medium: TStgMedium; fRelease: Bool): HRESULT;
begin
// Warning: Ordinarily it would be much more efficient to just call
// HasFormat(FormatEtc) to determine if we support the given format, but
// because we have to able to accept *all* data formats, even unknown ones, in
// order to support the Windows 2000 drag helper functionality, we can't
// reject any formats here. Instead we pass the request on to DoSetData and
// let it worry about the details.
 
// if (HasFormat(FormatEtc)) then
// begin
try
Result := DoSetData(FormatEtc, Medium);
finally
if (fRelease) then
ReleaseStgMedium(Medium);
end;
// end else
// Result:= DV_E_FORMATETC;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.DAdvise(const FormatEtc: TFormatEtc; advf: LongInt;
const advSink: IAdviseSink; out dwConnection: LongInt): HRESULT;
begin
Result := OLE_E_ADVISENOTSUPPORTED;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.DUnadvise(dwConnection: LongInt): HRESULT;
begin
Result := OLE_E_ADVISENOTSUPPORTED;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.EnumDAdvise(out EnumAdvise: IEnumStatData): HRESULT;
begin
Result := OLE_E_ADVISENOTSUPPORTED;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.GetData(const FormatEtcIn: TFormatEtc;
out Medium: TStgMedium):HRESULT; stdcall;
var
Handled: boolean;
begin
Handled := False;
if (Assigned(FOnGetData)) then
// Fire event to ask user for data.
FOnGetData(Self, FormatEtcIn, Medium, Handled);
 
// If user provided data, there is no need to call descendant for it.
if (Handled) then
Result := S_OK
else if (HasFormat(FormatEtcIn)) then
// Call descendant class to get data.
Result := DoGetData(FormatEtcIn, Medium)
else
Result:= DV_E_FORMATETC;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.GetDataHere(const FormatEtc: TFormatEtc;
out Medium: TStgMedium):HRESULT; stdcall;
begin
Result := E_NOTIMPL;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.QueryGetData(const FormatEtc: TFormatEtc): HRESULT; stdcall;
begin
if (HasFormat(FormatEtc)) then
Result:= S_OK
else
Result:= DV_E_FORMATETC;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.EnumFormatEtc(dwDirection: LongInt;
out EnumFormatEtc:IEnumFormatEtc): HRESULT; stdcall;
begin
EnumFormatEtc := GetEnumFormatEtc(dwDirection);
if (EnumFormatEtc <> nil) then
Result := S_OK
else
Result := E_NOTIMPL;
end;
// -----------------------------------------------------------------------------
 
// Implements IDropSource.QueryContinueDrag
function TCustomDropSource.QueryContinueDrag(fEscapePressed: bool;
grfKeyState: LongInt): HRESULT; stdcall;
var
ContinueDrop : Boolean;
DragType : TDragType;
begin
if FEscapePressed then
Result := DRAGDROP_S_CANCEL
// Allow drag and drop with either mouse buttons.
else if (grfKeyState and (MK_LBUTTON or MK_RBUTTON) = 0) then
begin
ContinueDrop := DropEffectToDragType(FeedbackEffect, DragType) and
(DragType in DragTypes);
 
InShellDragLoop := False;
 
// If a valid drop then do OnDrop event if assigned...
if ContinueDrop and Assigned(OnDrop) then
OnDrop(Self, DragType, ContinueDrop);
 
if ContinueDrop then
Result := DRAGDROP_S_DROP
else
Result := DRAGDROP_S_CANCEL;
end else
Result := S_OK;
end;
// -----------------------------------------------------------------------------
 
// Implements IDropSource.GiveFeedback
function TCustomDropSource.GiveFeedback(dwEffect: LongInt): HRESULT; stdcall;
var
UseDefaultCursors: Boolean;
begin
UseDefaultCursors := True;
FeedbackEffect := dwEffect;
if Assigned(OnFeedback) then
OnFeedback(Self, dwEffect, UseDefaultCursors);
if UseDefaultCursors then
Result := DRAGDROP_S_USEDEFAULTCURSORS
else
Result := S_OK;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.DoSetData(const FormatEtc: TFormatEtc;
var Medium: TStgMedium): HRESULT;
var
Handled: boolean;
begin
Result := E_NOTIMPL;
if (Assigned(FOnSetData)) then
begin
Handled := False;
// Fire event to ask user to handle data.
FOnSetData(Self, FormatEtc, Medium, Handled);
if (Handled) then
Result := S_OK;
end;
end;
// -----------------------------------------------------------------------------
 
procedure TCustomDropSource.SetAllowAsync(const Value: boolean);
begin
if (FAllowAsync <> Value) then
begin
FAllowAsync := Value;
if (not FAllowAsync) then
begin
FRequestAsync := False;
FIsAsync := False;
end;
end;
end;
 
function TCustomDropSource.GetAsyncMode(out fDoOpAsync: LongBool): HRESULT;
begin
fDoOpAsync := FRequestAsync;
Result := S_OK;
end;
 
function TCustomDropSource.SetAsyncMode(fDoOpAsync: LongBool): HRESULT;
begin
if (FAllowAsync) then
begin
FRequestAsync := fDoOpAsync;
Result := S_OK;
end else
Result := E_NOTIMPL;
end;
 
function TCustomDropSource.InOperation(out pfInAsyncOp: LongBool): HRESULT;
begin
pfInAsyncOp := FIsAsync;
Result := S_OK;
end;
 
function TCustomDropSource.StartOperation(const pbcReserved: IBindCtx): HRESULT;
begin
if (FRequestAsync) then
begin
FIsAsync := True;
Result := S_OK;
end else
Result := E_NOTIMPL;
end;
 
function TCustomDropSource.EndOperation(hResult: HRESULT;
const pbcReserved: IBindCtx; dwEffects: Cardinal): HRESULT;
var
DropResult: TDragResult;
begin
if (FIsAsync) then
begin
FIsAsync := False;
if (Assigned(FOnAfterDrop)) then
begin
if (Succeeded(hResult)) then
DropResult := DropEffectToDragResult(dwEffects and DragTypesToDropEffect(FDragTypes))
else
DropResult := drUnknown;
FOnAfterDrop(Self, DropResult,
(DropResult <> drDropMove) or (PerformedDropEffect <> DROPEFFECT_MOVE));
end;
Result := S_OK;
end else
Result := E_FAIL;
end;
 
function TCustomDropSource.Execute: TDragResult;
 
function GetRGBColor(Value: TColor): DWORD;
begin
Result := ColorToRGB(Value);
case Result of
clNone: Result := CLR_NONE;
clDefault: Result := CLR_DEFAULT;
end;
end;
 
var
DropResult: HRESULT;
AllowedEffects,
DropEffect: longint;
IsDraggingImage: boolean;
shDragImage: TSHDRAGIMAGE;
shDragBitmap: TBitmap;
begin
shDragBitmap := nil;
 
AllowedEffects := DragTypesToDropEffect(FDragTypes);
 
// Reset the "Performed Drop Effect" value. If it is supported by the target,
// the target will set it to the desired value when the drop occurs.
PerformedDropEffect := -1;
 
if (FShowImage) then
begin
// Attempt to create Drag Drop helper object.
// At present this is only supported on Windows 2000. If the object can't be
// created, we fall back to the old image list based method (which only
// works within the application).
CoCreateInstance(CLSID_DragDropHelper, nil, CLSCTX_INPROC_SERVER,
IDragSourceHelper, FDragSourceHelper);
 
// Display drag image.
if (FDragSourceHelper <> nil) then
begin
IsDraggingImage := True;
shDragBitmap := TBitmap.Create;
shDragBitmap.PixelFormat := pfDevice;
FImages.GetBitmap(ImageIndex, shDragBitmap);
shDragImage.hbmpDragImage := shDragBitmap.Handle;
shDragImage.sizeDragImage.cx := shDragBitmap.Width;
shDragImage.sizeDragImage.cy := shDragBitmap.Height;
shDragImage.crColorKey := GetRGBColor(FImages.BkColor);
shDragImage.ptOffset.x := ImageHotSpotX;
shDragImage.ptOffset.y := ImageHotSpotY;
if Failed(FDragSourceHelper.InitializeFromBitmap(shDragImage, Self)) then
begin
FDragSourceHelper := nil;
shDragBitmap.Free;
shDragBitmap := nil;
end;
end else
IsDraggingImage := False;
 
// Fall back to image list drag image if platform doesn't support
// IDragSourceHelper or if we "just" failed to initialize properly.
if (FDragSourceHelper = nil) then
begin
IsDraggingImage := ImageList_BeginDrag(FImages.Handle, FImageIndex,
FImageHotSpot.X, FImageHotSpot.Y);
end;
end else
IsDraggingImage := False;
 
if (AllowAsyncTransfer) then
SetAsyncMode(True);
 
try
InShellDragLoop := True;
try
DropResult := DoDragDrop(Self, Self, AllowedEffects, DropEffect);
finally
// InShellDragLoop is also reset in TCustomDropSource.QueryContinueDrag.
// This is just to make absolutely sure that it is reset (actually no big
// deal if it isn't).
InShellDragLoop := False;
end;
 
finally
if IsDraggingImage then
begin
if (FDragSourceHelper <> nil) then
begin
FDragSourceHelper := nil;
shDragBitmap.Free;
end else
ImageList_EndDrag;
end;
end;
 
case DropResult of
DRAGDROP_S_DROP:
(*
** Special handling of "optimized move".
** If PerformedDropEffect has been set by the target to DROPEFFECT_MOVE
** and the drop effect returned from DoDragDrop is different from
** DROPEFFECT_MOVE, then an optimized move was performed.
** Note: This is different from how MSDN states that an optimized move is
** signalled, but matches how Windows 2000 signals an optimized move.
**
** On Windows 2000 an optimized move is signalled by:
** 1) Returning DRAGDROP_S_DROP from DoDragDrop.
** 2) Setting drop effect to DROPEFFECT_NONE.
** 3) Setting the "Performed Dropeffect" format to DROPEFFECT_MOVE.
**
** On previous version of Windows, an optimized move is signalled by:
** 1) Returning DRAGDROP_S_DROP from DoDragDrop.
** 2) Setting drop effect to DROPEFFECT_MOVE.
** 3) Setting the "Performed Dropeffect" format to DROPEFFECT_NONE.
**
** The documentation states that an optimized move is signalled by:
** 1) Returning DRAGDROP_S_DROP from DoDragDrop.
** 2) Setting drop effect to DROPEFFECT_NONE or DROPEFFECT_COPY.
** 3) Setting the "Performed Dropeffect" format to DROPEFFECT_NONE.
*)
if (LogicalPerformedDropEffect = DROPEFFECT_MOVE) or
((DropEffect <> DROPEFFECT_MOVE) and (PerformedDropEffect = DROPEFFECT_MOVE)) then
Result := drDropMove
else
Result := DropEffectToDragResult(DropEffect and AllowedEffects);
DRAGDROP_S_CANCEL:
Result := drCancel;
E_OUTOFMEMORY:
Result := drOutMemory;
else
// This should never happen!
Result := drUnknown;
end;
 
// Reset PerformedDropEffect if the target didn't set it.
if (PerformedDropEffect = -1) then
PerformedDropEffect := DROPEFFECT_NONE;
 
// Fire OnAfterDrop event unless we are in the middle of an async data
// transfer.
if (not AsyncTransfer) and (Assigned(FOnAfterDrop)) then
FOnAfterDrop(Self, Result,
(Result = drDropMove) and
((DropEffect <> DROPEFFECT_MOVE) or (PerformedDropEffect <> DROPEFFECT_MOVE)));
 
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.GetPerformedDropEffect: longInt;
begin
Result := DROPEFFECT_NONE;
end;
 
function TCustomDropSource.GetLogicalPerformedDropEffect: longInt;
begin
Result := DROPEFFECT_NONE;
end;
 
procedure TCustomDropSource.SetPerformedDropEffect(const Value: longInt);
begin
// Not implemented in base class
end;
 
function TCustomDropSource.GetPreferredDropEffect: longInt;
begin
Result := DROPEFFECT_NONE;
end;
 
procedure TCustomDropSource.SetPreferredDropEffect(const Value: longInt);
begin
// Not implemented in base class
end;
 
function TCustomDropSource.GetInShellDragLoop: boolean;
begin
Result := False;
end;
 
function TCustomDropSource.GetTargetCLSID: TCLSID;
begin
Result := GUID_NULL;
end;
 
procedure TCustomDropSource.SetInShellDragLoop(const Value: boolean);
begin
// Not implemented in base class
end;
 
procedure TCustomDropSource.DataChanging(Sender: TObject);
begin
// Data is changing - Flush clipboard to freeze the contents
FlushClipboard;
end;
 
procedure TCustomDropSource.FlushClipboard;
begin
// If we have live data on the clipboard...
if (LiveDataOnClipboard) then
// ...we force the clipboard to make a static copy of the data
// before the data changes.
OleCheck(OleFlushClipboard);
end;
 
procedure TCustomDropSource.EmptyClipboard;
begin
// If we have live data on the clipboard...
if (LiveDataOnClipboard) then
// ...we empty the clipboard.
OleCheck(OleSetClipboard(nil));
end;
 
function TCustomDropSource.CutToClipboard: boolean;
begin
PreferredDropEffect := DROPEFFECT_MOVE;
// Copy data to clipboard
Result := CutOrCopyToClipboard;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.CopyToClipboard: boolean;
begin
PreferredDropEffect := DROPEFFECT_COPY;
// Copy data to clipboard
Result := CutOrCopyToClipboard;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.CutOrCopyToClipboard: boolean;
begin
Result := (OleSetClipboard(Self as IDataObject) = S_OK);
end;
 
procedure TCustomDropSource.DoOnPaste(Action: TDragResult; DeleteOnPaste: boolean);
begin
if (Assigned(FOnPaste)) then
FOnPaste(Self, Action, DeleteOnPaste);
end;
 
function TCustomDropSource.GetLiveDataOnClipboard: boolean;
begin
Result := (OleIsCurrentClipboard(Self as IDataObject) = S_OK);
end;
 
// -----------------------------------------------------------------------------
 
procedure TCustomDropSource.SetImages(const Value: TImageList);
begin
if (FImages = Value) then
exit;
FImages := Value;
if (csLoading in ComponentState) then
exit;
 
{ DONE -oanme : Shouldn't FShowImage and FImageIndex only be reset if FImages = nil? }
if (FImages = nil) or (FImageIndex >= FImages.Count) then
FImageIndex := 0;
FShowImage := FShowImage and (FImages <> nil) and (FImages.Count > 0);
end;
// -----------------------------------------------------------------------------
 
procedure TCustomDropSource.SetImageIndex(const Value: integer);
begin
if (csLoading in ComponentState) then
begin
FImageIndex := Value;
exit;
end;
 
if (Value < 0) or (FImages.Count = 0) or (FImages = nil) then
begin
FImageIndex := 0;
FShowImage := False;
end else
if (Value < FImages.Count) then
FImageIndex := Value;
end;
// -----------------------------------------------------------------------------
 
procedure TCustomDropSource.SetPoint(Index: integer; Value: integer);
begin
if (Index = 1) then
FImageHotSpot.x := Value
else
FImageHotSpot.y := Value;
end;
// -----------------------------------------------------------------------------
 
function TCustomDropSource.GetPoint(Index: integer): integer;
begin
if (Index = 1) then
Result := FImageHotSpot.x
else
Result := FImageHotSpot.y;
end;
// -----------------------------------------------------------------------------
 
procedure TCustomDropSource.SetShowImage(Value: boolean);
begin
FShowImage := Value;
if (csLoading in ComponentState) then
exit;
if (FImages = nil) then
FShowImage := False;
end;
// -----------------------------------------------------------------------------
 
procedure TCustomDropSource.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FImages) then
Images := nil;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TEnumFormatEtc
//
////////////////////////////////////////////////////////////////////////////////
// Format enumerator used by TCustomDropMultiTarget.
////////////////////////////////////////////////////////////////////////////////
type
TEnumFormatEtc = class(TInterfacedObject, IEnumFormatEtc)
private
FFormats : TClipboardFormats;
FIndex : integer;
protected
constructor CreateClone(AFormats: TClipboardFormats; AIndex: Integer);
public
constructor Create(AFormats: TDataFormats; Direction: TDataDirection);
{ IEnumFormatEtc implentation }
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;
end;
 
constructor TEnumFormatEtc.Create(AFormats: TDataFormats; Direction: TDataDirection);
var
i, j : integer;
begin
inherited Create;
FFormats := TClipboardFormats.Create(nil, False);
FIndex := 0;
for i := 0 to AFormats.Count-1 do
for j := 0 to AFormats[i].CompatibleFormats.Count-1 do
if (Direction in AFormats[i].CompatibleFormats[j].DataDirections) and
(not FFormats.Contain(TClipboardFormatClass(AFormats[i].CompatibleFormats[j].ClassType))) then
FFormats.Add(AFormats[i].CompatibleFormats[j]);
end;
 
constructor TEnumFormatEtc.CreateClone(AFormats: TClipboardFormats; AIndex: Integer);
var
i : integer;
begin
inherited Create;
FFormats := TClipboardFormats.Create(nil, False);
FIndex := AIndex;
for i := 0 to AFormats.Count-1 do
FFormats.Add(AFormats[i]);
end;
 
function TEnumFormatEtc.Next(Celt: LongInt; out Elt;
pCeltFetched: pLongInt): HRESULT;
var
i : integer;
FormatEtc : PFormatEtc;
begin
i := 0;
FormatEtc := PFormatEtc(@Elt);
while (i < Celt) and (FIndex < FFormats.Count) do
begin
FormatEtc^ := FFormats[FIndex].FormatEtc;
Inc(FormatEtc);
Inc(i);
Inc(FIndex);
end;
 
if (pCeltFetched <> nil) then
pCeltFetched^ := i;
 
if (i = Celt) then
Result := S_OK
else
Result := S_FALSE;
end;
 
function TEnumFormatEtc.Skip(Celt: LongInt): HRESULT;
begin
if (FIndex + Celt <= FFormats.Count) then
begin
inc(FIndex, Celt);
Result := S_OK;
end else
begin
FIndex := FFormats.Count;
Result := S_FALSE;
end;
end;
 
function TEnumFormatEtc.Reset: HRESULT;
begin
FIndex := 0;
Result := S_OK;
end;
 
function TEnumFormatEtc.Clone(out Enum: IEnumFormatEtc): HRESULT;
begin
Enum := TEnumFormatEtc.CreateClone(FFormats, FIndex);
Result := S_OK;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomDropMultiSource
//
////////////////////////////////////////////////////////////////////////////////
type
TSourceDataFormats = class(TDataFormats)
public
function Add(DataFormat: TCustomDataFormat): integer; override;
end;
 
function TSourceDataFormats.Add(DataFormat: TCustomDataFormat): integer;
begin
Result := inherited Add(DataFormat);
// Set up change notification so drop source can flush clipboard if data changes.
DataFormat.OnChanging := TCustomDropMultiSource(DataFormat.Owner).DataChanging;
end;
 
constructor TCustomDropMultiSource.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FDataFormats := TSourceDataFormats.Create;
FFeedbackDataFormat := TFeedbackDataFormat.Create(Self);
FRawDataFormat := TRawDataFormat.Create(Self);
end;
 
destructor TCustomDropMultiSource.Destroy;
var
i : integer;
begin
EmptyClipboard;
// Delete all target formats owned by the object
for i := FDataFormats.Count-1 downto 0 do
FDataFormats[i].Free;
FDataFormats.Free;
inherited Destroy;
end;
 
function TCustomDropMultiSource.DoGetData(const FormatEtcIn: TFormatEtc;
out Medium: TStgMedium): HRESULT;
var
i, j: integer;
DF: TCustomDataFormat;
CF: TClipboardFormat;
begin
// TODO : Add support for delayed rendering with OnRenderData event.
Medium.tymed := 0;
Medium.UnkForRelease := nil;
Medium.hGlobal := 0;
 
Result := DV_E_FORMATETC;
 
(*
** Loop through all data formats associated with this drop source to find one
** which can offer the clipboard format requested by the target.
*)
for i := 0 to DataFormats.Count-1 do
begin
DF := DataFormats[i];
 
// Ignore empty data formats.
if (not DF.HasData) then
continue;
 
(*
** Loop through all the data format's supported clipboard formats to find
** one which contains data and can provide it in the format requested by the
** target.
*)
for j := 0 to DF.CompatibleFormats.Count-1 do
begin
CF := DF.CompatibleFormats[j];
(*
** 1) Determine if the clipboard format supports the format requested by
** the target.
** 2) Transfer data from the data format object to the clipboard format
** object.
** 3) Determine if the clipboard format object now has data to offer.
** 4) Transfer the data from the clipboard format object to the medium.
*)
if (CF.AcceptFormat(FormatEtcIn)) and
(DataFormats[i].AssignTo(CF)) and
(CF.HasData) and
(CF.SetDataToMedium(FormatEtcIn, Medium)) then
begin
// Once data has been sucessfully transfered to the medium, we clear
// the data in the TClipboardFormat object in order to conserve
// resources.
CF.Clear;
Result := S_OK;
exit;
end;
end;
end;
end;
 
function TCustomDropMultiSource.DoSetData(const FormatEtc: TFormatEtc;
var Medium: TStgMedium): HRESULT;
var
i, j : integer;
GenericClipboardFormat: TRawClipboardFormat;
begin
Result := E_NOTIMPL;
 
// Get data for requested source format.
for i := 0 to DataFormats.Count-1 do
for j := 0 to DataFormats[i].CompatibleFormats.Count-1 do
if (DataFormats[i].CompatibleFormats[j].AcceptFormat(FormatEtc)) and
(DataFormats[i].CompatibleFormats[j].GetDataFromMedium(Self, Medium)) and
(DataFormats[i].Assign(DataFormats[i].CompatibleFormats[j])) then
begin
DoOnSetData(DataFormats[i], DataFormats[i].CompatibleFormats[j]);
// Once data has been sucessfully transfered to the medium, we clear
// the data in the TClipboardFormat object in order to conserve
// resources.
DataFormats[i].CompatibleFormats[j].Clear;
Result := S_OK;
exit;
end;
 
// The requested data format wasn't supported by any of the registered
// clipboard formats, but in order to support the Windows 2000 drag drop helper
// object we have to accept any data which is written to the IDataObject.
// To do this we create a new clipboard format object, initialize it with the
// format information passed to us and copy the data.
GenericClipboardFormat := TRawClipboardFormat.CreateFormatEtc(FormatEtc);
FRawDataFormat.CompatibleFormats.Add(GenericClipboardFormat);
if (GenericClipboardFormat.GetDataFromMedium(Self, Medium)) and
(FRawDataFormat.Assign(GenericClipboardFormat)) then
Result := S_OK;
end;
 
function TCustomDropMultiSource.GetEnumFormatEtc(dwDirection: Integer): IEnumFormatEtc;
begin
if (dwDirection = DATADIR_GET) then
Result := TEnumFormatEtc.Create(FDataFormats, ddRead)
else if (dwDirection = DATADIR_SET) then
Result := TEnumFormatEtc.Create(FDataFormats, ddWrite)
else
Result := nil;
end;
 
function TCustomDropMultiSource.HasFormat(const FormatEtc: TFormatEtc): boolean;
var
i ,
j : integer;
begin
Result := False;
 
for i := 0 to DataFormats.Count-1 do
for j := 0 to DataFormats[i].CompatibleFormats.Count-1 do
if (DataFormats[i].CompatibleFormats[j].AcceptFormat(FormatEtc)) then
begin
Result := True;
exit;
end;
end;
 
function TCustomDropMultiSource.GetPerformedDropEffect: longInt;
begin
Result := FFeedbackDataFormat.PerformedDropEffect;
end;
 
function TCustomDropMultiSource.GetLogicalPerformedDropEffect: longInt;
begin
Result := FFeedbackDataFormat.LogicalPerformedDropEffect;
end;
 
function TCustomDropMultiSource.GetPreferredDropEffect: longInt;
begin
Result := FFeedbackDataFormat.PreferredDropEffect;
end;
 
procedure TCustomDropMultiSource.SetPerformedDropEffect(const Value: longInt);
begin
FFeedbackDataFormat.PerformedDropEffect := Value;
end;
 
procedure TCustomDropMultiSource.SetPreferredDropEffect(const Value: longInt);
begin
FFeedbackDataFormat.PreferredDropEffect := Value;
end;
 
function TCustomDropMultiSource.GetInShellDragLoop: boolean;
begin
Result := FFeedbackDataFormat.InShellDragLoop;
end;
 
procedure TCustomDropMultiSource.SetInShellDragLoop(const Value: boolean);
begin
FFeedbackDataFormat.InShellDragLoop := Value;
end;
 
function TCustomDropMultiSource.GetTargetCLSID: TCLSID;
begin
Result := FFeedbackDataFormat.TargetCLSID;
end;
 
procedure TCustomDropMultiSource.DoOnSetData(DataFormat: TCustomDataFormat;
ClipboardFormat: TClipboardFormat);
var
DropEffect : longInt;
begin
if (ClipboardFormat is TPasteSuccededClipboardFormat) then
begin
DropEffect := TPasteSuccededClipboardFormat(ClipboardFormat).Value;
DoOnPaste(DropEffectToDragResult(DropEffect),
(DropEffect = DROPEFFECT_MOVE) and (PerformedDropEffect = DROPEFFECT_MOVE));
end;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropSourceThread
//
////////////////////////////////////////////////////////////////////////////////
constructor TDropSourceThread.Create(ADropSource: TCustomDropSource;
AFreeOnTerminate: Boolean);
begin
inherited Create(True);
FreeOnTerminate := AFreeOnTerminate;
FDropSource := ADropSource;
FDragResult := drAsync;
end;
 
procedure TDropSourceThread.Execute;
var
pt: TPoint;
hwndAttach: HWND;
dwAttachThreadID, dwCurrentThreadID : DWORD;
begin
(*
** See Microsoft Knowledgebase Article Q139408 for an explanation of the
** AttachThreadInput stuff.
** http://support.microsoft.com/support/kb/articles/Q139/4/08.asp
*)
 
// Get handle of window under mouse-cursor.
GetCursorPos(pt);
hwndAttach := WindowFromPoint(pt);
ASSERT(hwndAttach<>0, 'Can''t find window with drag-object');
 
// Get thread IDs.
dwAttachThreadID := GetWindowThreadProcessId(hwndAttach, nil);
dwCurrentThreadID := GetCurrentThreadId();
 
// Attach input queues if necessary.
if (dwAttachThreadID <> dwCurrentThreadID) then
AttachThreadInput(dwAttachThreadID, dwCurrentThreadID, True);
try
 
// Initialize OLE for this thread.
OleInitialize(nil);
try
// Start drag & drop.
FDragResult := FDropSource.Execute;
finally
OleUninitialize;
end;
 
finally
// Restore input queue settings.
if (dwAttachThreadID <> dwCurrentThreadID) then
AttachThreadInput(dwAttachThreadID, dwCurrentThreadID, False);
// Set Terminated flag so owner knows that drag has finished.
Terminate;
end;
end;
 
end.
 
/trunk/VCL_DRAGDROP/DropSource3.pas
0,0 → 1,207
unit DropSource3;
 
// -----------------------------------------------------------------------------
//
// *** NOT FOR RELEASE ***
//
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Module: DropSource3
// Description: Deprecated TDropSource class.
// Provided for compatibility with previous versions of the
// Drag and Drop Component Suite.
// Version: 4.0
// Date: 25-JUN-2000
// Target: Win32, Delphi 3-6 and C++ Builder 3-5
// Authors: Angus Johnson, ajohnson@rpi.net.au
// Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2000 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
 
interface
 
uses
DragDrop,
DropSource,
ActiveX,
Classes;
 
{$include DragDrop.inc}
 
const
MAXFORMATS = 20;
 
type
// TODO -oanme -cStopShip : Verify that TDropSource can be used for pre v4 components.
TDropSource = class(TCustomDropSource)
private
FDataFormats: array[0..MAXFORMATS-1] of TFormatEtc;
FDataFormatsCount: integer;
 
protected
// IDataObject implementation
function QueryGetData(const FormatEtc: TFormatEtc): HRESULT; stdcall;
 
// TCustomDropSource implementation
function HasFormat(const FormatEtc: TFormatEtc): boolean; override;
function GetEnumFormatEtc(dwDirection: LongInt): IEnumFormatEtc; override;
 
// New functions...
procedure AddFormatEtc(cfFmt: TClipFormat; pt: PDVTargetDevice;
dwAsp, lInd, tym: longint); virtual;
 
public
constructor Create(AOwner: TComponent); override;
end;
 
implementation
 
uses
ShlObj,
SysUtils,
Windows;
 
// -----------------------------------------------------------------------------
// TEnumFormatEtc
// -----------------------------------------------------------------------------
 
type
 
pFormatList = ^TFormatList;
TFormatList = array[0..255] of TFormatEtc;
 
TEnumFormatEtc = class(TInterfacedObject, IEnumFormatEtc)
private
FFormatList: pFormatList;
FFormatCount: Integer;
FIndex: Integer;
public
constructor Create(FormatList: pFormatList; FormatCount, Index: Integer);
{ 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;
end;
// -----------------------------------------------------------------------------
 
constructor TEnumFormatEtc.Create(FormatList: pFormatList;
FormatCount, Index: Integer);
begin
inherited Create;
FFormatList := FormatList;
FFormatCount := FormatCount;
FIndex := Index;
end;
// -----------------------------------------------------------------------------
 
function TEnumFormatEtc.Next(Celt: LongInt;
out Elt; pCeltFetched: pLongInt): HRESULT;
var
i: Integer;
begin
i := 0;
WHILE (i < Celt) and (FIndex < FFormatCount) do
begin
TFormatList(Elt)[i] := FFormatList[fIndex];
Inc(FIndex);
Inc(i);
end;
if pCeltFetched <> NIL then pCeltFetched^ := i;
if i = Celt then result := S_OK else result := S_FALSE;
end;
// -----------------------------------------------------------------------------
 
function TEnumFormatEtc.Skip(Celt: LongInt): HRESULT;
begin
if Celt <= FFormatCount - FIndex then
begin
FIndex := FIndex + Celt;
result := S_OK;
end else
begin
FIndex := FFormatCount;
result := S_FALSE;
end;
end;
// -----------------------------------------------------------------------------
 
function TEnumFormatEtc.ReSet: HRESULT;
begin
fIndex := 0;
result := S_OK;
end;
// -----------------------------------------------------------------------------
 
function TEnumFormatEtc.Clone(out Enum: IEnumFormatEtc): HRESULT;
begin
enum := TEnumFormatEtc.Create(FFormatList, FFormatCount, FIndex);
result := S_OK;
end;
 
// -----------------------------------------------------------------------------
// TDropSource
// -----------------------------------------------------------------------------
 
constructor TDropSource.Create(AOwner: TComponent);
begin
inherited Create(aOwner);
FDataFormatsCount := 0;
end;
// -----------------------------------------------------------------------------
 
function TDropSource.QueryGetData(const FormatEtc: TFormatEtc): HRESULT; stdcall;
var
i: integer;
begin
result:= S_OK;
for i := 0 to FDataFormatsCount-1 do
with FDataFormats[i] do
begin
if (FormatEtc.cfFormat = cfFormat) and
(FormatEtc.dwAspect = dwAspect) and
(FormatEtc.tymed and tymed <> 0) then exit; //result:= S_OK;
end;
result:= E_FAIL;
end;
// -----------------------------------------------------------------------------
 
function TDropSource.GetEnumFormatEtc(dwDirection: Integer): IEnumFormatEtc;
begin
if (dwDirection = DATADIR_GET) then
Result := TEnumFormatEtc.Create(pFormatList(@FDataFormats), FDataFormatsCount, 0)
else
result := nil;
end;
// -----------------------------------------------------------------------------
 
procedure TDropSource.AddFormatEtc(cfFmt: TClipFormat;
pt: PDVTargetDevice; dwAsp, lInd, tym: longint);
begin
if fDataFormatsCount = MAXFORMATS then exit;
 
FDataFormats[fDataFormatsCount].cfFormat := cfFmt;
FDataFormats[fDataFormatsCount].ptd := pt;
FDataFormats[fDataFormatsCount].dwAspect := dwAsp;
FDataFormats[fDataFormatsCount].lIndex := lInd;
FDataFormats[fDataFormatsCount].tymed := tym;
inc(FDataFormatsCount);
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
 
function TDropSource.HasFormat(const FormatEtc: TFormatEtc): boolean;
begin
Result := True;
{ TODO -oanme -cStopShip : TDropSource.HasFormat needs implementation }
end;
 
initialization
OleInitialize(NIL);
ShGetMalloc(ShellMalloc);
 
finalization
ShellMalloc := nil;
OleUninitialize;
end.
/trunk/VCL_DRAGDROP/DropTarget.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DropTarget.pas
0,0 → 1,1605
unit DropTarget;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Module: DropTarget
// Description: Implements the drop target base classes which allows your
// application to accept data dropped on it from other
// applications.
// Version: 4.0
// Date: 18-MAY-2001
// Target: Win32, Delphi 5-6
// Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
// Copyright © 1997-2001 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
// General changes:
// - Some component glyphs has changed.
// - New components:
// * TDropMetaFileTarget
// * TDropImageTarget
// * TDropSuperTarget
// * Replaced all use of KeysToShiftState with KeysToShiftStatePlus for
// correct mapping of Alt key.
// TCustomDropTarget changes:
// - New protected method SetDataObject.
// Provides write access to DataObject property for use in descendant classes.
// - New protected methods: GetPreferredDropEffect and SetPerformedDropEffect.
// - New protected method DoUnregister handles unregistration of all or
// individual targets.
// - Unregister method has been overloaded to handle multiple drop targets
// (Delphi 4 and later only).
// - All private methods has been made protected.
// - New public methods: FindTarget and FindNearestTarget.
// For use with multiple drop targets.
// - New published property MultiTarget enables multiple drop targets.
// - New public property Targets for support of multiple drop targets.
// - Visibility of Target property has changed from public to published and
// has been made writable.
// - PasteFromClipboard method now handles all formats via DoGetData.
// - Now "handles" situations where the target window handle is recreated.
// - Implemented TCustomDropTarget.Assign to assign from TClipboard and any object
// which implements IDataObject.
// - Added support for optimized moves and delete-on-paste with new
// OptimizedMove property.
// - Fixed inconsistency between GetValidDropEffect and standard IDropTarget
// behaviour.
// - The HasValidFormats method has been made public and now accepts an
// IDataObject as a parameter.
// - The OnGetDropEffect Effect parameter is now initialized to the drop
// source's allowed drop effect mask prior to entry.
// - Added published AutoScroll property and OnScroll even´t and public
// NoScrollZone property.
// Auto scroling can now be completely customized via the OnDragEnter,
// OnDragOver OnGetDropEffect and OnScroll events and the above properties.
// - Added support for IDropTargetHelper interface.
// - Added support for IAsyncOperation interface.
// - New OnStartAsyncTransfer and OnEndAsyncTransfer events.
//
// TDropDummy changes:
// - Bug in HasValidFormats fixed. Spotted by David Polberger.
// Return value changed from True to False.
//
// -----------------------------------------------------------------------------
 
interface
 
uses
DragDrop,
Windows, ActiveX, Classes, Controls, CommCtrl, ExtCtrls, Forms;
 
{$include DragDrop.inc}
 
////////////////////////////////////////////////////////////////////////////////
//
// TControlList
//
////////////////////////////////////////////////////////////////////////////////
// List of TWinControl objects.
// Used for the TCustomDropTarget.Targets property.
////////////////////////////////////////////////////////////////////////////////
type
TControlList = class(TObject)
private
FList: TList;
function GetControl(AIndex: integer): TWinControl;
function GetCount: integer;
protected
function Add(AControl: TWinControl): integer;
procedure Insert(Index: Integer; AControl: TWinControl);
procedure Remove(AControl: TWinControl);
procedure Delete(AIndex: integer);
public
constructor Create;
destructor Destroy; override;
function IndexOf(AControl: TWinControl): integer;
property Count: integer read GetCount;
property Controls[AIndex: integer]: TWinControl read GetControl; default;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomDropTarget
//
////////////////////////////////////////////////////////////////////////////////
// Top level abstract base class for all drop target classes.
// Implements the IDropTarget and IDataObject interfaces.
// Do not derive from TCustomDropTarget! Instead derive from TCustomDropTarget.
// TCustomDropTarget will be replaced by/renamed to TCustomDropTarget in a future
// version.
////////////////////////////////////////////////////////////////////////////////
type
TScrolDirection = (sdUp, sdDown, sdLeft, sdRight);
TScrolDirections = set of TScrolDirection;
 
TDropTargetScrollEvent = procedure(Sender: TObject; Point: TPoint;
var Scroll: TScrolDirections; var Interval: integer) of object;
 
TScrollBars = set of TScrollBarKind;
 
TDropTargetEvent = procedure(Sender: TObject; ShiftState: TShiftState;
APoint: TPoint; var Effect: Longint) of object;
 
TCustomDropTarget = class(TDragDropComponent, IDropTarget)
private
FDataObject : IDataObject;
FDragTypes : TDragTypes;
FGetDataOnEnter : boolean;
FOnEnter : TDropTargetEvent;
FOnDragOver : TDropTargetEvent;
FOnLeave : TNotifyEvent;
FOnDrop : TDropTargetEvent;
FOnGetDropEffect : TDropTargetEvent;
FOnScroll : TDropTargetScrollEvent;
FTargets : TControlList;
FMultiTarget : boolean;
FOptimizedMove : boolean;
FTarget : TWinControl;
 
FImages : TImageList;
FDragImageHandle : HImageList;
FShowImage : boolean;
FImageHotSpot : TPoint;
FDropTargetHelper : IDropTargetHelper;
// FLastPoint points to where DragImage was last painted (used internally)
FLastPoint : TPoint;
// Auto scrolling enables scrolling of target window during drags and
// paints any drag image 'cleanly'.
FScrollBars : TScrollBars;
FScrollTimer : TTimer;
FAutoScroll : boolean;
FNoScrollZone : TRect;
FIsAsync : boolean;
FOnEndAsyncTransfer : TNotifyEvent;
FOnStartAsyncTransfer: TNotifyEvent;
FAllowAsync : boolean;
protected
// IDropTarget implementation
function DragEnter(const DataObj: IDataObject; grfKeyState: Longint;
pt: TPoint; var dwEffect: Longint): HRESULT; stdcall;
function DragOver(grfKeyState: Longint; pt: TPoint;
var dwEffect: Longint): HRESULT; stdcall;
function DragLeave: HRESULT; stdcall;
function Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint;
var dwEffect: Longint): HRESULT; stdcall;
 
procedure DoEnter(ShiftState: TShiftState; Point: TPoint; var Effect: Longint); virtual;
procedure DoDragOver(ShiftState: TShiftState; Point: TPoint; var Effect: Longint); virtual;
procedure DoDrop(ShiftState: TShiftState; Point: TPoint; var Effect: Longint); virtual;
procedure DoLeave; virtual;
procedure DoOnPaste(var Effect: Integer); virtual;
procedure DoScroll(Point: TPoint; var Scroll: TScrolDirections;
var Interval: integer); virtual;
 
function GetData(Effect: longInt): boolean; virtual;
function DoGetData: boolean; virtual; abstract;
procedure ClearData; virtual; abstract;
function GetValidDropEffect(ShiftState: TShiftState; pt: TPoint;
dwEffect: LongInt): LongInt; virtual; // V4: Improved
function GetPreferredDropEffect: LongInt; virtual; // V4: New
function SetPerformedDropEffect(Effect: LongInt): boolean; virtual; // V4: New
function SetPasteSucceded(Effect: LongInt): boolean; virtual; // V4: New
procedure DoUnregister(ATarget: TWinControl); // V4: New
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
function GetTarget: TWinControl;
procedure SetTarget(const Value: TWinControl);
procedure DoAutoScroll(Sender: TObject); // V4: Renamed from DoTargetScroll.
procedure SetShowImage(Show: boolean);
procedure SetDataObject(Value: IDataObject); // V4: New
procedure DoEndAsyncTransfer(Sender: TObject);
property DropTargetHelper: IDropTargetHelper read FDropTargetHelper;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Register(ATarget: TWinControl);
{$ifdef VER12_PLUS}
procedure Unregister(ATarget: TWinControl = nil); // V4: New
{$else}
procedure Unregister;
{$endif}
function FindTarget(p: TPoint): TWinControl; virtual; // V4: New
function FindNearestTarget(p: TPoint): TWinControl; // V4: New
procedure Assign(Source: TPersistent); override; // V4: New
function HasValidFormats(ADataObject: IDataObject): boolean; virtual; abstract; // V4: Improved
function PasteFromClipboard: longint; virtual; // V4: Improved
property DataObject: IDataObject read FDataObject;
property Targets: TControlList read FTargets; // V4: New
property NoScrollZone: TRect read FNoScrollZone write FNoScrollZone; // V4: New
property AsyncTransfer: boolean read FIsAsync;
published
property Dragtypes: TDragTypes read FDragTypes write FDragTypes;
property GetDataOnEnter: Boolean read FGetDataOnEnter write FGetDataOnEnter;
// Events...
property OnEnter: TDropTargetEvent read FOnEnter write FOnEnter;
property OnDragOver: TDropTargetEvent read FOnDragOver write FOnDragOver;
property OnLeave: TNotifyEvent read FOnLeave write FOnLeave;
property OnDrop: TDropTargetEvent read FOnDrop write FOnDrop;
property OnGetDropEffect: TDropTargetEvent read FOnGetDropEffect
write FOnGetDropEffect; // V4: Improved
property OnScroll: TDropTargetScrollEvent read FOnScroll write FOnScroll; // V4: New
property OnStartAsyncTransfer: TNotifyEvent read FOnStartAsyncTransfer
write FOnStartAsyncTransfer;
property OnEndAsyncTransfer: TNotifyEvent read FOnEndAsyncTransfer
write FOnEndAsyncTransfer;
// Drag Images...
property ShowImage: boolean read FShowImage write SetShowImage;
// Target
property Target: TWinControl read GetTarget write SetTarget; // V4: Improved
property MultiTarget: boolean read FMultiTarget write FMultiTarget default False; // V4: New
// Auto scroll
property AutoScroll: boolean read FAutoScroll write FAutoScroll default True; // V4: New
// Misc
property OptimizedMove: boolean read FOptimizedMove write FOptimizedMove default False; // V4: New
// Async transfer...
property AllowAsyncTransfer: boolean read FAllowAsync write FAllowAsync;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropTarget
//
////////////////////////////////////////////////////////////////////////////////
// Deprecated base class for all drop target components.
// Replaced by the TCustomDropTarget class.
////////////////////////////////////////////////////////////////////////////////
TDropTarget = class(TCustomDropTarget)
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropDummy
//
////////////////////////////////////////////////////////////////////////////////
// The sole purpose of this component is to enable drag images to be displayed
// over the registered TWinControl(s). The component does not accept any drops.
////////////////////////////////////////////////////////////////////////////////
TDropDummy = class(TCustomDropTarget)
protected
procedure ClearData; override;
function DoGetData: boolean; override;
public
function HasValidFormats(ADataObject: IDataObject): boolean; override;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomDropMultiTarget
//
////////////////////////////////////////////////////////////////////////////////
// Drop target base class which can accept multiple formats.
////////////////////////////////////////////////////////////////////////////////
TAcceptFormatEvent = procedure(Sender: TObject;
const DataFormat: TCustomDataFormat; var Accept: boolean) of object;
 
TCustomDropMultiTarget = class(TCustomDropTarget)
private
FOnAcceptFormat: TAcceptFormatEvent;
protected
procedure ClearData; override;
function DoGetData: boolean; override;
procedure DoAcceptFormat(const DataFormat: TCustomDataFormat;
var Accept: boolean); virtual;
property OnAcceptFormat: TAcceptFormatEvent read FOnAcceptFormat
write FOnAcceptFormat;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function HasValidFormats(ADataObject: IDataObject): boolean; override;
property DataFormats;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropEmptyTarget
//
////////////////////////////////////////////////////////////////////////////////
// Do-nothing target for use with TDataFormatAdapter and such
////////////////////////////////////////////////////////////////////////////////
TDropEmptyTarget = class(TCustomDropMultiTarget);
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc.
//
////////////////////////////////////////////////////////////////////////////////
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
 
 
(*******************************************************************************
**
** IMPLEMENTATION
**
*******************************************************************************)
implementation
 
uses
DragDropFormats,
ComObj,
SysUtils,
Graphics,
Messages,
ShlObj,
ClipBrd,
ComCtrls;
 
resourcestring
sAsyncBusy = 'Can''t clear data while async data transfer is in progress';
// sRegisterFailed = 'Failed to register %s as a drop target';
// sUnregisterActiveTarget = 'Can''t unregister target while drag operation is in progress';
 
////////////////////////////////////////////////////////////////////////////////
//
// Component registration
//
////////////////////////////////////////////////////////////////////////////////
procedure Register;
begin
RegisterComponents(DragDropComponentPalettePage, [TDropEmptyTarget, TDropDummy]);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// Misc.
//
////////////////////////////////////////////////////////////////////////////////
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TControlList
//
////////////////////////////////////////////////////////////////////////////////
constructor TControlList.Create;
begin
inherited Create;
FList := TList.Create;
end;
 
destructor TControlList.Destroy;
begin
FList.Free;
inherited Destroy;
end;
 
function TControlList.Add(AControl: TWinControl): integer;
begin
Result := FList.Add(AControl);
end;
 
procedure TControlList.Insert(Index: Integer; AControl: TWinControl);
begin
FList.Insert(Index, AControl);
end;
 
procedure TControlList.Delete(AIndex: integer);
begin
FList.Delete(AIndex);
end;
 
function TControlList.IndexOf(AControl: TWinControl): integer;
begin
Result := FList.IndexOf(AControl);
end;
 
function TControlList.GetControl(AIndex: integer): TWinControl;
begin
Result := TWinControl(FList[AIndex]);
end;
 
function TControlList.GetCount: integer;
begin
Result := FList.Count;
end;
 
procedure TControlList.Remove(AControl: TWinControl);
begin
FList.Remove(AControl);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomDropTarget
//
////////////////////////////////////////////////////////////////////////////////
constructor TCustomDropTarget.Create(AOwner: TComponent);
var
bm : TBitmap;
begin
inherited Create(AOwner);
FScrollTimer := TTimer.Create(Self);
FScrollTimer.Enabled := False;
FScrollTimer.OnTimer := DoAutoScroll;
 
// Note: Normally we would call _AddRef or coLockObjectExternal(Self) here to
// make sure that the component wasn't deleted prematurely (e.g. after a call
// to RegisterDragDrop), but since our ancestor class TInterfacedComponent
// disables reference counting, we do not need to do so.
 
FGetDataOnEnter := False;
FTargets := TControlList.Create;
 
FImages := TImageList.Create(Self);
// Create a blank image for FImages which we will use to hide any cursor
// 'embedded' in a drag image.
// This avoids the possibility of two cursors showing.
bm := TBitmap.Create;
try
bm.Height := 32;
bm.Width := 32;
bm.Canvas.Brush.Color := clWindow;
bm.Canvas.FillRect(bm.Canvas.ClipRect);
FImages.AddMasked(bm, clWindow);
finally
bm.Free;
end;
FDataObject := nil;
ShowImage := True;
FMultiTarget := False;
FOptimizedMove := False;
FAutoScroll := True;
end;
 
destructor TCustomDropTarget.Destroy;
begin
FDataObject := nil;
FDropTargetHelper := nil;
Unregister;
FImages.Free;
FScrollTimer.Free;
FTargets.Free;
inherited Destroy;
end;
 
// TDummyWinControl is declared just to expose the protected property - Font -
// which is used to calculate the 'scroll margin' for the target window.
type
TDummyWinControl = Class(TWinControl);
 
function TCustomDropTarget.DragEnter(const dataObj: IDataObject; grfKeyState: Longint;
pt: TPoint; var dwEffect: Longint): HRESULT;
var
ShiftState : TShiftState;
TargetStyles : longint;
begin
ClearData;
FDataObject := dataObj;
Result := S_OK;
 
// Find the target control.
FTarget := FindTarget(pt);
 
(*
** If no target control has been registered we disable all features which
** depends on the existence of a drop target (e.g. drag images and auto
** scroll). Presently, this situation can only arise if the drop target is
** being used as a drop handler (TDrophandler component).
** Note also that if no target control exists, the mouse coordinates are
** relative to the screen, not the control as is normally the case.
*)
if (FTarget = nil) then
begin
ShowImage := False;
AutoScroll := False;
end else
begin
pt := FTarget.ScreenToClient(pt);
FLastPoint := pt;
end;
 
(*
** Refuse the drag if we can't handle any of the data formats offered by
** the drop source. We must return S_OK here in order for the drop to continue
** to generate DragOver events for this drop target (needed for drag images).
*)
if HasValidFormats(FDataObject) then
begin
 
FScrollBars := [];
 
if (AutoScroll) then
begin
// Determine if the target control has scroll bars (and which).
TargetStyles := GetWindowLong(FTarget.Handle, GWL_STYLE);
if (TargetStyles and WS_HSCROLL <> 0) then
include(FScrollBars, sbHorizontal);
if (TargetStyles and WS_VSCROLL <> 0) then
include(FScrollBars, sbVertical);
 
// The Windows UI guidelines recommends that the scroll margin be based on
// the width/height of the scroll bars:
// From "The Windows Interface Guidelines for Software Design", page 82:
// "Use twice the width of a vertical scroll bar or height of a
// horizontal scroll bar to determine the width of the hot zone."
// Previous versions of these components used the height of the current
// target control font as the scroll margin. Yet another approach would be
// to use the DragDropScrollInset constant.
if (FScrollBars <> []) then
begin
FNoScrollZone := FTarget.ClientRect;
if (sbVertical in FScrollBars) then
InflateRect(FNoScrollZone, 0, -GetSystemMetrics(SM_CYHSCROLL));
// InflateRect(FNoScrollZone, 0, -abs(TDummyWinControl(FTarget).Font.Height));
if (sbHorizontal in FScrollBars) then
InflateRect(FNoScrollZone, -GetSystemMetrics(SM_CXHSCROLL), 0);
// InflateRect(FNoScrollZone, -abs(TDummyWinControl(FTarget).Font.Height), 0);
end;
end;
 
// It's generally more efficient to get data only if and when a drop occurs
// rather than on entering a potential target window.
// However - sometimes there is a good reason to get it here.
if FGetDataOnEnter then
if (not GetData(dwEffect)) then
begin
FDataObject := nil;
dwEffect := DROPEFFECT_NONE;
Result := DV_E_CLIPFORMAT;
exit;
end;
 
ShiftState := KeysToShiftStatePlus(grfKeyState);
 
// Create a default drop effect based on the shift state and allowed
// drop effects (or an OnGetDropEffect event if implemented).
dwEffect := GetValidDropEffect(ShiftState, Pt, dwEffect);
 
// Generate an OnEnter event
DoEnter(ShiftState, pt, dwEffect);
 
// If IDropTarget.DragEnter returns with dwEffect set to DROPEFFECT_NONE it
// means that the drop has been rejected and IDropTarget.DragOver should
// not be called (according to MSDN). Unfortunately IDropTarget.DragOver is
// called regardless of the value of dwEffect. We work around this problem
// (bug?) by setting FDataObject to nil and thus internally rejecting the
// drop in TCustomDropTarget.DragOver.
if (dwEffect = DROPEFFECT_NONE) then
FDataObject := nil;
 
end else
begin
FDataObject := nil;
dwEffect := DROPEFFECT_NONE;
end;
 
// Display drag image.
// Note: This was previously done prior to caling GetValidDropEffect and
// DoEnter. The SDK documentation states that IDropTargetHelper.DragEnter
// should be called last in IDropTarget.DragEnter (presumably after dwEffect
// has been modified), but Microsoft's own demo application calls it as the
// very first thing (same for all other IDropTargetHelper methods).
if ShowImage then
begin
// Attempt to create Drag Drop helper object.
// At present this is only supported on Windows 2000. If the object can't be
// created, we fall back to the old image list based method (which only
// works on Win9x).
CoCreateInstance(CLSID_DragDropHelper, nil, CLSCTX_INPROC_SERVER,
IDropTargetHelper, FDropTargetHelper);
 
if (FDropTargetHelper <> nil) then
begin
// If the call to DragEnter fails (which it will do if the drop source
// doesn't support IDropSourceHelper or hasn't specified a drag image),
// we release the drop target helper and fall back to imagelist based
// drag images.
if (DropTargetHelper.DragEnter(FTarget.Handle, DataObj, pt, dwEffect) <> S_OK) then
FDropTargetHelper := nil;
end;
 
if (FDropTargetHelper = nil) then
begin
FDragImageHandle := ImageList_GetDragImage(nil, @FImageHotSpot);
if (FDragImageHandle <> 0) then
begin
// Currently we will just replace any 'embedded' cursor with our
// blank (transparent) image otherwise we sometimes get 2 cursors ...
ImageList_SetDragCursorImage(FImages.Handle, 0, FImageHotSpot.x, FImageHotSpot.y);
with ClientPtToWindowPt(FTarget.Handle, pt) do
ImageList_DragEnter(FTarget.handle, x, y);
end;
end;
end else
FDragImageHandle := 0;
end;
 
procedure TCustomDropTarget.DoEnter(ShiftState: TShiftState; Point: TPoint; var Effect: Longint);
begin
if Assigned(FOnEnter) then
FOnEnter(Self, ShiftState, Point, Effect);
end;
 
function TCustomDropTarget.DragOver(grfKeyState: Longint; pt: TPoint;
var dwEffect: Longint): HResult;
var
ShiftState: TShiftState;
IsScrolling: boolean;
begin
// Refuse drop if we dermined in DragEnter that a drop weren't possible,
// but still handle drag images provided we have a valid target.
if (FTarget = nil) then
begin
dwEffect := DROPEFFECT_NONE;
Result := E_UNEXPECTED;
exit;
end;
 
pt := FTarget.ScreenToClient(pt);
 
if (FDataObject <> nil) then
begin
 
ShiftState := KeysToShiftStatePlus(grfKeyState);
 
// Create a default drop effect based on the shift state and allowed
// drop effects (or an OnGetDropEffect event if implemented).
dwEffect := GetValidDropEffect(ShiftState, pt, dwEffect);
 
// Generate an OnDragOver event
DoDragOver(ShiftState, pt, dwEffect);
 
// Note: Auto scroll is detected by the GetValidDropEffect method, but can
// also be started by the user via the OnDragOver or OnGetDropEffect events.
// Auto scroll is initiated by specifying the DROPEFFECT_SCROLL value as
// part of the drop effect.
 
// Start the auto scroll timer if auto scroll were requested. Do *not* rely
// on any other mechanisms to detect auto scroll since the user can only
// specify auto scroll with the DROPEFFECT_SCROLL value.
IsScrolling := (dwEffect and DROPEFFECT_SCROLL <> 0);
if (IsScrolling) and (not FScrollTimer.Enabled) then
begin
FScrollTimer.Interval := DragDropScrollDelay; // hardcoded to 100 in previous versions.
FScrollTimer.Enabled := True;
end;
 
Result := S_OK;
end else
begin
// Even though this isn't an error condition per se, we must return
// an error code (e.g. E_UNEXPECTED) in order for the cursor to change
// to DROPEFFECT_NONE.
IsScrolling := False;
Result := DV_E_CLIPFORMAT;
end;
 
// Move drag image
if (DropTargetHelper <> nil) then
begin
OleCheck(DropTargetHelper.DragOver(pt, dwEffect));
end else
if (FDragImageHandle <> 0) then
begin
if (not IsScrolling) and ((FLastPoint.x <> pt.x) or (FLastPoint.y <> pt.y)) then
with ClientPtToWindowPt(FTarget.Handle, pt) do
ImageList_DragMove(x, y);
end;
 
FLastPoint := pt;
end;
 
procedure TCustomDropTarget.DoDragOver(ShiftState: TShiftState; Point: TPoint; var Effect: Longint);
begin
if Assigned(FOnDragOver) then
FOnDragOver(Self, ShiftState, Point, Effect);
end;
 
function TCustomDropTarget.DragLeave: HResult;
begin
ClearData;
FScrollTimer.Enabled := False;
 
FDataObject := nil;
 
if (DropTargetHelper <> nil) then
begin
DropTargetHelper.DragLeave;
end else
if (FDragImageHandle <> 0) then
ImageList_DragLeave(FTarget.Handle);
 
// Generate an OnLeave event.
// Protect resources against exceptions in event handler.
try
DoLeave;
finally
FTarget := nil;
FDropTargetHelper := nil;
end;
 
Result := S_OK;
end;
 
procedure TCustomDropTarget.DoLeave;
begin
if Assigned(FOnLeave) then
FOnLeave(Self);
end;
 
function TCustomDropTarget.Drop(const dataObj: IDataObject; grfKeyState: Longint;
pt: TPoint; var dwEffect: Longint): HResult;
var
ShiftState: TShiftState;
ClientPt: TPoint;
begin
FScrollTimer.Enabled := False;
 
// Protect resources against exceptions in OnDrop event handler.
try
// Refuse drop if we have lost the data object somehow.
// This can happen if the drop is rejected in one of the other IDropTarget
// methods (e.g. DragOver).
if (FDataObject = nil) then
begin
dwEffect := DROPEFFECT_NONE;
Result := E_UNEXPECTED;
end else
begin
 
ShiftState := KeysToShiftStatePlus(grfKeyState);
 
// Create a default drop effect based on the shift state and allowed
// drop effects (or an OnGetDropEffect event if implemented).
if (FTarget <> nil) then
ClientPt := FTarget.ScreenToClient(pt)
else
ClientPt := pt;
dwEffect := GetValidDropEffect(ShiftState, ClientPt, dwEffect);
 
// Get data from source and generate an OnDrop event unless we failed to
// get data.
if (FGetDataOnEnter) or (GetData(dwEffect)) then
DoDrop(ShiftState, ClientPt, dwEffect)
else
dwEffect := DROPEFFECT_NONE;
Result := S_OK;
end;
 
if (DropTargetHelper <> nil) then
begin
DropTargetHelper.Drop(DataObj, pt, dwEffect);
end else
if (FDragImageHandle <> 0) and (FTarget <> nil) then
ImageList_DragLeave(FTarget.Handle);
finally
// clean up!
ClearData;
FDataObject := nil;
FDropTargetHelper := nil;
FTarget := nil;
end;
end;
 
procedure TCustomDropTarget.DoDrop(ShiftState: TShiftState; Point: TPoint; var Effect: Longint);
begin
if Assigned(FOnDrop) then
FOnDrop(Self, ShiftState, Point, Effect);
 
(*
Optimized move (from MSDN):
 
Scenario: A file is moved from the file system to a namespace extension using
an optimized move.
 
In a conventional move operation, the target makes a copy of the data and the
source deletes the original. This procedure can be inefficient because it
requires two copies of the data. With large objects such as databases, a
conventional move operation might not even be practical.
 
With an optimized move, the target uses its understanding of how the data is
stored to handle the entire move operation. There is never a second copy of
the data, and there is no need for the source to delete the original data.
Shell data is well suited to optimized moves because the target can handle the
entire operation using the shell API. A typical example is moving files. Once
the target has the path of a file to be moved, it can use SHFileOperation to
move it. There is no need for the source to delete the original file.
 
Note The shell normally uses an optimized move to move files. To handle shell
data transfer properly, your application must be capable of detecting and
handling an optimized move.
 
Optimized moves are handled in the following way:
 
1) The source calls DoDragDrop with the dwEffect parameter set to
DROPEFFECT_MOVE to indicate that the source objects can be moved.
2) The target receives the DROPEFFECT_MOVE value through one of its
IDropTarget methods, indicating that a move is allowed.
3) The target either copies the object (unoptimized move) or moves the object
(optimized move).
4) The target then tells the source whether it needs to delete the original
data.
An optimized move is the default operation, with the data deleted by the
target. To inform the source that an optimized move was performed:
- The target sets the pdwEffect value it received through its
IDropTarget::Drop method to some value other than DROPEFFECT_MOVE. It is
typically set to either DROPEFFECT_NONE or DROPEFFECT_COPY. The value
will be returned to the source by DoDragDrop.
- The target also calls the data object's IDataObject::SetData method and
passes it a CFSTR_PERFORMEDDROPEFFECT format identifier set to
DROPEFFECT_NONE. This method call is necessary because some drop targets
might not set the pdwEffect parameter of DoDragDrop properly. The
CFSTR_PERFORMEDDROPEFFECT format is the reliable way to indicate that an
optimized move has taken place.
If the target did an unoptimized move, the data must be deleted by the
source. To inform the source that an unoptimized move was performed:
- The target sets the pdwEffect value it received through its
IDropTarget::Drop method to DROPEFFECT_MOVE. The value will be returned
to the source by DoDragDrop.
- The target also calls the data object's IDataObject::SetData method and
passes it a CFSTR_PERFORMEDDROPEFFECT format identifier set to
DROPEFFECT_MOVE. This method call is necessary because some drop targets
might not set the pdwEffect parameter of DoDragDrop properly. The
CFSTR_PERFORMEDDROPEFFECT format is the reliable way to indicate that an
unoptimized move has taken place.
5) The source inspects the two values that can be returned by the target. If
both are set to DROPEFFECT_MOVE, it completes the unoptimized move by
deleting the original data. Otherwise, the target did an optimized move and
the original data has been deleted.
*)
 
// TODO : Why isn't this code in the Drop method?
// Report performed drop effect back to data originator.
if (Effect <> DROPEFFECT_NONE) then
begin
// If the transfer was an optimized move operation (target deletes data),
// we convert the move operation to a copy operation to prevent that the
// source deletes the data.
if (FOptimizedMove) and (Effect = DROPEFFECT_MOVE) then
Effect := DROPEFFECT_COPY;
SetPerformedDropEffect(Effect);
end;
end;
 
type
TDropTargetTransferThread = class(TThread)
private
FCustomDropTarget: TCustomDropTarget;
FDataObject: IDataObject;
FEffect: Longint;
FMarshalStream: pointer;
protected
procedure Execute; override;
property MarshalStream: pointer read FMarshalStream write FMarshalStream;
public
constructor Create(ACustomDropTarget: TCustomDropTarget;
const ADataObject: IDataObject; AEffect: Longint);
property CustomDropTarget: TCustomDropTarget read FCustomDropTarget;
property DataObject: IDataObject read FDataObject;
property Effect: Longint read FEffect;
end;
 
constructor TDropTargetTransferThread.Create(ACustomDropTarget: TCustomDropTarget;
const ADataObject: IDataObject; AEffect: longInt);
begin
inherited Create(True);
FreeOnTerminate := True;
FCustomDropTarget := ACustomDropTarget;
OnTerminate := FCustomDropTarget.DoEndAsyncTransfer;
FEffect := AEffect;
OleCheck(CoMarshalInterThreadInterfaceInStream(IDataObject, ADataObject,
IStream(FMarshalStream)));
end;
 
procedure TDropTargetTransferThread.Execute;
var
Res: HResult;
begin
CoInitialize(nil);
try
try
OleCheck(CoGetInterfaceAndReleaseStream(IStream(MarshalStream),
IDataObject, FDataObject));
MarshalStream := nil;
CustomDropTarget.FDataObject := DataObject;
CustomDropTarget.DoGetData;
Res := S_OK;
except
Res := E_UNEXPECTED;
end;
(FDataObject as IAsyncOperation).EndOperation(Res, nil, Effect);
finally
FDataObject := nil;
CoUninitialize;
end;
end;
 
procedure TCustomDropTarget.DoEndAsyncTransfer(Sender: TObject);
begin
// Reset async transfer flag once transfer completes and...
FIsAsync := False;
 
// ...Fire event.
if Assigned(FOnEndAsyncTransfer) then
FOnEndAsyncTransfer(Self);
end;
 
function TCustomDropTarget.GetData(Effect: longInt): boolean;
var
DoAsync: LongBool;
AsyncOperation: IAsyncOperation;
// h: HResult;
begin
ClearData;
 
// Determine if drop source supports and has enabled asynchronous data
// transfer.
(*
h := DataObject.QueryInterface(IAsyncOperation, AsyncOperation);
h := DataObject.QueryInterface(IDropSource, AsyncOperation);
OutputDebugString(PChar(SysErrorMessage(h)));
*)
if not(AllowAsyncTransfer and
Succeeded(DataObject.QueryInterface(IAsyncOperation, AsyncOperation)) and
Succeeded(AsyncOperation.GetAsyncMode(DoAsync))) then
DoAsync := False;
 
// Start an async data transfer...
if (DoAsync) then
begin
// Fire event.
if Assigned(FOnStartAsyncTransfer) then
FOnStartAsyncTransfer(Self);
FIsAsync := True;
// Notify drop source that an async data transfer is starting.
AsyncOperation.StartOperation(nil);
// Create the data transfer thread and launch it.
with TDropTargetTransferThread.Create(Self, DataObject, Effect) do
Resume;
 
Result := True;
end else
Result := DoGetData;
end;
 
procedure TCustomDropTarget.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent is TWinControl) then
begin
if (csDesigning in ComponentState) and (AComponent = FTarget) then
FTarget := nil;
if (FTargets.IndexOf(TWinControl(AComponent)) <> -1) then
DoUnregister(TWinControl(AComponent));
end;
end;
 
type
TWinControlProxy = class(TWinControl)
protected
procedure DestroyWnd; override;
procedure CreateWnd; override;
end;
 
procedure TWinControlProxy.CreateWnd;
begin
inherited CreateWnd;
OleCheck(RegisterDragDrop(Parent.Handle, TCustomDropTarget(Owner)));
Visible := False;
end;
 
procedure TWinControlProxy.DestroyWnd;
begin
if (Parent.HandleAllocated) then
RevokeDragDrop(Parent.Handle);
// Control must be visible in order to guarantee that CreateWnd is called when
// parent control recreates window handle.
Visible := True;
inherited DestroyWnd;
end;
 
procedure TCustomDropTarget.Register(ATarget: TWinControl);
 
function Contains(Parent, Child: TWinControl): boolean;
var
i: integer;
begin
if (Child.Parent <> Parent) then
begin
Result := False;
for i := 0 to Parent.ControlCount-1 do
if (Parent.Controls[i] is TWinControl) and
Contains(TWinControl(Parent.Controls[i]), Child) then
begin
Result := True;
break;
end;
end else
Result := True;
end;
 
var
i: integer;
Inserted: boolean;
begin
// Don't register if the target is already registered.
// TODO -cImprovement : Maybe we should unregister and reregister the target if it has already been registered (in case the handle has changed)...
if (FTargets.IndexOf(ATarget) <> -1) then
exit;
 
// Unregister previous target unless MultiTarget is enabled (for backwards
// compatibility).
if (not FMultiTarget) and not(csLoading in ComponentState) then
Unregister;
 
if (ATarget = nil) then
exit;
 
// Insert the target in Z order, Topmost last.
// Note: The target is added to the target list even though the drop target
// registration may fail below. This is done because we would like
// the target to be unregistered (RevokeDragDrop) even if we failed to
// register it.
Inserted := False;
for i := FTargets.Count-1 downto 0 do
if Contains(FTargets[i], ATarget) then
begin
FTargets.Insert(i+1, ATarget);
Inserted := True;
break;
end;
if (not Inserted) then
begin
FTargets.Add(ATarget);
// ATarget.FreeNotification(Self);
end;
 
 
// If the target is a TRichEdit control, we disable the rich edit control's
// built-in drag/drop support.
if (ATarget is TCustomRichEdit) then
RevokeDragDrop(ATarget.Handle);
 
// Create a child control to monitor the target window handle.
// The child control will perform the drop target registration for us.
with TWinControlProxy.Create(Self) do
Parent := ATarget;
end;
 
{$ifdef VER12_PLUS}
procedure TCustomDropTarget.Unregister(ATarget: TWinControl);
begin
// Unregister a single targets (or all targets if ATarget is nil).
DoUnregister(ATarget);
end;
{$else}
procedure TCustomDropTarget.Unregister;
begin
// Unregister all targets (for backward compatibility).
DoUnregister(nil);
end;
{$endif}
 
procedure TCustomDropTarget.DoUnregister(ATarget: TWinControl);
var
i : integer;
begin
if (ATarget = nil) then
begin
for i := FTargets.Count-1 downto 0 do
DoUnregister(FTargets[i]);
exit;
end;
 
i := FTargets.IndexOf(ATarget);
if (i = -1) then
exit;
 
if (ATarget = FTarget) then
FTarget := nil;
// raise Exception.Create(sUnregisterActiveTarget);
 
FTargets.Delete(i);
 
(* Handled by proxy
if (ATarget.HandleAllocated) then
// Ignore failed unregistrations - nothing to do about it anyway
RevokeDragDrop(ATarget.Handle);
*)
 
// Delete target proxy.
// The target proxy willl unregister the drop target for us when it is
// destroyed.
for i := ATarget.ControlCount-1 downto 0 do
if (ATarget.Controls[i] is TWinControlProxy) and
(TWinControlProxy(ATarget.Controls[i]).Owner = Self) then
with TWinControlProxy(ATarget.Controls[i]) do
begin
Parent := nil;
Free;
break;
end;
end;
 
function TCustomDropTarget.FindTarget(p: TPoint): TWinControl;
(*
var
i: integer;
r: TRect;
Parent: TWinControl;
*)
begin
 
Result := FindVCLWindow(p);
while (Result <> nil) and (Targets.IndexOf(Result) = -1) do
begin
Result := Result.Parent;
end;
(*
// Search list in Z order. Top to bottom.
for i := Targets.Count-1 downto 0 do
begin
Result := Targets[i];
 
// If the control or any of its parent aren't visible, we can't drop on it.
Parent := Result;
while (Parent <> nil) do
begin
if (not Parent.Showing) then
break;
Parent := Parent.Parent;
end;
if (Parent <> nil) then
continue;
 
GetWindowRect(Result.Handle, r);
if PtInRect(r, p) then
exit;
end;
Result := nil;
*)
end;
 
function TCustomDropTarget.FindNearestTarget(p: TPoint): TWinControl;
var
i : integer;
r : TRect;
pc : TPoint;
Control : TWinControl;
Dist ,
BestDist : integer;
 
function Distance(r: TRect; p: TPoint): integer;
var
dx ,
dy : integer;
begin
if (p.x < r.Left) then
dx := r.Left - p.x
else if (p.x > r.Right) then
dx := r.Right - p.x
else
dx := 0;
if (p.y < r.Top) then
dy := r.Top - p.y
else if (p.y > r.Bottom) then
dy := r.Bottom - p.y
else
dy := 0;
Result := dx*dx + dy*dy;
end;
 
begin
Result := nil;
BestDist := high(integer);
for i := 0 to Targets.Count-1 do
begin
Control := Targets[i];
r := Control.ClientRect;
inc(r.Right);
inc(r.Bottom);
pc := Control.ScreenToClient(p);
if (PtInRect(r, p)) then
begin
Result := Control;
exit;
end;
Dist := Distance(r, pc);
if (Dist < BestDist) then
begin
Result := Control;
BestDist := Dist;
end;
end;
end;
 
function TCustomDropTarget.GetTarget: TWinControl;
begin
Result := FTarget;
if (Result = nil) and not(csDesigning in ComponentState) then
begin
if (FTargets.Count > 0) then
Result := TWinControl(FTargets[0])
else
Result := nil;
end;
end;
 
procedure TCustomDropTarget.SetTarget(const Value: TWinControl);
begin
if (FTarget = Value) then
exit;
 
if (csDesigning in ComponentState) then
FTarget := Value
else
begin
// If MultiTarget isn't enabled, Register will automatically unregister do
// no need to do it here.
if (FMultiTarget) and not(csLoading in ComponentState) then
Unregister;
Register(Value);
end;
end;
 
procedure TCustomDropTarget.SetDataObject(Value: IDataObject);
begin
FDataObject := Value;
end;
 
procedure TCustomDropTarget.SetShowImage(Show: boolean);
begin
FShowImage := Show;
if (DropTargetHelper <> nil) then
DropTargetHelper.Show(Show)
else
if (FDataObject <> nil) then
ImageList_DragShowNolock(FShowImage);
end;
 
function TCustomDropTarget.GetValidDropEffect(ShiftState: TShiftState;
pt: TPoint; dwEffect: LongInt): LongInt;
begin
// dwEffect 'in' parameter = set of drop effects allowed by drop source.
// Now filter out the effects disallowed by target...
Result := dwEffect AND DragTypesToDropEffect(FDragTypes);
 
Result := ShiftStateToDropEffect(ShiftState, Result, True);
 
// Add Scroll effect if necessary...
if (FAutoScroll) and (FScrollBars <> []) then
begin
// If the cursor is inside the no-scroll zone, clear the drag scroll flag,
// otherwise set it.
if (PtInRect(FNoScrollZone, pt)) then
Result := Result AND NOT integer(DROPEFFECT_SCROLL)
else
Result := Result OR integer(DROPEFFECT_SCROLL);
end;
 
// 'Default' behaviour can be overriden by assigning OnGetDropEffect.
if Assigned(FOnGetDropEffect) then
FOnGetDropEffect(Self, ShiftState, pt, Result);
end;
 
function TCustomDropTarget.GetPreferredDropEffect: LongInt;
begin
with TPreferredDropEffectClipboardFormat.Create do
try
if GetData(DataObject) then
Result := Value
else
Result := DROPEFFECT_NONE;
finally
Free;
end;
end;
 
function TCustomDropTarget.SetPasteSucceded(Effect: LongInt): boolean;
var
Medium: TStgMedium;
begin
with TPasteSuccededClipboardFormat.Create do
try
Value := Effect;
Result := SetData(DataObject, FormatEtc, Medium);
finally
Free;
end;
end;
 
function TCustomDropTarget.SetPerformedDropEffect(Effect: longInt): boolean;
var
Medium: TStgMedium;
begin
with TPerformedDropEffectClipboardFormat.Create do
try
Value := Effect;
Result := SetData(DataObject, FormatEtc, Medium);
finally
Free;
end;
end;
 
(*
The basic procedure for a delete-on-paste operation is as follows (from MSDN):
 
1) The source marks the screen display of the selected data.
2) The source creates a data object. It indicates a cut operation by adding the
CFSTR_PREFERREDDROPEFFECT format with a data value of DROPEFFECT_MOVE.
3) The source places the data object on the Clipboard using OleSetClipboard.
4) The target retrieves the data object from the Clipboard using
OleGetClipboard.
5) The target extracts the CFSTR_PREFERREDDROPEFFECT data. If it is set to only
DROPEFFECT_MOVE, the target can either do an optimized move or simply copy
the data.
6) If the target does not do an optimized move, it calls the
IDataObject::SetData method with the CFSTR_PERFORMEDDROPEFFECT format set
to DROPEFFECT_MOVE.
7) When the paste is complete, the target calls the IDataObject::SetData method
with the CFSTR_PASTESUCCEEDED format set to DROPEFFECT_MOVE.
8) When the source's IDataObject::SetData method is called with the
CFSTR_PASTESUCCEEDED format set to DROPEFFECT_MOVE, it must check to see if it
also received the CFSTR_PERFORMEDDROPEFFECT format set to DROPEFFECT_MOVE. If
both formats are sent by the target, the source will have to delete the data.
If only the CFSTR_PASTESUCCEEDED format is received, the source can simply
remove the data from its display. If the transfer fails, the source updates
the display to its original appearance.
*)
function TCustomDropTarget.PasteFromClipboard: longint;
var
Effect: longInt;
begin
// Get an IDataObject interface to the clipboard.
// Temporarily pretend that the IDataObject has been dropped on the target.
OleCheck(OleGetClipboard(FDataObject));
try
Effect := GetPreferredDropEffect;
// Get data from the IDataObject.
if (GetData(Effect)) then
Result := Effect
else
Result := DROPEFFECT_NONE;
 
DoOnPaste(Result);
finally
// Clean up
FDataObject := nil;
end;
end;
 
procedure TCustomDropTarget.DoOnPaste(var Effect: longint);
begin
// Generate an OnDrop event
DoDrop([], Point(0,0), Effect);
 
// Report performed drop effect back to data originator.
if (Effect <> DROPEFFECT_NONE) then
// Delete on paste:
// We now set the CF_PASTESUCCEDED format to indicate to the source
// that we are using the "delete on paste" protocol and that the
// paste has completed.
SetPasteSucceded(Effect);
end;
 
procedure TCustomDropTarget.Assign(Source: TPersistent);
begin
if (Source is TClipboard) then
PasteFromClipboard
else if (Source.GetInterface(IDataObject, FDataObject)) then
begin
try
// Get data from the IDataObject
if (not GetData(DROPEFFECT_COPY)) then
inherited Assign(Source);
finally
// Clean up
FDataObject := nil;
end;
end else
inherited Assign(Source);
end;
 
procedure TCustomDropTarget.DoAutoScroll(Sender: TObject);
var
Scroll: TScrolDirections;
Interval: integer;
begin
// Disable timer until we are ready to auto-repeat the scroll.
// If no scroll is performed, the scroll stops here.
FScrollTimer.Enabled := False;;
 
Interval := DragDropScrollInterval;
Scroll := [];
 
// Only scroll if the pointer is outside the non-scroll area
if (not PtInRect(FNoScrollZone, FLastPoint)) then
begin
with FLastPoint do
begin
// Determine which way to scroll.
if (Y < FNoScrollZone.Top) then
include(Scroll, sdUp)
else if (Y > FNoScrollZone.Bottom) then
include(Scroll, sdDown);
 
if (X < FNoScrollZone.Left) then
include(Scroll, sdLeft)
else if (X > FNoScrollZone.Right) then
include(Scroll, sdRight);
end;
end;
 
DoScroll(FLastPoint, Scroll, Interval);
 
// Note: Once the OnScroll event has been fired and the user has had a
// chance of overriding the auto scroll logic, we should *only* use to Scroll
// variable to determine if and how to scroll. Do not use FScrollBars past
// this point.
 
// Only scroll if the pointer is outside the non-scroll area
if (Scroll <> []) then
begin
// Remove drag image before scrolling
if (FDragImageHandle <> 0) then
ImageList_DragLeave(FTarget.Handle);
try
if (sdUp in Scroll) then
FTarget.Perform(WM_VSCROLL,SB_LINEUP, 0)
else if (sdDown in Scroll) then
FTarget.Perform(WM_VSCROLL,SB_LINEDOWN, 0);
 
if (sdLeft in Scroll) then
FTarget.Perform(WM_HSCROLL,SB_LINEUP, 0)
else if (sdRight in Scroll) then
FTarget.Perform(WM_HSCROLL,SB_LINEDOWN, 0);
finally
// Restore drag image
if (FDragImageHandle <> 0) then
with ClientPtToWindowPt(FTarget.Handle, FLastPoint) do
ImageList_DragEnter(FTarget.Handle, x, y);
end;
 
// Reset scroll timer interval once timer has fired once.
FScrollTimer.Interval := Interval;
FScrollTimer.Enabled := True;
end;
end;
 
procedure TCustomDropTarget.DoScroll(Point: TPoint;
var Scroll: TScrolDirections; var Interval: integer);
begin
if Assigned(FOnScroll) then
FOnScroll(Self, FLastPoint, Scroll, Interval);
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TDropDummy
//
////////////////////////////////////////////////////////////////////////////////
function TDropDummy.HasValidFormats(ADataObject: IDataObject): boolean;
begin
Result := False;
end;
 
procedure TDropDummy.ClearData;
begin
// Abstract method override - doesn't do anything as you can see.
end;
 
function TDropDummy.DoGetData: boolean;
begin
Result := False;
end;
 
 
////////////////////////////////////////////////////////////////////////////////
//
// TCustomDropMultiTarget
//
////////////////////////////////////////////////////////////////////////////////
constructor TCustomDropMultiTarget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
DragTypes := [dtLink, dtCopy];
GetDataOnEnter := False;
FDataFormats := TDataFormats.Create;
end;
 
destructor TCustomDropMultiTarget.Destroy;
var
i : integer;
begin
// Delete all target formats owned by the object.
for i := FDataFormats.Count-1 downto 0 do
FDataFormats[i].Free;
FDataFormats.Free;
inherited Destroy;
end;
 
function TCustomDropMultiTarget.HasValidFormats(ADataObject: IDataObject): boolean;
var
GetNum ,
GotNum : longInt;
FormatEnumerator : IEnumFormatEtc;
i : integer;
SourceFormatEtc : TFormatEtc;
begin
Result := False;
 
if (ADataObject.EnumFormatEtc(DATADIR_GET, FormatEnumerator) <> S_OK) or
(FormatEnumerator.Reset <> S_OK) then
exit;
 
GetNum := 1; // Get one format at a time.
 
// Enumerate all data formats offered by the drop source.
// Note: Depends on order of evaluation.
while (not Result) and
(FormatEnumerator.Next(GetNum, SourceFormatEtc, @GotNum) = S_OK) and
(GetNum = GotNum) do
begin
// Determine if any of the associated clipboard formats can
// read the current data format.
for i := 0 to FDataFormats.Count-1 do
if (FDataFormats[i].AcceptFormat(SourceFormatEtc)) and
(FDataFormats[i].HasValidFormats(ADataObject)) then
begin
Result := True;
DoAcceptFormat(FDataFormats[i], Result);
if (Result) then
break;
end;
end;
end;
 
procedure TCustomDropMultiTarget.ClearData;
var
i : integer;
begin
if (AsyncTransfer) then
raise Exception.Create(sAsyncBusy);
for i := 0 to DataFormats.Count-1 do
DataFormats[i].Clear;
end;
 
function TCustomDropMultiTarget.DoGetData: boolean;
var
i: integer;
Accept: boolean;
begin
Result := False;
 
// Get data for all target formats
for i := 0 to DataFormats.Count-1 do
begin
// This isn't strictly nescessary and adds overhead, but it reduces
// unnescessary calls to DoAcceptData (format is asked if it can accept data
// even though no data is available to the format).
if not(FDataFormats[i].HasValidFormats(DataObject)) then
continue;
 
// Only get data from accepted formats.
// TDropComboTarget uses the DoAcceptFormat method to filter formats and to
// allow the user to disable formats via an event.
Accept := True;
DoAcceptFormat(DataFormats[i], Accept);
if (not Accept) then
Continue;
 
Result := DataFormats[i].GetData(DataObject) or Result;
end;
end;
 
procedure TCustomDropMultiTarget.DoAcceptFormat(const DataFormat: TCustomDataFormat;
var Accept: boolean);
begin
if Assigned(FOnAcceptFormat) then
FOnAcceptFormat(Self, DataFormat, Accept);
end;
 
end.
 
/trunk/VCL_DRAGDROP/DropTargetCur.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DropURLSource.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DropURLSource.pas
0,0 → 1,217
unit DropURLSource;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Component Names: TDropURLSource
// Module: DropURLSource
// Description: Implements Dragging & Dropping of URLs
// FROM your application to another.
// Version: 3.7
// Date: 22-APR-1999
// Target: Win32, Delphi 3 - Delphi 5, C++ Builder 3, C++ Builder 4
// Authors: Angus Johnson, ajohnson@rpi.net.au
// Anders Melander, anders@melander.dk
// http://www.melander.dk
// Copyright © 1997-99 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
interface
 
uses
DropSource,
Classes, ActiveX;
 
{$include DragDrop.inc}
 
type
TDropURLSource = class(TDropSource)
private
fURL: String;
fTitle: String;
protected
function DoGetData(const FormatEtcIn: TFormatEtc; OUT Medium: TStgMedium):HRESULT; Override;
public
constructor Create(aOwner: TComponent); Override;
function CutOrCopyToClipboard: boolean; Override;
published
property URL: String Read fURL Write fURL;
property Title: String Read fTitle Write fTitle;
end;
 
procedure Register;
 
implementation
 
uses
Windows,
SysUtils,
ClipBrd,
ShlObj;
 
procedure Register;
begin
RegisterComponents('DragDrop', [TDropURLSource]);
end;
// -----------------------------------------------------------------------------
 
function ConvertURLToFilename(url: string): string;
const
Invalids = '\/:?*<>,|''"';
var
i: integer;
begin
if lowercase(copy(url,1,7)) = 'http://' then
url := copy(url,8,128) // limit to 120 chars.
else if lowercase(copy(url,1,6)) = 'ftp://' then
url := copy(url,7,127)
else if lowercase(copy(url,1,7)) = 'mailto:' then
url := copy(url,8,128)
else if lowercase(copy(url,1,5)) = 'file:' then
url := copy(url,6,126);
 
if url = '' then url := 'untitled';
result := url;
for i := 1 to length(result) do
if result[i] = '/'then
begin
result := copy(result,1,i-1);
break;
end
else if pos(result[i],Invalids) <> 0 then
result[i] := ' ';
appendstr(result,'.url');
end;
 
// -----------------------------------------------------------------------------
// TDropURLSource
// -----------------------------------------------------------------------------
 
constructor TDropURLSource.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
fURL := '';
fTitle := '';
DragTypes := [dtLink]; // Only dtLink allowed
 
AddFormatEtc(CF_URL, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
AddFormatEtc(CF_FILEGROUPDESCRIPTOR, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
AddFormatEtc(CF_FILECONTENTS, NIL, DVASPECT_CONTENT, 0, TYMED_HGLOBAL);
AddFormatEtc(CF_TEXT, NIL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
end;
// -----------------------------------------------------------------------------
 
function TDropURLSource.CutOrCopyToClipboard: boolean;
var
FormatEtcIn: TFormatEtc;
Medium: TStgMedium;
begin
result := false;
FormatEtcIn.cfFormat := CF_URL;
FormatEtcIn.dwAspect := DVASPECT_CONTENT;
FormatEtcIn.tymed := TYMED_HGLOBAL;
if fURL = '' then exit;
if GetData(formatetcIn,Medium) = S_OK then
begin
Clipboard.SetAsHandle(CF_URL,Medium.hGlobal);
result := true;
end else exit;
 
//render several formats...
FormatEtcIn.cfFormat := CF_TEXT;
FormatEtcIn.dwAspect := DVASPECT_CONTENT;
FormatEtcIn.tymed := TYMED_HGLOBAL;
if GetData(formatetcIn,Medium) = S_OK then
begin
Clipboard.SetAsHandle(CF_TEXT,Medium.hGlobal);
result := true;
end;
end;
// -----------------------------------------------------------------------------
 
function TDropURLSource.DoGetData(const FormatEtcIn: TFormatEtc; OUT Medium: TStgMedium):HRESULT;
const
URLPrefix = '[InternetShortcut]'#10'URL=';
var
pFGD: PFileGroupDescriptor;
pText: PChar;
begin
 
Medium.tymed := 0;
Medium.UnkForRelease := NIL;
Medium.hGlobal := 0;
 
//--------------------------------------------------------------------------
if ((FormatEtcIn.cfFormat = CF_URL) or (FormatEtcIn.cfFormat = CF_TEXT)) and
(FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
(FormatEtcIn.tymed and TYMED_HGLOBAL <> 0) then
begin
Medium.hGlobal := GlobalAlloc(GMEM_SHARE or GHND, Length(fURL)+1);
if (Medium.hGlobal = 0) then
result := E_OUTOFMEMORY
else
begin
medium.tymed := TYMED_HGLOBAL;
pText := PChar(GlobalLock(Medium.hGlobal));
try
StrCopy(pText, PChar(fURL));
finally
GlobalUnlock(Medium.hGlobal);
end;
result := S_OK;
end;
end
//--------------------------------------------------------------------------
else if (FormatEtcIn.cfFormat = CF_FILECONTENTS) and
(FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
(FormatEtcIn.tymed and TYMED_HGLOBAL <> 0) then
begin
Medium.hGlobal := GlobalAlloc(GMEM_SHARE or GHND, Length(URLPrefix + fURL)+1);
if (Medium.hGlobal = 0) then
result := E_OUTOFMEMORY
else
begin
medium.tymed := TYMED_HGLOBAL;
pText := PChar(GlobalLock(Medium.hGlobal));
try
StrCopy(pText, PChar(URLPrefix + fURL));
finally
GlobalUnlock(Medium.hGlobal);
end;
result := S_OK;
end;
end
//--------------------------------------------------------------------------
else if (FormatEtcIn.cfFormat = CF_FILEGROUPDESCRIPTOR) and
(FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
(FormatEtcIn.tymed and TYMED_HGLOBAL <> 0) then
begin
Medium.hGlobal := GlobalAlloc(GMEM_SHARE or GHND, SizeOf(TFileGroupDescriptor));
if (Medium.hGlobal = 0) then
begin
result := E_OUTOFMEMORY;
Exit;
end;
medium.tymed := TYMED_HGLOBAL;
pFGD := pointer(GlobalLock(Medium.hGlobal));
try
with pFGD^ do
begin
cItems := 1;
fgd[0].dwFlags := FD_LINKUI;
if title = '' then
StrPCopy(fgd[0].cFileName,ConvertURLToFilename(fURL))
else
StrPCopy(fgd[0].cFileName,ConvertURLToFilename(fTitle));
end;
finally
GlobalUnlock(Medium.hGlobal);
end;
result := S_OK;
//--------------------------------------------------------------------------
end else
result := DV_E_FORMATETC;
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
 
end.
/trunk/VCL_DRAGDROP/DropURLTarget.dcr
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/DropURLTarget.pas
0,0 → 1,262
unit DropURLTarget;
 
// -----------------------------------------------------------------------------
// Project: Drag and Drop Component Suite
// Component Names: TDropURLTarget
// Module: DropURLTarget
// Description: Implements Dragging & Dropping of URLs
// TO your application from another.
// Version: 3.7
// Date: 22-APR-1999
// Target: Win32, Delphi 3 - Delphi 5, C++ Builder 3, C++ Builder 4
// Authors: Angus Johnson, ajohnson@rpi.net.au
// Anders Melander, anders@melander.dk
// http://www.melander.dk
// Copyright © 1997-99 Angus Johnson & Anders Melander
// -----------------------------------------------------------------------------
 
interface
 
uses
DropSource, DropTarget,
Classes, ActiveX;
 
{$include DragDrop.inc}
 
type
TDropURLTarget = class(TDropTarget)
private
URLFormatEtc,
FileContentsFormatEtc,
FGDFormatEtc: TFormatEtc;
fURL: String;
fTitle: String;
protected
procedure ClearData; override;
function DoGetData: boolean; override;
function HasValidFormats: boolean; override;
public
constructor Create(AOwner: TComponent); override;
property URL: String Read fURL Write fURL;
property Title: String Read fTitle Write fTitle;
end;
 
procedure Register;
 
implementation
 
uses
Windows,
SysUtils,
ShlObj;
 
procedure Register;
begin
RegisterComponents('DragDrop', [TDropURLTarget]);
end;
// -----------------------------------------------------------------------------
 
function GetURLFromFile(const Filename: string; var URL: string): boolean;
var
URLfile : TStringList;
i : integer;
s : string;
p : PChar;
begin
Result := False;
URLfile := TStringList.Create;
try
URLFile.LoadFromFile(Filename);
i := 0;
while (i < URLFile.Count-1) do
begin
if (CompareText(URLFile[i], '[InternetShortcut]') = 0) then
begin
inc(i);
while (i < URLFile.Count) do
begin
s := URLFile[i];
p := PChar(s);
if (StrLIComp(p, 'URL=', length('URL=')) = 0) then
begin
inc(p, length('URL='));
URL := p;
Result := True;
exit;
end else
if (p^ = '[') then
exit;
inc(i);
end;
end;
inc(i);
end;
finally
URLFile.Free;
end;
end;
 
// -----------------------------------------------------------------------------
// TDropURLTarget
// -----------------------------------------------------------------------------
 
constructor TDropURLTarget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
DragTypes := [dtLink]; //Only allow links.
GetDataOnEnter := true;
with URLFormatEtc do
begin
cfFormat := CF_URL;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := -1;
tymed := TYMED_HGLOBAL;
end;
with FileContentsFormatEtc do
begin
cfFormat := CF_FILECONTENTS;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := 0;
tymed := TYMED_HGLOBAL;
end;
with FGDFormatEtc do
begin
cfFormat := CF_FILEGROUPDESCRIPTOR;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := -1;
tymed := TYMED_HGLOBAL;
end;
end;
// -----------------------------------------------------------------------------
 
//This demonstrates how to enumerate all DataObject formats.
function TDropURLTarget.HasValidFormats: boolean;
var
GetNum, GotNum: longint;
FormatEnumerator: IEnumFormatEtc;
tmpFormatEtc: TformatEtc;
begin
result := false;
//Enumerate available DataObject formats
//to see if any one of the wanted formats is available...
if (DataObject.EnumFormatEtc(DATADIR_GET,FormatEnumerator) <> S_OK) or
(FormatEnumerator.Reset <> S_OK) then
exit;
GetNum := 1; //get one at a time...
while (FormatEnumerator.Next(GetNum, tmpFormatEtc, @GotNum) = S_OK) and
(GetNum = GotNum) do
with tmpFormatEtc do
if (ptd = nil) and (dwAspect = DVASPECT_CONTENT) and
{(lindex <> -1) or} (tymed and TYMED_HGLOBAL <> 0) and
((cfFormat = CF_URL) or (cfFormat = CF_FILECONTENTS) or
(cfFormat = CF_HDROP) or (cfFormat = CF_TEXT)) then
begin
result := true;
break;
end;
end;
// -----------------------------------------------------------------------------
 
procedure TDropURLTarget.ClearData;
begin
fURL := '';
end;
// -----------------------------------------------------------------------------
 
function TDropURLTarget.DoGetData: boolean;
var
medium: TStgMedium;
cText: pchar;
tmpFiles: TStringList;
pFGD: PFileGroupDescriptor;
begin
fURL := '';
fTitle := '';
result := false;
//--------------------------------------------------------------------------
if (DataObject.GetData(URLFormatEtc, medium) = S_OK) then
begin
try
if (medium.tymed <> TYMED_HGLOBAL) then
exit;
cText := PChar(GlobalLock(medium.HGlobal));
fURL := cText;
GlobalUnlock(medium.HGlobal);
result := true;
finally
ReleaseStgMedium(medium);
end;
end
//--------------------------------------------------------------------------
else if (DataObject.GetData(TextFormatEtc, medium) = S_OK) then
begin
try
if (medium.tymed <> TYMED_HGLOBAL) then
exit;
cText := PChar(GlobalLock(medium.HGlobal));
fURL := cText;
GlobalUnlock(medium.HGlobal);
result := true;
finally
ReleaseStgMedium(medium);
end;
end
//--------------------------------------------------------------------------
else if (DataObject.GetData(FileContentsFormatEtc, medium) = S_OK) then
begin
try
if (medium.tymed <> TYMED_HGLOBAL) then
exit;
cText := PChar(GlobalLock(medium.HGlobal));
fURL := cText;
fURL := copy(fURL,24,250);
GlobalUnlock(medium.HGlobal);
result := true;
finally
ReleaseStgMedium(medium);
end;
end
//--------------------------------------------------------------------------
else if (DataObject.GetData(HDropFormatEtc, medium) = S_OK) then
begin
try
if (medium.tymed <> TYMED_HGLOBAL) then exit;
tmpFiles := TStringList.create;
try
if GetFilesFromHGlobal(medium.HGlobal,TStrings(tmpFiles)) and
(lowercase(ExtractFileExt(tmpFiles[0])) = '.url') and
GetURLFromFile(tmpFiles[0], fURL) then
begin
fTitle := extractfilename(tmpFiles[0]);
delete(fTitle,length(fTitle)-3,4); //deletes '.url' extension
result := true;
end;
finally
tmpFiles.free;
end;
finally
ReleaseStgMedium(medium);
end;
end;
 
if (DataObject.GetData(FGDFormatEtc, medium) = S_OK) then
begin
try
if (medium.tymed <> TYMED_HGLOBAL) then exit;
pFGD := pointer(GlobalLock(medium.HGlobal));
fTitle := pFGD^.fgd[0].cFileName;
GlobalUnlock(medium.HGlobal);
delete(fTitle,length(fTitle)-3,4); //deletes '.url' extension
finally
ReleaseStgMedium(medium);
end;
end
else if fTitle = '' then fTitle := fURL;
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
 
end.
/trunk/VCL_DRAGDROP/dragdropC3.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/dragdropC4.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/VCL_DRAGDROP/dragdropC5.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property