cxshellcommon.pas

来自「胜天进销存源码,国产优秀的进销存」· PAS 代码 · 共 2,198 行 · 第 1/5 页

PAS
2,198
字号
    property OpenIconIndex:Integer read FOpenIconIndex;
    property pidl:PItemIDList read Fpidl;
    property Updated:Boolean read FUpdated write FUpdated;
  end;

  PcxShellItemInfo = TcxShellItemInfo;

  { TcxShellItemsInfoGatherer }

  TcxShellItemsInfoGatherer = class
  private
    FFetchQueue: TList;
    FFetchStoppedEvent: THandle;
    FFetchThread: THandle;
    FIsFetchQueueClearing: Boolean;
    FOwner: TWinControl;
    FStopFetchCount: Integer;
    FStopFetchEvent: THandle;
    FTerminateFetchThreadEvent: THandle;
    procedure CreateFetchThread;
    function CreateRequestItem(AItemProducer: TcxCustomItemProducer;
      AIndex: Integer; APriority: Boolean): PcxRequestItem;
    function GetFetchQueueItemIndex(AFetchQueue: TList;
      AItemProducer: TcxCustomItemProducer; AIndex: Integer): Integer;
    function GetIsFetchStopping: Boolean;
    function GetIsFetchThreadTerminating: Boolean;
    procedure FetchResumed;
    procedure FetchStopped;
    procedure InternalCloseHandle(var AHandle: THandle);
    procedure TerminateFetchThread;
    property FetchQueue: TList read FFetchQueue;
    property IsFetchStopping: Boolean read GetIsFetchStopping;
    property IsFetchThreadTerminating: Boolean read GetIsFetchThreadTerminating;
  protected
    procedure DestroyFetchThread;
  public
    constructor Create(AOwner: TWinControl);
    destructor Destroy; override;
    procedure ClearFetchQueue(AItemProducer: TcxCustomItemProducer);
    procedure RequestItemInfo(AItemProducer: TcxCustomItemProducer;
      AIndex: Integer; APriority: Boolean);
    procedure ResumeFetch;
    procedure StopFetch;
  end;

  TcxCustomItemProducer=class
  private
    FDetails: TcxShellDetails;
    FFolderPidl: PItemIDList;
    FItems: TList;
    FItemsLock: TMultiReadExclusiveWriteSynchronizer;
    FOwner: TWinControl;
    FShellFolder: IShellFolder;
  protected
    function AllowBackgroundProcessing: Boolean; virtual; abstract;
    function CanAddFolder(AFolder: TcxShellFolder): Boolean; virtual;
    function DoCompareItems(AItem1, AItem2: TcxShellFolder;
      out ACompare: Integer): Boolean; virtual;
    procedure DoSort; virtual;
    procedure FetchItems(cPreloadItems:Integer);
    function GetEnumFlags:Cardinal;virtual;abstract;
    function GetItemsInfoGatherer: TcxShellItemsInfoGatherer; virtual; abstract;
    function GetShowToolTip:Boolean;virtual;abstract;
    procedure InitializeItem(Item:TcxShellItemInfo);virtual;
    procedure CheckForSubitems(AItem: TcxShellItemInfo); virtual;
    procedure ClearFetchQueue;
    property ItemsLock:TMultiReadExclusiveWriteSynchronizer read FItemsLock;
    property ShellFolder:IShellFolder read FShellFolder;
    property FolderPidl:PItemIDList read FFolderPidl write FFolderPidl;
    property Owner:TWinControl read FOwner;
  public
    constructor Create(AOwner:TWinControl);virtual;
    destructor Destroy;override;
    procedure ProcessItems(AIFolder: IShellFolder; AFolderPIDL: PItemIDList;
      cPreloadItems: Integer); virtual;
    procedure ProcessDetails(ShellFolder:IShellFolder;CharWidth:Integer);virtual;
    procedure FetchRequest(AIndex: Integer; APriority: Boolean = False);
    procedure ClearItems;
    procedure LockRead;
    procedure LockWrite;
    procedure UnlockRead;
    procedure UnlockWrite;
    procedure RequestItemsInfo;
    procedure SetItemsCount(Count:Integer);virtual;
    procedure NotifyUpdateItem(AItem: PcxRequestItem); virtual; abstract;
    procedure NotifyRemoveItem(Index:Integer);virtual;
    procedure NotifyAddItem(Index:Integer);virtual;
    procedure DoGetInfoTip(Handle:HWND;ItemIndex: Integer; InfoTip: PChar; cch:Integer);
    function GetItemByPidl(apidl:PItemIDList):TcxShellItemInfo;
    function GetItemIndexByPidl(apidl:PItemIDList):Integer;
    procedure Sort;
    property Details:TcxShellDetails read FDetails;
    property Items:TList read FItems;
    property ItemsInfoGatherer: TcxShellItemsInfoGatherer read GetItemsInfoGatherer;
  end;

  TcxDragDropSettings = class(TPersistent)
  private
    FAllowDragObjects: Boolean;
    FDefaultDropEffect: TcxDropEffect;
    FDropEffect: TcxDropEffectSet;
    FScroll: Boolean;
    FOnChange: TNotifyEvent;
    function GetDefaultDropEffectAPI: Integer;
    function GetDropEffectAPI: DWORD;
    procedure SetAllowDragObjects(Value: Boolean);
  protected
    procedure Changed;
  public
    property DropEffectAPI: DWORD read GetDropEffectApi;
    property DefaultDropEffectAPI: Integer read GetDefaultDropEffectAPI;
    constructor Create;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  published
    property AllowDragObjects: Boolean read FAllowDragObjects
      write SetAllowDragObjects default True;
    property DefaultDropEffect: TcxDropEffect read FDefaultDropEffect
      write FDefaultDropEffect default deMove;
    property DropEffect: TcxDropEffectSet read FDropEffect write FDropEffect
      default [deCopy, deMove, deLink];
    property Scroll: Boolean read FScroll write FScroll stored False; // deprecated
  end;

  TShChangeNotifyEntry = packed record
    pidlPath: PItemIDList;
    bWatchSubtree: BOOL;
  end;

  DWORDITEMID=record
    cb: SHORT;
    dwItem1: DWORD;
    dwItem2: DWORD;
  end;

  PDWORDITEMID=^DWORDITEMID;

  PShChangeNotifyEntry = ^TShChangeNotifyEntry;

