Subversion Repositories decoder

Rev

Blame | Last modification | View Log | RSS feed

  1. unit DropPIDLTarget;
  2.  
  3. // -----------------------------------------------------------------------------
  4. // Project:         Drag and Drop Component Suite
  5. // Component Names: TDropPIDLTarget
  6. // Module:          DropPIDLTarget
  7. // Description:     Implements Dragging & Dropping of PIDLs
  8. //                  TO your application from another.
  9. // Version:         3.7
  10. // Date:            22-JUL-1999
  11. // Target:          Win32, Delphi 3 - Delphi 5, C++ Builder 3, C++ Builder 4
  12. // Authors:         Angus Johnson,   ajohnson@rpi.net.au
  13. //                  Anders Melander, anders@melander.dk
  14. //                                   http://www.melander.dk
  15. // Copyright        © 1997-99 Angus Johnson & Anders Melander
  16. // -----------------------------------------------------------------------------
  17.  
  18.  
  19. interface
  20.  
  21. uses
  22.   DropSource, DropTarget,
  23.   Classes, ActiveX, ShlObj;
  24.  
  25. {$include DragDrop.inc}
  26.  
  27. type
  28.   TDropPIDLTarget = class(TDropTarget)
  29.   private
  30.     PIDLFormatEtc,
  31.     fFileNameMapFormatEtc,
  32.     fFileNameMapWFormatEtc: TFormatEtc;
  33.     fPIDLs: TStrings; // Used internally to store PIDLs. I use strings to simplify cleanup.
  34.     fFiles: TStrings; // List of filenames (paths)
  35.     fMappedNames: TStrings;
  36.     function GetPidlCount: integer;
  37.   protected
  38.     procedure ClearData; override;
  39.     function DoGetData: boolean; override;
  40.     function HasValidFormats: boolean; override;
  41.   public
  42.     constructor Create(AOwner: TComponent); override;
  43.     destructor Destroy; Override;
  44.  
  45.     function GetFolderPidl: pItemIdList;
  46.     function GetRelativeFilePidl(index: integer): pItemIdList;
  47.     function GetAbsoluteFilePidl(index: integer): pItemIdList;
  48.     function PasteFromClipboard: longint; Override;
  49.     property PidlCount: integer read GetPidlCount; //includes folder pidl in count
  50.     //If you just want the filenames (not PIDLs) then use ...
  51.     property Filenames: TStrings read fFiles;
  52.     //MappedNames is only needed if files need to be renamed after a drag op
  53.     //eg dragging from 'Recycle Bin'.
  54.     property MappedNames: TStrings read fMappedNames;
  55.   end;
  56.  
  57. procedure Register;
  58.  
  59. implementation
  60.  
  61. uses
  62.   DropPIDLSource,
  63.   Windows,
  64.   SysUtils,
  65.   ClipBrd;
  66.  
  67. procedure Register;
  68. begin
  69.   RegisterComponents('DragDrop', [TDropPIDLTarget]);
  70. end;
  71.  
  72. // -----------------------------------------------------------------------------
  73. //                      Miscellaneous Functions...
  74. // -----------------------------------------------------------------------------
  75.  
  76. function GetPidlsFromHGlobal(const HGlob: HGlobal; var Pidls: TStrings): boolean;
  77. var
  78.   i: integer;
  79.   pInt: ^UINT;
  80.   pCIDA: PIDA;
  81. begin
  82.   result := false;
  83.   pCIDA := PIDA(GlobalLock(HGlob));
  84.   try
  85.     pInt := @(pCIDA^.aoffset[0]);
  86.     for i := 0 to pCIDA^.cidl do
  87.     begin
  88.       Pidls.add(PidlToString(pointer(UINT(pCIDA)+ pInt^)));
  89.       inc(pInt);
  90.     end;
  91.     if Pidls.count > 1 then result := true;
  92.  finally
  93.     GlobalUnlock(HGlob);
  94.   end;
  95. end;
  96.  
  97. {By implementing the following TStrings class, component processing is reduced.}
  98. // -----------------------------------------------------------------------------
  99. //                      TPIDLTargetStrings
  100. // -----------------------------------------------------------------------------
  101.  
  102. type
  103.   TPIDLTargetStrings = class(TStrings)
  104.   private
  105.     DropPIDLTarget: TDropPIDLTarget;
  106.   protected
  107.     function Get(Index: Integer): string; override;
  108.     function GetCount: Integer; override;
  109.     procedure Put(Index: Integer; const S: string); override;
  110.     procedure PutObject(Index: Integer; AObject: TObject); override;
  111.   public
  112.     procedure Clear; override;
  113.     procedure Delete(Index: Integer); override;
  114.     procedure Insert(Index: Integer; const S: string); override;
  115.   end;
  116.  
  117. // -----------------------------------------------------------------------------
  118.  
  119. function TPIDLTargetStrings.Get(Index: Integer): string;
  120. var
  121.   PidlStr: string;
  122.   buff: array [0..MAX_PATH] of char;
  123. begin
  124.   with DropPIDLTarget do
  125.   begin
  126.     if (Index < 0) or (Index > fPIDLs.count-2) then
  127.       raise Exception.create('Filename index out of range');
  128.     PidlStr := JoinPidlStrings(fPIDLs[0], fPIDLs[Index+1]);
  129.     if SHGetPathFromIDList(PItemIDList(pChar(PidlStr)),buff) then
  130.       result := buff else
  131.       result := '';
  132.   end;
  133. end;
  134. // -----------------------------------------------------------------------------
  135.  
  136. function TPIDLTargetStrings.GetCount: Integer;
  137. begin
  138.   with DropPIDLTarget do
  139.     if fPIDLs.count < 2 then
  140.       result := 0 else
  141.       result := fPIDLs.count-1;
  142. end;
  143. // -----------------------------------------------------------------------------
  144.  
  145. //Overriden abstract methods which do not need implementation...
  146.  
  147. procedure TPIDLTargetStrings.Put(Index: Integer; const S: string);
  148. begin
  149. end;
  150. // -----------------------------------------------------------------------------
  151.  
  152. procedure TPIDLTargetStrings.PutObject(Index: Integer; AObject: TObject);
  153. begin
  154. end;
  155. // -----------------------------------------------------------------------------
  156.  
  157. procedure TPIDLTargetStrings.Clear;
  158. begin
  159. end;
  160. // -----------------------------------------------------------------------------
  161.  
  162. procedure TPIDLTargetStrings.Delete(Index: Integer);
  163. begin
  164. end;
  165. // -----------------------------------------------------------------------------
  166.  
  167. procedure TPIDLTargetStrings.Insert(Index: Integer; const S: string);
  168. begin
  169. end;
  170.  
  171. // -----------------------------------------------------------------------------
  172. //                      TDropPIDLTarget
  173. // -----------------------------------------------------------------------------
  174.  
  175. constructor TDropPIDLTarget.Create(AOwner: TComponent);
  176. begin
  177.   inherited Create(AOwner);
  178.   fPIDLs := TStringList.create;
  179.   fFiles := TPIDLTargetStrings.create;
  180.   TPIDLTargetStrings(fFiles).DropPIDLTarget := self;
  181.   fMappedNames := TStringList.Create;
  182.   //SHGetMalloc(fShellMalloc);
  183.   with PIDLFormatEtc do
  184.   begin
  185.     cfFormat := CF_IDLIST;
  186.     ptd := nil;
  187.     dwAspect := DVASPECT_CONTENT;
  188.     lindex := -1;
  189.     tymed := TYMED_HGLOBAL;
  190.   end;
  191.   with fFileNameMapFormatEtc do
  192.   begin
  193.     cfFormat := CF_FILENAMEMAP;
  194.     ptd := nil;
  195.     dwAspect := DVASPECT_CONTENT;
  196.     lindex := -1;
  197.     tymed := TYMED_HGLOBAL;
  198.   end;
  199.   with fFileNameMapWFormatEtc do
  200.   begin
  201.     cfFormat := CF_FILENAMEMAPW;
  202.     ptd := nil;
  203.     dwAspect := DVASPECT_CONTENT;
  204.     lindex := -1;
  205.     tymed := TYMED_HGLOBAL;
  206.   end;
  207. end;
  208. // -----------------------------------------------------------------------------
  209.  
  210. destructor TDropPIDLTarget.Destroy;
  211. begin
  212.   fPIDLs.free;
  213.   fFiles.free;
  214.   fMappedNames.free;
  215.   inherited Destroy;
  216. end;
  217. // -----------------------------------------------------------------------------
  218.  
  219. function TDropPIDLTarget.HasValidFormats: boolean;
  220. begin
  221.   result := (DataObject.QueryGetData(PIDLFormatEtc) = S_OK);
  222. end;
  223. // -----------------------------------------------------------------------------
  224.  
  225. procedure TDropPIDLTarget.ClearData;
  226. begin
  227.   fPIDLs.clear;
  228.   fMappedNames.clear;
  229. end;
  230. // -----------------------------------------------------------------------------
  231.  
  232. function TDropPIDLTarget.DoGetData: boolean;
  233. var
  234.   medium: TStgMedium;
  235.   pFilename: pChar;
  236.   pFilenameW: PWideChar;
  237.   sFilename: String;
  238. begin
  239.   ClearData;
  240.   result := false;
  241.  
  242.   //--------------------------------------------------------------------------
  243.   if (DataObject.GetData(PIDLFormatEtc, medium) = S_OK) then
  244.   begin
  245.     try
  246.       if (medium.tymed <> TYMED_HGLOBAL) then exit;
  247.       result := GetPidlsFromHGlobal(medium.HGlobal,fPIDLs);
  248.     finally
  249.       ReleaseStgMedium(medium);
  250.     end;
  251.  
  252.     if not result then exit;
  253.     //Now check for FileNameMapping as well ...
  254.     //--------------------------------------------------------------------------
  255.     if (DataObject.GetData(fFileNameMapFormatEtc, medium) = S_OK) then
  256.     begin
  257.       try
  258.         if (medium.tymed = TYMED_HGLOBAL) then
  259.         begin
  260.           pFilename := GlobalLock(medium.HGlobal);
  261.           try
  262.             while true do
  263.             begin
  264.               sFilename := pFilename;
  265.               if sFilename = '' then break;
  266.               fMappedNames.add(sFilename);
  267.               inc(pFilename, length(sFilename)+1);
  268.             end;
  269.             if Filenames.count <> fMappedNames.count then
  270.               fMappedNames.clear;
  271.           finally
  272.             GlobalUnlock(medium.HGlobal);
  273.           end;
  274.         end;
  275.       finally
  276.         ReleaseStgMedium(medium);
  277.       end;
  278.     end
  279.     //WideChar support for WinNT...
  280.     else if (DataObject.GetData(fFileNameMapWFormatEtc, medium) = S_OK) then
  281.     try
  282.       if (medium.tymed = TYMED_HGLOBAL) then
  283.       begin
  284.         pFilenameW := GlobalLock(medium.HGlobal);
  285.         try
  286.           while true do
  287.           begin
  288.             sFilename := WideCharToString(pFilenameW);
  289.             if sFilename = '' then break;
  290.             fMappedNames.add(sFilename);
  291.             inc(pFilenameW, length(sFilename)+1);
  292.           end;
  293.           if fFiles.count <> fMappedNames.count then
  294.             fMappedNames.clear;
  295.         finally
  296.           GlobalUnlock(medium.HGlobal);
  297.         end;
  298.       end;
  299.     finally
  300.       ReleaseStgMedium(medium);
  301.     end;
  302.  
  303.   end;
  304. end;
  305. // -----------------------------------------------------------------------------
  306.  
  307. //Note: It is the component user's responsibility to cleanup
  308. //the returned PIDLs from the following 3 methods.
  309. //Use - CoTaskMemFree() - to free the PIDLs.
  310. function TDropPIDLTarget.GetFolderPidl: pItemIdList;
  311. begin
  312.   result :=nil;
  313.   if fPIDLs.count = 0 then exit;
  314.   result := ShellMalloc.alloc(length(fPIDLs[0]));
  315.   if result <> nil then
  316.     move(pChar(fPIDLs[0])^,result^,length(fPIDLs[0]));
  317. end;
  318. // -----------------------------------------------------------------------------
  319.  
  320. function TDropPIDLTarget.GetRelativeFilePidl(index: integer): pItemIdList;
  321. begin
  322.   result :=nil;
  323.   if (index < 1) or (index >= fPIDLs.count) then exit;
  324.   result := ShellMalloc.alloc(length(fPIDLs[index]));
  325.   if result <> nil then
  326.     move(pChar(fPIDLs[index])^,result^,length(fPIDLs[index]));
  327. end;
  328. // -----------------------------------------------------------------------------
  329.  
  330. function TDropPIDLTarget.GetAbsoluteFilePidl(index: integer): pItemIdList;
  331. var
  332.   s: string;
  333. begin
  334.   result :=nil;
  335.   if (index < 1) or (index >= fPIDLs.count) then exit;
  336.   s := JoinPidlStrings(fPIDLs[0], fPIDLs[index]);
  337.   result := ShellMalloc.alloc(length(s));
  338.   if result <> nil then
  339.     move(pChar(s)^,result^,length(s));
  340. end;
  341. // -----------------------------------------------------------------------------
  342.  
  343. function TDropPIDLTarget.PasteFromClipboard: longint;
  344. var
  345.   Global: HGlobal;
  346.   Preferred: longint;
  347. begin
  348.   result  := DROPEFFECT_NONE;
  349.   if not ClipBoard.HasFormat(CF_IDLIST) then exit;
  350.   Global := Clipboard.GetAsHandle(CF_IDLIST);
  351.   fPIDLs.clear;
  352.   if not GetPidlsFromHGlobal(Global,fPidls) then exit;
  353.   Preferred := inherited PasteFromClipboard;
  354.   //if no Preferred DropEffect then return copy else return Preferred ...
  355.   if (Preferred = DROPEFFECT_NONE) then
  356.     result := DROPEFFECT_COPY else
  357.     result := Preferred;
  358. end;
  359. // -----------------------------------------------------------------------------
  360.  
  361. function TDropPIDLTarget.GetPidlCount: integer;
  362. begin
  363.   result := fPidls.count; //Note: includes folder pidl in count!
  364. end;
  365. // -----------------------------------------------------------------------------
  366. // -----------------------------------------------------------------------------
  367.  
  368. end.
  369.