function GetDesktopIShellFolder: IShellFolder;
function GetTextFromStrRet(var AStrRet: TStrRet; APIDL: PitemIDList): WideString;
function GetShellDetails(pFolder:IShellFolder;pidl:PItemIDList;out sd:IShellDetails):Hresult;
function HasSubItems(AParentIFolder: IShellFolder; AFullPIDL: PItemIDList;
  AEnumSettings: Cardinal): Boolean;
function cxFileTimeToDateTime(fTime:FILETIME):TDateTime;
function cxMalloc: IMalloc;
procedure DisplayContextMenu(AWnd: HWND; AIFolder: IShellFolder;
  AItemPIDLList: TList; const APos: TPoint);

{ Pidl Tools}

function GetPidlItemsCount(pidl:PItemIDList):Integer;
function GetPidlSize(pidl:PItemIDList):Integer;
function GetNextItemID(pidl:PItemIDList):PItemIDList;
function GetPidlCopy(pidl:PItemIDList):PItemIDList;
function GetLastPidlItem(pidl:PItemIDList):PItemIDList;
function GetPidlName(APIDL: PItemIDList): WideString;
function ConcatenatePidls(pidl1,pidl2:PItemIDList):PItemIDList;
procedure DisposePidl(pidl:PItemIDList);
function GetPidlParent(pidl:PItemIDList):PItemIDList;
function CreateEmptyPidl:PItemIDList;
function CreatePidlListFromList(List:TList):PItemIDList;
function ExtractParticularPidl(pidl:PItemIDList):PItemIDList;
function EqualPIDLs(APIDL1, APIDL2: PItemIDList): Boolean;
function IsSubPath(APIDL1, APIDL2: PItemIDList): Boolean;

{ Unicode Tools }

procedure StrPLCopyW(Dest:PWideChar;Source:WideString;MaxLen:Cardinal);
function StrPasW(Source:PWideChar):WideString;
function StrLenW(Source:PWideChar):Cardinal;
function UpperCaseW(Source:WideString):WideString;
function LowerCaseW(Source:WideString):WideString;

procedure CheckShellRoot(ARoot: TcxCustomShellRoot);
function GetShellItemDisplayName(AIFolder: IShellFolder;
  APIDL: PItemIDList; ACheckIsFolder: Boolean): WideString;

const
  DSM_SETCOUNT=CM_BASE+315;
  DSM_NOTIFYUPDATE=CM_BASE+316;
  DSM_NOTIFYREMOVEITEM=CM_BASE+318;
  DSM_NOTIFYADDITEM=CM_BASE+319;
  DSM_NOTIFYUPDATECONTENTS=CM_BASE+320;
  DSM_SHELLCHANGENOTIFY=CM_BASE+321;
  DSM_DONAVIGATE=CM_BASE+322;
  DSM_SYNCHRONIZEROOT=CM_BASE+323;
  DSM_SHELLTREECHANGENOTIFY=CM_BASE+324;
  DSM_SHELLTREERESTORECURRENTPATH=CM_BASE+325;

  PRELOAD_ITEMS_COUNT=10;

  SHCNF_ACCEPT_INTERRUPTS =     $1;
  SHCNF_ACCEPT_NON_INTERRUPTS = $2;
  SHCNF_NO_PROXY =              $8000;

var
  SHChangeNotifyRegister:function (hwnd:HWND;dwFlags:DWORD;wEventMask:DWORD;
           uMsg:UINT;cItems:DWORD;lpItems:PShChangeNotifyEntry):Cardinal;stdcall;
  SHChangeNotifyUnregister:function (hNotify:Cardinal):Boolean;stdcall;

implementation

uses
  cxContainer, cxControls, cxEdit, dxUxTheme;

const
  ShellLibraryName = 'shell32.dll';
{$IFNDEF DELPHI6}
  PathDelim  = '\';
  cxIID_IShellFolder2: TGUID = (
    D1:$93F2F68C; D2:$1D1B; D3:$11D3; D4:($A3,$0E,$00,$C0,$4F,$79,$AB,$D1));
{$ENDIF}
  SFGAO_ENCRYPTED       = $00002000;
  SFGAO_ISSLOW          = $00004000;
  SFGAO_STORAGE         = $00000008;
  SFGAO_STORAGEANCESTOR = $00800000;
  SFGAO_STORAGECAPMASK  = $70C50008;
  SFGAO_STREAM          = $00400000;

type
  TcxContextMenuMessageWindow = class(TcxMessageWindow)
  private
    FContextMenu: IContextMenu2;
  protected
    procedure WndProc(var Message: TMessage); override;
  public
    property ContextMenu: IContextMenu2 read FContextMenu write FContextMenu;
  end;

  TSHGetPathFromIDList = function(APIDL: PItemIDList; APath: PChar): BOOL; stdcall;
  TSHGetPathFromIDListW = function(APIDL: PItemIDList; APath: PWideChar): BOOL; stdcall;

{$IFDEF DELPHI6}
  cxIShellFolder2 = interface(IShellFolder2)
    ['{93F2F68C-1D1B-11D3-A30E-00C04F79ABD1}']
  end;
{$ENDIF}

var
  FSysFileIconIndex: Integer = -1;
  FSysFolderIconIndex: Integer = -1;
  FSysFolderOpenIconIndex: Integer = -1;
  cxSHGetFolderLocation:function (wnd:HWND;nFolder:Integer;hToken:THandle;
             dwReserwed:DWORD;var ppidl:PItemIDList):HResult;stdcall;
  cxSHGetPathFromIDList: TSHGetPathFromIDList = nil;
  cxSHGetPathFromIDListW: TSHGetPathFromIDListW = nil;
  ShellLibrary: HMODULE = 0;
  FcxMalloc: IMalloc;
  FShellItemsInfoGatherers: TList;

(*function GetShellItemDisplayName(AIFolder: IShellFolder;
  APIDL: PItemIDList; ACheckIsFolder: Boolean): WideString;
var
  AAttributes, AFlags: Cardinal;
  AIsFolder: Boolean;
  AStrRet: TStrRet;
begin
  Result := '';

  if ACheckIsFolder then
  begin
    AAttributes := SFGAO_FOLDER;
    if not Succeeded(AIFolder.GetAttributesOf(1, APIDL, AAttributes)) then
      Exit;
    AIsFolder := AAttributes and SFGAO_FOLDER <> 0;
  end
  else
    AIsFolder := False;

  AFlags := SHGDN_INFOLDER;
  if AIsFolder then
    AFlags := AFlags or SHGDN_FORPARSING;

  if not Succeeded(AIFolder.GetDisplayNameOf(APIDL, AFlags, AStrRet)) then
    Exit;
  Result := GetTextFromStrRet(AStrRet, APIDL);
  if AIsFolder and (Length(Result) > 2) then
    if (Result[1] = ':') and (Result[2] = ':') or
      (Result[1] = '\') and (Result[2] = '\') then
    begin
      AIFolder.GetDisplayNameOf(APIDL, SHGDN_INFOLDER, AStrRet);
      Result := GetTextFromStrRet(AStrRet, APIDL);
    end;
end;*)

procedure CheckShellRoot(ARoot: TcxCustomShellRoot);
begin
  if ARoot.ShellFolder = nil then
    ARoot.CheckRoot;
end;

function GetShellItemDisplayName(AIFolder: IShellFolder;
  APIDL: PItemIDList; ACheckIsFolder: Boolean): WideString;
var
  AStrRet: TStrRet;
begin
  if Succeeded(AIFolder.GetDisplayNameOf(APIDL, SHGDN_INFOLDER, AStrRet)) then
    Result := GetTextFromStrRet(AStrRet, APIDL)
  else
    Result := '';
end;

function HasSubItems(AParentIFolder: IShellFolder; AFullPIDL: PItemIDList;
  AEnumSettings: Cardinal): Boolean;

  function HasAttributes(AAttributes: UINT): Boolean;
  var
    ATempAttributes: UINT;
    ATempPIDL: PItemIDList;
  begin
    ATempAttributes := AAttributes;
    ATempPIDL := GetLastPidlItem(AFullPIDL);
    AParentIFolder.GetAttributesOf(1, ATempPIDL, ATempAttributes);
    Result := ATempAttributes and AAttributes = AAttributes;
  end;

  function CheckLocalFolder(out AHasSubItems: Boolean): Boolean;
  var
    AAttributes, AParsedCharCount: ULONG;
    ADesktopIFolder: IShellFolder;
    AFileSearchAttributes: Integer;
    ATempPIDL: PItemIDList;
    ASearchRec: TSearchRec;
    S: WideString;
  begin
    Result := False;
    S := GetPidlName(AFullPIDL);
    if (S = '')(* or (Pos('\\', S) = 1)*) then
      Exit;
    SHGetDesktopFolder(ADesktopIFolder);
    AAttributes := 0;
    ADesktopIFolder.ParseDisplayName(0, nil, PWideChar(S),
      AParsedCharCount, ATempPIDL, AAttributes);
    if ATempPIDL = nil then
      Exit;
    try
      Result := True;
      AHasSubItems := False;

      AFileSearchAttributes := faReadOnly or faSysFile or faArchive;
      if AEnumSettings and SHCONTF_FOLDERS <> 0 then
        AFileSearchAttributes := AFileSearchAttributes or faDirectory;
      if AEnumSettings and SHCONTF_INCLUDEHIDDEN <> 0 then
        AFileSearchAttributes := AFileSearchAttributes or faHidden;

      if S[Length(S)] = PathDelim then
        Delete(S, Length(S), 1);
      if FindFirst(S + PathDelim + '*.*', AFileSearchAttributes, ASearchRec) = 0 then
      begin
        repeat
          if (ASearchRec.Name = '.') or (ASearchRec.Name = '..') then
          begin
            if FindNext(ASearchRec) <> 0 then
              Break;
          end
          else
          begin
            AHasSubItems := True;
            Break;
          end;
        until False;
        FindClose(ASearchRec);
      end;
    finally
      DisposePidl(ATempPIDL);
    end;
  end;

var
  ATempIFolder: IShellFolder;
  ATempPIDL: PItemIDList;
  AIEnum: IEnumIDList;
  AFetchedItemCount: Cardinal;
begin
  Result := HasAttributes(SFGAO_FOLDER);
  if not Result then
    Exit;
//  if (AEnumSettings and SHCONTF_NONFOLDERS = 0) and AFast then
  if AEnumSettings and SHCONTF_NONFOLDERS = 0 then
    Result := HasAttributes(SFGAO_HASSUBFOLDER)
  else
  begin
    if CheckLocalFolder(Result) then
      Exit;
    Result := False;
    if Succeeded(AParentIFolder.BindToObject(GetLastPidlItem(AFullPIDL), nil, IID_IShellFolder,
      ATempIFolder)) then
        if ATempIFolder <> nil then
          if Succeeded(ATempIFolder.EnumObjects(0, AEnumSettings, AIEnum)) and Assigned(AIEnum) then
            if AIEnum.Next(1, ATempPIDL, AFetchedItemCount) = S_OK then
            try
              Result := AFetchedItemCount = 1;
            finally
              DisposePidl(ATempPIDL);
            end;
  end;
end;

function GetDesktopIShellFolder: IShellFolder;
begin
  OleCheck(SHGetDesktopFolder(Result));
end;

function GetTextFromStrRet(var AStrRet: TStrRet; APIDL: PitemIDList): WideString;
var
  P: PChar;
begin
  case AStrRet.uType of
    STRRET_CSTR:
      SetString(Result, AStrRet.cStr, lstrlen(AStrRet.cStr));
    STRRET_OFFSET:
      begin
        P := @APIDL.mkid.abID;
        Inc(P, AStrRet.uOffset - SizeOf(APIDL.mkid.cb));
        SetString(Result, P, APIDL.mkid.cb - AStrRet.uOffset);
      end;
    STRRET_WSTR:
      begin
        Result := StrPasW(AStrRet.pOleStr);
        cxMalloc.Free(AStrRet.pOleStr);
      end;
  end;
end;

function GetShellDetails(pFolder:IShellFolder;pidl:PItemIDList;out sd:IShellDetails):Hresult;
begin
  try
    Result := pFolder.QueryInterface(IID_IShellDetails, sd);
    if Result = S_OK then
       Exit;
    Result:=pFolder.GetUIObjectOf(0,0,pidl,IID_IShellDetails,nil,sd);
    if Result = S_OK then
       Exit;
    Result:=pFolder.CreateViewObject(0,IID_IShellDetails,sd);
    if Result = S_OK then
       Exit;
    Result:=pFolder.GetUIObjectOf(0,Integer(pidl<>nil)(*1*),pidl,IID_IShellDetails,nil,sd);
  finally
    if sd = nil then
      Result := E_NOINTERFACE;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?