mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
Getting rid of TDictionary as it crashes 64-bit linker
https://winscp.net/tracker/1016 Source commit: 02d79c8672c60c572c9b722a93dea8b5030ea1fe
This commit is contained in:
@@ -68,7 +68,7 @@
|
||||
<RunBCCOutOfProcess>true</RunBCCOutOfProcess>
|
||||
<SanitizedProjectName>DScpComp</SanitizedProjectName>
|
||||
<SubProcessesNumber>8</SubProcessesNumber>
|
||||
<TLIB_PageSize>64</TLIB_PageSize>
|
||||
<TLIB_PageSize>128</TLIB_PageSize>
|
||||
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <vcl.h>
|
||||
#pragma hdrstop
|
||||
|
||||
#include <Common.h>
|
||||
#include "DirView.h"
|
||||
#include "IEDriveInfo.h"
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -12,3 +13,107 @@ __fastcall TDirView::TDirView(TComponent * AOwner) :
|
||||
{
|
||||
DriveInfoRequire();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TDirView::IconUpdateClear()
|
||||
{
|
||||
FIconUpdateQueue = TIconUpdateQueue();
|
||||
FIconUpdateQueueDeferred = TIconUpdateQueue();
|
||||
FIconUpdateSet.clear();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TDirView::IconUpdateEnqueue(TListItem * ListItem)
|
||||
{
|
||||
if (FIconUpdateSet.find(ListItem->Index) == FIconUpdateSet.end())
|
||||
{
|
||||
TIconUpdateSchedule Schedule { .Index = ListItem->Index };
|
||||
FIconUpdateQueue.push(Schedule);
|
||||
DebugAssert(FIconUpdateSet.size() == FIconUpdateQueue.size() + FIconUpdateQueueDeferred.size());
|
||||
}
|
||||
StartIconUpdateThread();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
int __fastcall TDirView::IconUpdatePeek()
|
||||
{
|
||||
int Result;
|
||||
if (!FIconUpdateQueue.empty())
|
||||
{
|
||||
Result = FIconUpdateQueue.front().Index;
|
||||
}
|
||||
else if (!FIconUpdateQueueDeferred.empty())
|
||||
{
|
||||
Result = FIconUpdateQueueDeferred.front().Index;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = -1;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool __fastcall TDirView::IconUpdateDeprioritize(Dirviewint::TFileRec * ItemData, int Index)
|
||||
{
|
||||
bool Result = !FIconUpdateQueue.empty();
|
||||
if (Result)
|
||||
{
|
||||
DebugAssert(!ThumbnailNeeded(ItemData));
|
||||
if (ItemData->IconEmpty)
|
||||
{
|
||||
TIconUpdateSchedule Schedule = FIconUpdateQueue.front();
|
||||
FIconUpdateQueue.pop();
|
||||
FIconUpdateQueueDeferred.push(Schedule);
|
||||
}
|
||||
else
|
||||
{
|
||||
IconUpdateDequeue(Index);
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TDirView::IconUpdateDequeue(int Index)
|
||||
{
|
||||
if (!FIconUpdateQueue.empty())
|
||||
{
|
||||
FIconUpdateQueue.pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
FIconUpdateQueueDeferred.pop();
|
||||
}
|
||||
FIconUpdateSet.erase(Index);
|
||||
DebugAssert(FIconUpdateSet.size() == FIconUpdateQueue.size() + FIconUpdateQueueDeferred.size());
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TDirView::PathChanged()
|
||||
{
|
||||
TDirViewInt::PathChanged();
|
||||
// make sure to use PathName as Path maybe just X: what
|
||||
// ExpandFileName resolves to current working directory
|
||||
// on the drive, not to root path
|
||||
UnicodeString Expanded = ExpandFileName(PathName);
|
||||
FLastPaths[DriveInfo->GetDriveKey(Expanded)] = Expanded;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool __fastcall TDirView::TryGetLastPath(UnicodeString Drive, UnicodeString & Path)
|
||||
{
|
||||
auto I = FLastPaths.find(Drive);
|
||||
bool Result = (I != FLastPaths.end());
|
||||
if (Result)
|
||||
{
|
||||
Path = I->second;
|
||||
#ifndef DESIGN_ONLY
|
||||
if (!DirectoryExists(ApiPath(Path)))
|
||||
{
|
||||
if (DriveInfo->IsRealDrive(Drive))
|
||||
{
|
||||
Path = FORMAT(L"%s:", (Drive));
|
||||
}
|
||||
else
|
||||
{
|
||||
Path = Drive;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -3,11 +3,30 @@
|
||||
#define DirViewH
|
||||
//---------------------------------------------------------------------------
|
||||
#include "DirViewInt.hpp"
|
||||
#include <set>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
//---------------------------------------------------------------------------
|
||||
class TDirView : public TDirViewInt
|
||||
{
|
||||
public:
|
||||
__fastcall TDirView(TComponent * AOwner);
|
||||
|
||||
protected:
|
||||
virtual void __fastcall IconUpdateClear();
|
||||
virtual void __fastcall IconUpdateEnqueue(TListItem * ListItem);
|
||||
virtual int __fastcall IconUpdatePeek();
|
||||
virtual bool __fastcall IconUpdateDeprioritize(Dirviewint::TFileRec * ItemData, int Index);
|
||||
virtual void __fastcall IconUpdateDequeue(int Index);
|
||||
virtual void __fastcall PathChanged();
|
||||
virtual bool __fastcall TryGetLastPath(UnicodeString Drive, UnicodeString & Path);
|
||||
|
||||
private:
|
||||
std::set<int> FIconUpdateSet;
|
||||
typedef std::queue<TIconUpdateSchedule> TIconUpdateQueue;
|
||||
TIconUpdateQueue FIconUpdateQueue;
|
||||
TIconUpdateQueue FIconUpdateQueueDeferred;
|
||||
std::map<UnicodeString, UnicodeString> FLastPaths;
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <vcl.h>
|
||||
#pragma hdrstop
|
||||
|
||||
#include <Common.h>
|
||||
#include "DriveView.h"
|
||||
#include "IEDriveInfo.h"
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -11,4 +12,47 @@ __fastcall TDriveView::TDriveView(TComponent * AOwner) :
|
||||
TDriveViewInt(AOwner)
|
||||
{
|
||||
DriveInfoRequire();
|
||||
|
||||
FDriveStatus.reset(new TStringList());
|
||||
FDriveStatus->Sorted = true;
|
||||
for (TRealDrive Drive = FirstDrive; Drive <= LastDrive; Drive++)
|
||||
{
|
||||
FDriveStatus->AddObject(Drive, CreateDriveStatus());
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TDriveStatus * __fastcall TDriveView::GetDriveStatus(UnicodeString Drive)
|
||||
{
|
||||
int Index = FDriveStatus->IndexOf(Drive);
|
||||
TDriveStatus * Result;
|
||||
if (Index < 0)
|
||||
{
|
||||
Result = CreateDriveStatus();
|
||||
FDriveStatus->AddObject(Drive, Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = GetDriveStatus(Index);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TDriveStatus * TDriveView::GetDriveStatus(int Index)
|
||||
{
|
||||
return DebugNotNull(dynamic_cast<TDriveStatus *>(FDriveStatus->Objects[Index]));
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool __fastcall TDriveView::GetNextDriveStatus(int & Iterator, UnicodeString * Drive, TDriveStatus *& Status)
|
||||
{
|
||||
bool Result = (Iterator < FDriveStatus->Count);
|
||||
if (Result)
|
||||
{
|
||||
if (Drive != nullptr)
|
||||
{
|
||||
*Drive = FDriveStatus->Strings[Iterator];
|
||||
}
|
||||
Status = GetDriveStatus(Iterator);
|
||||
++Iterator;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,18 @@ class TDriveView : public TDriveViewInt
|
||||
{
|
||||
public:
|
||||
__fastcall TDriveView(TComponent * AOwner);
|
||||
|
||||
virtual TDriveStatus * __fastcall GetDriveStatus(UnicodeString Drive);
|
||||
|
||||
protected:
|
||||
// Using TStringList as it's easy to iterate with int iterator for GetNextDriveStatus.
|
||||
// Once all code is moved here, we can replace it easily with std::map.
|
||||
std::unique_ptr<TStringList> FDriveStatus;
|
||||
|
||||
virtual bool __fastcall GetNextDriveStatus(int & Iterator, UnicodeString * Drive, TDriveStatus *& Status);
|
||||
|
||||
private:
|
||||
TDriveStatus * GetDriveStatus(int Index);
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#include <vcl.h>
|
||||
#pragma hdrstop
|
||||
|
||||
#include <Common.h>
|
||||
#include "IEDriveInfo.h"
|
||||
#include "PasTools.hpp"
|
||||
//---------------------------------------------------------------------------
|
||||
#pragma package(smart_init)
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -18,3 +20,66 @@ __fastcall TDriveInfo::TDriveInfo() :
|
||||
TDriveInfoInt()
|
||||
{
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TDriveInfoRec * __fastcall TDriveInfo::AddDrive(UnicodeString Drive)
|
||||
{
|
||||
TDriveInfoRec * Result = new TDriveInfoRec();
|
||||
FData.insert(std::make_pair(Drive, Result));
|
||||
ResetDrive(Drive);
|
||||
if (IsFixedDrive(Drive) || !IsRealDrive(Drive)) // not floppy
|
||||
{
|
||||
DoReadDriveStatus(Drive, dsSynchronous);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadDriveBasicStatus(Drive);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TDriveInfoRec * __fastcall TDriveInfo::GetInternal(UnicodeString Drive)
|
||||
{
|
||||
auto I = FData.find(Drive);
|
||||
DebugAssert(I != FData.end());
|
||||
return I->second.get();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TDriveInfoRec * __fastcall TDriveInfo::Get(UnicodeString Drive)
|
||||
{
|
||||
NeedData();
|
||||
|
||||
// We might want to wait for FReadyDrives to be empty before returning
|
||||
// (or even better do that only in DriveReady getter)
|
||||
TDriveInfoRec * Result;
|
||||
auto I = FData.find(Drive);
|
||||
if (I == FData.end())
|
||||
{
|
||||
DebugAssert(IsUncPath(Drive));
|
||||
Result = AddDrive(Drive);
|
||||
DriveRefresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = I->second.get();
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TDriveInfo::DriveRemoving(THandle DeviceHandle)
|
||||
{
|
||||
for (auto I = FData.begin(); I != FData.end(); ++I)
|
||||
{
|
||||
if (I->second->DriveHandle == DeviceHandle)
|
||||
{
|
||||
TDriveInfoInt::DriveRemoving(I->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TDriveInfo::UpdateDrivesNotifications()
|
||||
{
|
||||
for (auto I = FData.begin(); I != FData.end(); ++I)
|
||||
{
|
||||
UpdateDriveNotifications(I->first);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,22 @@
|
||||
#define IEDriveInfoH
|
||||
//---------------------------------------------------------------------------
|
||||
#include "IEDriveInfoInt.hpp"
|
||||
#include <map>
|
||||
//---------------------------------------------------------------------------
|
||||
class TDriveInfo : public TDriveInfoInt
|
||||
{
|
||||
public:
|
||||
__fastcall TDriveInfo();
|
||||
|
||||
protected:
|
||||
virtual TDriveInfoRec * __fastcall AddDrive(UnicodeString Drive);
|
||||
virtual TDriveInfoRec * __fastcall GetInternal(UnicodeString Drive);
|
||||
virtual TDriveInfoRec * __fastcall Get(UnicodeString Drive);
|
||||
virtual void __fastcall DriveRemoving(THandle DeviceHandle);
|
||||
virtual void __fastcall UpdateDrivesNotifications();
|
||||
|
||||
private:
|
||||
std::map<UnicodeString, std::unique_ptr<TDriveInfoRec>> FData;
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
void DriveInfoRequire();
|
||||
|
||||
@@ -121,7 +121,6 @@ type
|
||||
FParentFolder: IShellFolder;
|
||||
FDesktopFolder: IShellFolder;
|
||||
FDirOK: Boolean;
|
||||
FPath: string;
|
||||
FHiddenCount: Integer;
|
||||
FFilteredCount: Integer;
|
||||
FNotRelative: Boolean;
|
||||
@@ -131,9 +130,6 @@ type
|
||||
// Additional thread components:
|
||||
FIconUpdateThread: TIconUpdateThread;
|
||||
// only ever accessed by GUI thread
|
||||
FIconUpdateSet: TDictionary<Integer, Boolean>;
|
||||
FIconUpdateQueue: TQueue<TIconUpdateSchedule>;
|
||||
FIconUpdateQueueDeferred: TQueue<TIconUpdateSchedule>;
|
||||
FDiscMonitor: TDiscMonitor;
|
||||
FHomeDirectory: string;
|
||||
|
||||
@@ -143,7 +139,6 @@ type
|
||||
iRecycleFolder: iShellFolder;
|
||||
PIDLRecycle: PItemIDList;
|
||||
|
||||
FLastPath: TDictionary<string, string>;
|
||||
FTimeoutShellIconRetrieval: Boolean;
|
||||
FAnyCut: Boolean;
|
||||
|
||||
@@ -157,6 +152,8 @@ type
|
||||
procedure SetDirColProperties(Value: TDirViewColProperties);
|
||||
|
||||
protected
|
||||
FPath: string;
|
||||
|
||||
function NewColProperties: TCustomListViewColProperties; override;
|
||||
function SortAscendingByDefault(Index: Integer): Boolean; override;
|
||||
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
||||
@@ -183,7 +180,6 @@ type
|
||||
procedure SetLoadEnabled(Value: Boolean); override;
|
||||
function GetPath: string; override;
|
||||
procedure SetPath(Value: string); override;
|
||||
procedure PathChanged; override;
|
||||
procedure SetItemImageIndex(Item: TListItem; Index: Integer); override;
|
||||
procedure ChangeDetected(Sender: TObject; const Directory: string;
|
||||
var SubdirsChanged: Boolean);
|
||||
@@ -214,9 +210,9 @@ type
|
||||
procedure DoFetchIconUpdate;
|
||||
procedure DoUpdateIcon;
|
||||
procedure StartFileDeleteThread;
|
||||
procedure IconUpdateEnqueue(ListItem: TListItem);
|
||||
function IconUpdatePeek: Integer;
|
||||
procedure IconUpdateDequeue;
|
||||
procedure IconUpdateEnqueue(ListItem: TListItem); virtual; abstract;
|
||||
function IconUpdatePeek: Integer; virtual; abstract;
|
||||
procedure IconUpdateDequeue(Index: Integer); virtual; abstract;
|
||||
procedure WMDestroy(var Msg: TWMDestroy); message WM_DESTROY;
|
||||
procedure Load(DoFocusSomething: Boolean); override;
|
||||
procedure DoFetchIcon(
|
||||
@@ -226,6 +222,9 @@ type
|
||||
dwFileAttributes: DWORD; var psfi: TSHFileInfoW; uFlags: UINT): DWORD_PTR;
|
||||
function DoCopyToClipboard(Focused: Boolean; Cut: Boolean; Operation: TClipBoardOperation): Boolean;
|
||||
procedure ClearCutState;
|
||||
procedure IconUpdateClear; virtual; abstract;
|
||||
function IconUpdateDeprioritize(ItemData: PFileRec; Index: Integer): Boolean; virtual; abstract;
|
||||
function TryGetLastPath(Drive: string; var Path: string): Boolean; virtual; abstract;
|
||||
|
||||
function HiddenCount: Integer; override;
|
||||
function FilteredCount: Integer; override;
|
||||
@@ -687,22 +686,12 @@ begin
|
||||
DragDropFilesEx.ShellExtensions.DragDropHandler := True;
|
||||
DragDropFilesEx.ShellExtensions.DropHandler := True;
|
||||
|
||||
FIconUpdateSet := TDictionary<Integer, Boolean>.Create;
|
||||
FIconUpdateQueue := TQueue<TIconUpdateSchedule>.Create;
|
||||
FIconUpdateQueueDeferred := TQueue<TIconUpdateSchedule>.Create;
|
||||
|
||||
FLastPath := nil;
|
||||
end;
|
||||
|
||||
destructor TDirViewInt.Destroy;
|
||||
begin
|
||||
FreeAndNil(FIconUpdateQueue);
|
||||
FreeAndNil(FIconUpdateQueueDeferred);
|
||||
FreeAndNil(FIconUpdateSet);
|
||||
|
||||
if Assigned(PIDLRecycle) then FreePIDL(PIDLRecycle);
|
||||
|
||||
FLastPath.Free;
|
||||
FFileOperator.Free;
|
||||
FChangeTimer.Free;
|
||||
|
||||
@@ -753,23 +742,6 @@ begin
|
||||
Result := FPath;
|
||||
end;
|
||||
|
||||
procedure TDirViewInt.PathChanged;
|
||||
var
|
||||
Expanded: string;
|
||||
begin
|
||||
inherited;
|
||||
|
||||
// make sure to use PathName as Path maybe just X: what
|
||||
// ExpandFileName resolves to current working directory
|
||||
// on the drive, not to root path
|
||||
Expanded := ExpandFileName(PathName);
|
||||
if not Assigned(FLastPath) then
|
||||
begin
|
||||
FLastPath := TDictionary<string, string>.Create;
|
||||
end;
|
||||
FLastPath.AddOrSetValue(DriveInfo.GetDriveKey(Expanded), Expanded);
|
||||
end;
|
||||
|
||||
procedure TDirViewInt.SetPath(Value: string);
|
||||
const
|
||||
LongPathPrefix = '\\?\';
|
||||
@@ -1191,9 +1163,7 @@ procedure TDirViewInt.Load(DoFocusSomething: Boolean);
|
||||
begin
|
||||
try
|
||||
StopIconUpdateThread;
|
||||
FIconUpdateQueue.Clear;
|
||||
FIconUpdateQueueDeferred.Clear;
|
||||
FIconUpdateSet.Clear;
|
||||
IconUpdateClear();
|
||||
|
||||
StopWatchThread;
|
||||
|
||||
@@ -2372,40 +2342,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDirViewInt.IconUpdateEnqueue(ListItem: TListItem);
|
||||
var
|
||||
Schedule: TIconUpdateSchedule;
|
||||
begin
|
||||
if not FIconUpdateSet.ContainsKey(ListItem.Index) then
|
||||
begin
|
||||
FIconUpdateSet.Add(ListItem.Index, False);
|
||||
Schedule.Index := ListItem.Index;
|
||||
FIconUpdateQueue.Enqueue(Schedule);
|
||||
Assert(FIconUpdateSet.Count = FIconUpdateQueue.Count + FIconUpdateQueueDeferred.Count);
|
||||
end;
|
||||
StartIconUpdateThread;
|
||||
end;
|
||||
|
||||
function TDirViewInt.IconUpdatePeek: Integer;
|
||||
begin
|
||||
if FIconUpdateQueue.Count > 0 then
|
||||
Result := FIconUpdateQueue.Peek.Index
|
||||
else if FIconUpdateQueueDeferred.Count > 0 then
|
||||
Result := FIconUpdateQueueDeferred.Peek.Index
|
||||
else
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
procedure TDirViewInt.IconUpdateDequeue;
|
||||
begin
|
||||
if FIconUpdateQueue.Count > 0 then
|
||||
FIconUpdateQueue.Dequeue
|
||||
else
|
||||
FIconUpdateQueueDeferred.Dequeue;
|
||||
FIconUpdateSet.Remove(FIconUpdateThread.FCurrentIndex);
|
||||
Assert(FIconUpdateSet.Count = FIconUpdateQueue.Count + FIconUpdateQueueDeferred.Count);
|
||||
end;
|
||||
|
||||
function TDirViewInt.ThumbnailNeeded(ItemData: PFileRec): Boolean;
|
||||
begin
|
||||
Result := (not Assigned(ItemData.Thumbnail)) and (ItemData.ThumbnailSize <> ThumbnailNotNeeded);
|
||||
@@ -2428,7 +2364,7 @@ begin
|
||||
if FIconUpdateThread.FCurrentIndex >= Items.Count then
|
||||
begin
|
||||
FIconUpdateThread.FCurrentIndex := -1;
|
||||
IconUpdateDequeue;
|
||||
IconUpdateDequeue(-1);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@@ -2448,18 +2384,8 @@ begin
|
||||
// Deprioritizing unvisible item taken from priority queue.
|
||||
// As we ask Window to cache the image index (LVIF_DI_SETITEM), we won't get asked again,
|
||||
// so we have to retrieve the image eventually (but not thumbnail)
|
||||
if (FIconUpdateQueue.Count > 0) and
|
||||
Invisible then
|
||||
if Invisible and IconUpdateDeprioritize(ItemData, FIconUpdateThread.FCurrentIndex) then
|
||||
begin
|
||||
Assert(not ThumbnailNeeded(ItemData));
|
||||
if ItemData.IconEmpty then
|
||||
begin
|
||||
FIconUpdateQueueDeferred.Enqueue(FIconUpdateQueue.Dequeue);
|
||||
end
|
||||
else
|
||||
begin
|
||||
IconUpdateDequeue;
|
||||
end;
|
||||
FIconUpdateThread.FCurrentIndex := -1;
|
||||
end
|
||||
else
|
||||
@@ -2472,7 +2398,7 @@ begin
|
||||
end
|
||||
else
|
||||
begin
|
||||
IconUpdateDequeue;
|
||||
IconUpdateDequeue(FIconUpdateThread.FCurrentIndex);
|
||||
FIconUpdateThread.FCurrentIndex := -1;
|
||||
end;
|
||||
end;
|
||||
@@ -2492,7 +2418,7 @@ begin
|
||||
(not FIconUpdateThread.Terminated) and
|
||||
(FIconUpdateThread.FCurrentIndex = IconUpdatePeek) then
|
||||
begin
|
||||
IconUpdateDequeue;
|
||||
IconUpdateDequeue(FIconUpdateThread.FCurrentIndex);
|
||||
|
||||
if (FIconUpdateThread.FCurrentIndex >= 0) and
|
||||
(FIconUpdateThread.FCurrentIndex < Items.Count) then
|
||||
@@ -2749,18 +2675,7 @@ var
|
||||
APath: string;
|
||||
DriveRoot: string;
|
||||
begin
|
||||
if Assigned(FLastPath) and FLastPath.ContainsKey(Drive) then
|
||||
begin
|
||||
APath := FLastPath[Drive];
|
||||
if not DirectoryExists(ApiPath(APath)) then
|
||||
begin
|
||||
if DriveInfo.IsRealDrive(Drive) then
|
||||
APath := Format('%s:', [Drive])
|
||||
else
|
||||
APath := Drive;
|
||||
end;
|
||||
end
|
||||
else
|
||||
if not TryGetLastPath(Drive, APath) then
|
||||
begin
|
||||
if DriveInfo.IsRealDrive(Drive) then
|
||||
begin
|
||||
|
||||
@@ -56,8 +56,6 @@ type
|
||||
DefaultDir: string; // Current directory
|
||||
end;
|
||||
|
||||
TDriveStatusPair = TPair<string, TDriveStatus>;
|
||||
|
||||
TScanDirInfo = record
|
||||
SearchNewDirs: Boolean;
|
||||
StartNode: TTreeNode;
|
||||
@@ -142,8 +140,6 @@ type
|
||||
|
||||
TDriveViewInt = class(TCustomDriveView)
|
||||
private
|
||||
FDriveStatus: TObjectDictionary<string, TDriveStatus>;
|
||||
|
||||
FConfirmDelete: Boolean;
|
||||
FConfirmOverwrite: Boolean;
|
||||
FWatchDirectory: Boolean;
|
||||
@@ -227,6 +223,7 @@ type
|
||||
|
||||
function DirAttrMask: Integer;
|
||||
function CreateDriveStatus: TDriveStatus;
|
||||
function GetNextDriveStatus(var Iterator: Integer; Drive: PString; var Status: TDriveStatus): Boolean; virtual; abstract;
|
||||
|
||||
procedure ValidateDirectoryEx(Node: TTreeNode; Recurse: TRecursiveScan;
|
||||
NewDirs: Boolean); override;
|
||||
@@ -270,7 +267,7 @@ type
|
||||
procedure EmptyClipboard; dynamic;
|
||||
procedure EmptyClipboardIfCut; override;
|
||||
// Drive handling:
|
||||
function GetDriveStatus(Drive: string): TDriveStatus;
|
||||
function GetDriveStatus(Drive: string): TDriveStatus; virtual; abstract;
|
||||
function GetDriveTypetoNode(Node: TTreeNode): Integer; // Returns DRIVE_CDROM etc..
|
||||
function GetDriveToNode(Node: TTreeNode): string;
|
||||
procedure ScanDrive(Drive: string);
|
||||
@@ -798,21 +795,13 @@ end;
|
||||
// TDriveViewInt
|
||||
|
||||
constructor TDriveViewInt.Create(AOwner: TComponent);
|
||||
var
|
||||
Drive: TRealDrive;
|
||||
begin
|
||||
inherited;
|
||||
|
||||
FCreating := True;
|
||||
|
||||
FDriveStatus := TObjectDictionary<string, TDriveStatus>.Create([doOwnsValues]);
|
||||
FChangeInterval := MSecsPerSec;
|
||||
|
||||
for Drive := FirstDrive to LastDrive do
|
||||
begin
|
||||
FDriveStatus.Add(Drive, CreateDriveStatus);
|
||||
end;
|
||||
|
||||
FFileOperator := TFileOperator.Create(Self);
|
||||
FSubDirReaderThread := TSubDirReaderThread.Create(Self);
|
||||
FDelayedNodes := TStringList.Create;
|
||||
@@ -841,27 +830,25 @@ begin
|
||||
FStartPos.Y := -1;
|
||||
FDragPos := FStartPos;
|
||||
|
||||
DriveInfo.AddHandler(DriveNotification);
|
||||
|
||||
FDragDropFilesEx.ShellExtensions.DragDropHandler := True;
|
||||
|
||||
DriveInfo.AddHandler(DriveNotification);
|
||||
end; // Create
|
||||
|
||||
destructor TDriveViewInt.Destroy;
|
||||
var
|
||||
DriveStatusPair: TDriveStatusPair;
|
||||
begin
|
||||
|
||||
DriveInfo.RemoveHandler(DriveNotification);
|
||||
|
||||
for DriveStatusPair in FDriveStatus do
|
||||
var Iterator := 0;
|
||||
var DriveStatus: TDriveStatus;
|
||||
while GetNextDriveStatus(Iterator, nil, DriveStatus) do
|
||||
begin
|
||||
var DriveStatus := DriveStatusPair.Value;
|
||||
if Assigned(DriveStatus.DiscMonitor) then
|
||||
FreeAndNil(DriveStatus.DiscMonitor);
|
||||
if Assigned(DriveStatus.ChangeTimer) then
|
||||
FreeAndNil(DriveStatus.ChangeTimer);
|
||||
end;
|
||||
FDriveStatus.Free;
|
||||
|
||||
if Assigned(FFileOperator) then
|
||||
FFileOperator.Free;
|
||||
@@ -896,8 +883,6 @@ begin
|
||||
end;
|
||||
|
||||
procedure TDriveViewInt.CreateWnd;
|
||||
var
|
||||
DriveStatus: TDriveStatus;
|
||||
begin
|
||||
inherited;
|
||||
|
||||
@@ -910,7 +895,9 @@ begin
|
||||
FPrevSelectedIndex := -1;
|
||||
end;
|
||||
|
||||
for DriveStatus in FDriveStatus.Values do
|
||||
var Iterator := 0;
|
||||
var DriveStatus: TDriveStatus;
|
||||
while GetNextDriveStatus(Iterator, nil, DriveStatus) do
|
||||
begin
|
||||
if DriveStatus.RootNodeIndex >= 0 then
|
||||
begin
|
||||
@@ -930,7 +917,6 @@ end; // CreateWnd
|
||||
|
||||
procedure TDriveViewInt.DestroyWnd;
|
||||
var
|
||||
DriveStatus: TDriveStatus;
|
||||
I: Integer;
|
||||
begin
|
||||
FDelayedNodeTimer.Enabled := False;
|
||||
@@ -960,7 +946,9 @@ begin
|
||||
FPrevSelected := nil;
|
||||
end;
|
||||
|
||||
for DriveStatus in FDriveStatus.Values do
|
||||
var Iterator := 0;
|
||||
var DriveStatus: TDriveStatus;
|
||||
while GetNextDriveStatus(Iterator, nil, DriveStatus) do
|
||||
begin
|
||||
DriveStatus.RootNodeIndex := -1;
|
||||
if Assigned(DriveStatus.RootNode) then
|
||||
@@ -1459,14 +1447,15 @@ end;
|
||||
|
||||
function TDriveViewInt.GetDrives: TStrings;
|
||||
var
|
||||
DriveStatusPair: TDriveStatusPair;
|
||||
Drives: TStringList;
|
||||
begin
|
||||
Drives := TStringList.Create;
|
||||
// We could iterate only .Keys here, but that crashes IDE for some reason
|
||||
for DriveStatusPair in FDriveStatus do
|
||||
var Iterator := 0;
|
||||
var Drive: string;
|
||||
var DriveStatus: TDriveStatus;
|
||||
while GetNextDriveStatus(Iterator, @Drive, DriveStatus) do
|
||||
begin
|
||||
Drives.Add(DriveStatusPair.Key);
|
||||
Drives.Add(Drive);
|
||||
end;
|
||||
Drives.CustomSort(CompareDrive);
|
||||
Result := Drives;
|
||||
@@ -1627,15 +1616,6 @@ begin
|
||||
|
||||
end;
|
||||
|
||||
function TDriveViewInt.GetDriveStatus(Drive: string): TDriveStatus;
|
||||
begin
|
||||
if not FDriveStatus.TryGetValue(Drive, Result) then
|
||||
begin
|
||||
Result := CreateDriveStatus;
|
||||
FDriveStatus.Add(Drive, Result);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDriveViewInt.DoScanDir(FromNode: TTreeNode): Boolean;
|
||||
begin
|
||||
Result := not TNodeData(FromNode.Data).IsRecycleBin;
|
||||
@@ -2162,12 +2142,11 @@ begin
|
||||
end;
|
||||
|
||||
procedure TDriveViewInt.RebuildTree;
|
||||
var
|
||||
Drive: string;
|
||||
begin
|
||||
for Drive in FDriveStatus.Keys do
|
||||
var Iterator := 0;
|
||||
var DriveStatus: TDriveStatus;
|
||||
while GetNextDriveStatus(Iterator, nil, DriveStatus) do
|
||||
begin
|
||||
var DriveStatus := GetDriveStatus(Drive);
|
||||
if Assigned(DriveStatus.RootNode) and DriveStatus.Scanned then
|
||||
ValidateDirectory(DriveStatus.RootNode);
|
||||
end;
|
||||
@@ -2341,28 +2320,29 @@ begin
|
||||
end;
|
||||
|
||||
procedure TDriveViewInt.ChangeTimerOnTimer(Sender: TObject);
|
||||
var
|
||||
DriveStatusPair: TDriveStatusPair;
|
||||
begin
|
||||
if (FChangeTimerSuspended = 0) and (Sender is TTimer) then
|
||||
begin
|
||||
for DriveStatusPair in FDriveStatus do
|
||||
var Iterator := 0;
|
||||
var Drive: string;
|
||||
var DriveStatus: TDriveStatus;
|
||||
while GetNextDriveStatus(Iterator, @Drive, DriveStatus) do
|
||||
begin
|
||||
if DriveStatusPair.Value.ChangeTimer = Sender then
|
||||
if DriveStatus.ChangeTimer = Sender then
|
||||
begin
|
||||
// Messages are processed during ValidateDirectory, so we may detect another change while
|
||||
// updating the directory. Prevent the recursion.
|
||||
// But retry the update afterwards (by reenabling the timer in ChangeDetected)
|
||||
SuspendChangeTimer;
|
||||
try
|
||||
var ChangeTimer := DriveStatusPair.Value.ChangeTimer;
|
||||
var ChangeTimer := DriveStatus.ChangeTimer;
|
||||
ChangeTimer.Interval := 0;
|
||||
ChangeTimer.Enabled := False;
|
||||
|
||||
if Assigned(DriveStatusPair.Value.RootNode) then
|
||||
if Assigned(DriveStatus.RootNode) then
|
||||
begin
|
||||
// Check also collapsed (invisible) subdirectories:
|
||||
ValidateDirectory(DriveStatusPair.Value.RootNode);
|
||||
ValidateDirectory(DriveStatus.RootNode);
|
||||
end;
|
||||
finally
|
||||
ResumeChangeTimer;
|
||||
@@ -2432,24 +2412,23 @@ begin
|
||||
end;
|
||||
|
||||
procedure TDriveViewInt.StartAllWatchThreads;
|
||||
var
|
||||
DriveStatusPair: TDriveStatusPair;
|
||||
Drive: string;
|
||||
begin
|
||||
if (csDesigning in ComponentState) or (not FWatchDirectory) then
|
||||
Exit;
|
||||
|
||||
for DriveStatusPair in FDriveStatus do
|
||||
var Iterator := 0;
|
||||
var Drive: string;
|
||||
var DriveStatus: TDriveStatus;
|
||||
while GetNextDriveStatus(Iterator, @Drive, DriveStatus) do
|
||||
begin
|
||||
var DriveStatus := DriveStatusPair.Value;
|
||||
if DriveStatus.Scanned then
|
||||
begin
|
||||
if not Assigned(DriveStatus.DiscMonitor) then
|
||||
CreateWatchThread(DriveStatusPair.Key);
|
||||
CreateWatchThread(Drive);
|
||||
if Assigned(DriveStatus.DiscMonitor) and (not DriveStatus.DiscMonitor.Active) then
|
||||
begin
|
||||
DriveStatus.DiscMonitor.Open;
|
||||
SubscribeDriveNotifications(DriveStatusPair.Key);
|
||||
SubscribeDriveNotifications(Drive);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@@ -2465,15 +2444,14 @@ begin
|
||||
end;
|
||||
|
||||
procedure TDriveViewInt.StopAllWatchThreads;
|
||||
var
|
||||
DriveStatusPair: TDriveStatusPair;
|
||||
begin
|
||||
if (csDesigning in ComponentState) or (not FWatchDirectory) then
|
||||
Exit;
|
||||
|
||||
for DriveStatusPair in FDriveStatus do
|
||||
var Iterator := 0;
|
||||
var DriveStatus: TDriveStatus;
|
||||
while GetNextDriveStatus(Iterator, nil, DriveStatus) do
|
||||
begin
|
||||
var DriveStatus := DriveStatusPair.Value;
|
||||
if Assigned(DriveStatus.DiscMonitor) then
|
||||
begin
|
||||
DriveStatus.DiscMonitor.Close;
|
||||
|
||||
@@ -83,7 +83,6 @@ type
|
||||
|
||||
TDriveInfoInt = class(TObject)
|
||||
private
|
||||
FData: TObjectDictionary<string, TDriveInfoRec>;
|
||||
FNoDrives: DWORD;
|
||||
FNoViewOnDrive: DWORD;
|
||||
FDesktop: IShellFolder;
|
||||
@@ -94,12 +93,9 @@ type
|
||||
FHandlers: TList<TDriveNotificationEvent>;
|
||||
FChangeNotify: ULONG;
|
||||
function GetFolder(Folder: TSpecialFolder): PSpecialFolderRec;
|
||||
procedure ReadDriveBasicStatus(Drive: string);
|
||||
procedure ResetDrive(Drive: string);
|
||||
procedure SetHonorDrivePolicy(Value: Integer);
|
||||
function GetFirstFixedDrive: Char;
|
||||
procedure Load;
|
||||
function AddDrive(Drive: string): TDriveInfoRec;
|
||||
function GetDriveBitMask(Drive: string): Integer;
|
||||
function DoAnyValidPath(DriveType: Integer; CanBeHidden: Boolean; var Path: string): Boolean;
|
||||
function ReadDriveMask(Reg: TRegistry; ValueName: string): DWORD;
|
||||
@@ -107,18 +103,25 @@ type
|
||||
procedure CancelDriveRefresh;
|
||||
procedure InternalWndProc(var Msg: TMessage);
|
||||
procedure InvokeHandlers(DriveNotification: TDriveNotification; Drive: string);
|
||||
procedure UpdateDriveNotifications(Drive: string);
|
||||
procedure UpdateDrivesNotifications;
|
||||
procedure ProcessThreadResults;
|
||||
procedure ReadAsynchronous;
|
||||
procedure DoReadDriveStatus(Drive: string; Flags: Integer);
|
||||
procedure DriveRemoving(Drive: string);
|
||||
|
||||
protected
|
||||
constructor Create;
|
||||
|
||||
procedure DriveRemoving(Drive: string); overload;
|
||||
procedure ResetDrive(Drive: string);
|
||||
procedure DoReadDriveStatus(Drive: string; Flags: Integer);
|
||||
procedure ReadDriveBasicStatus(Drive: string);
|
||||
procedure UpdateDriveNotifications(Drive: string);
|
||||
|
||||
function AddDrive(Drive: string): TDriveInfoRec; virtual; abstract;
|
||||
function GetInternal(Drive: string): TDriveInfoRec; virtual; abstract;
|
||||
procedure DriveRemoving(DeviceHandle: THandle); overload; virtual; abstract;
|
||||
procedure UpdateDrivesNotifications; virtual; abstract;
|
||||
|
||||
public
|
||||
function Get(Drive: string): TDriveInfoRec;
|
||||
function Get(Drive: string): TDriveInfoRec; virtual; abstract;
|
||||
property SpecialFolder[Folder: TSpecialFolder]: PSpecialFolderRec read GetFolder;
|
||||
|
||||
procedure NeedData;
|
||||
@@ -228,7 +231,6 @@ begin
|
||||
FHonorDrivePolicy := 1;
|
||||
FUseABDrives := True;
|
||||
FLoaded := False;
|
||||
FData := TObjectDictionary<string, TDriveInfoRec>.Create([doOwnsValues]);
|
||||
FHandlers := TList<TDriveNotificationEvent>.Create;
|
||||
FChangeNotify := 0;
|
||||
end; {TDriveInfoInt.Create}
|
||||
@@ -237,7 +239,6 @@ destructor TDriveInfoInt.Destroy;
|
||||
begin
|
||||
Assert(FHandlers.Count = 0);
|
||||
FHandlers.Free;
|
||||
FData.Free;
|
||||
inherited;
|
||||
end; {TDriveInfoInt.Destroy}
|
||||
|
||||
@@ -262,8 +263,7 @@ begin
|
||||
for I := 1 to Length(ReadyDrives) do
|
||||
begin
|
||||
Drive := ReadyDrives[I];
|
||||
Assert(FData.ContainsKey(Drive));
|
||||
FData[Drive].DriveReady := True;
|
||||
GetInternal(Drive).DriveReady := True;
|
||||
UpdateDriveNotifications(Drive);
|
||||
AppLog(Format('Drive "%s" is ready', [Drive]))
|
||||
end;
|
||||
@@ -419,8 +419,7 @@ var
|
||||
InaccessibleByDrivePolicy, HiddenByDrivePolicy: Boolean;
|
||||
DriveBitMask: Integer;
|
||||
begin
|
||||
Assert(FData.ContainsKey(Drive));
|
||||
with FData[Drive] do
|
||||
with GetInternal(Drive) do
|
||||
begin
|
||||
DriveType := Windows.GetDriveType(PChar(GetDriveRoot(Drive)));
|
||||
if IsRealDrive(Drive) then DriveBitMask := GetDriveBitMask(Drive)
|
||||
@@ -439,7 +438,7 @@ end;
|
||||
|
||||
procedure TDriveInfoInt.ResetDrive(Drive: string);
|
||||
begin
|
||||
with FData[Drive] do
|
||||
with GetInternal(Drive) do
|
||||
begin
|
||||
DriveReady := False;
|
||||
DisplayName := '';
|
||||
@@ -515,7 +514,7 @@ begin
|
||||
for Drive := FirstDrive to LastDrive do
|
||||
begin
|
||||
// Not using Get as that would recurse into Load
|
||||
if FData[Drive].Valid then
|
||||
if GetInternal(Drive).Valid then
|
||||
Drives := Drives + Drive;
|
||||
end;
|
||||
TDriveInfoThread.Create(Drives);
|
||||
@@ -527,17 +526,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDriveInfoInt.AddDrive(Drive: string): TDriveInfoRec;
|
||||
begin
|
||||
Result := TDriveInfoRec.Create;
|
||||
FData.Add(Drive, Result);
|
||||
ResetDrive(Drive);
|
||||
if IsFixedDrive(Drive) or (not IsRealDrive(Drive)) then // not floppy
|
||||
DoReadDriveStatus(Drive, dsSynchronous)
|
||||
else
|
||||
ReadDriveBasicStatus(Drive);
|
||||
end;
|
||||
|
||||
function TDriveInfoInt.GetImageIndex(Drive: string): Integer;
|
||||
begin
|
||||
NeedData;
|
||||
@@ -585,21 +573,6 @@ begin
|
||||
if IsRealDrive(Result) then Result := Result + ':';
|
||||
end;
|
||||
|
||||
function TDriveInfoInt.Get(Drive: string): TDriveInfoRec;
|
||||
begin
|
||||
NeedData;
|
||||
|
||||
// We might want to wait for FReadyDrives to be empty before returning
|
||||
// (or even better do that only in DriveReady getter)
|
||||
|
||||
if not FData.TryGetValue(Drive, Result) then
|
||||
begin
|
||||
Assert(IsUncPath(Drive));
|
||||
Result := AddDrive(Drive);
|
||||
DriveRefresh;
|
||||
end;
|
||||
end; {TDriveInfoInt.GetData}
|
||||
|
||||
procedure TDriveInfoInt.ReadDriveStatus(Drive: string; Flags: Integer);
|
||||
begin
|
||||
// Among other, this makes sure the pending drive-ready status from the background thread are collected,
|
||||
@@ -629,8 +602,7 @@ begin
|
||||
DriveRoot := GetDriveRoot(Drive);
|
||||
|
||||
// When this method is called, the entry always exists already
|
||||
Assert(FData.ContainsKey(Drive));
|
||||
DriveInfoRec := FData[Drive];
|
||||
DriveInfoRec := GetInternal(Drive);
|
||||
with DriveInfoRec do
|
||||
begin
|
||||
Init := True;
|
||||
@@ -743,12 +715,11 @@ procedure TDriveInfoInt.OverrideDrivePolicy(Drive: string);
|
||||
var
|
||||
Mask: DWORD;
|
||||
begin
|
||||
Assert(FData.ContainsKey(Drive));
|
||||
Assert(FData[Drive].ValidButHiddenByDrivePolicy);
|
||||
Assert(GetInternal(Drive).ValidButHiddenByDrivePolicy);
|
||||
Mask := (not GetDriveBitMask(Drive));
|
||||
FNoDrives := FNoDrives and Mask;
|
||||
ReadDriveStatus(Drive, dsAll);
|
||||
Assert(FData[Drive].Valid);
|
||||
Assert(GetInternal(Drive).Valid);
|
||||
DriveRefresh;
|
||||
end;
|
||||
|
||||
@@ -854,7 +825,6 @@ var
|
||||
PPIDL: PPItemIDList;
|
||||
Event: LONG;
|
||||
Lock: THandle;
|
||||
DrivePair: TPair<string, TDriveInfoRec>;
|
||||
begin
|
||||
with Msg do
|
||||
begin
|
||||
@@ -908,11 +878,7 @@ begin
|
||||
if DeviceType = DBT_DEVTYP_HANDLE then
|
||||
begin
|
||||
DeviceHandle := PDEV_BROADCAST_HANDLE(lParam)^.dbch_handle;
|
||||
for DrivePair in FData do
|
||||
if DrivePair.Value.DriveHandle = DeviceHandle then
|
||||
begin
|
||||
DriveRemoving(DrivePair.Key);
|
||||
end;
|
||||
DriveRemoving(DeviceHandle);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
@@ -941,7 +907,7 @@ end;
|
||||
|
||||
procedure TDriveInfoInt.DriveRemoving(Drive: string);
|
||||
begin
|
||||
FData[Drive].DriveReady := False;
|
||||
GetInternal(Drive).DriveReady := False;
|
||||
UpdateDriveNotifications(Drive);
|
||||
AppLog(Format('Removing drive "%s"', [Drive]));
|
||||
InvokeHandlers(dnRemoving, Drive);
|
||||
@@ -975,7 +941,7 @@ begin
|
||||
if IsFixedDrive(Drive) then
|
||||
begin
|
||||
// Not using Get to avoid recursion
|
||||
DriveInfoRec := FData[Drive];
|
||||
DriveInfoRec := GetInternal(Drive);
|
||||
NeedNotifications :=
|
||||
(FHandlers.Count > 0) and
|
||||
(DriveInfoRec.DriveType <> DRIVE_REMOTE) and
|
||||
@@ -1024,14 +990,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDriveInfoInt.UpdateDrivesNotifications;
|
||||
var
|
||||
Drive: string;
|
||||
begin
|
||||
for Drive in FData.Keys do
|
||||
UpdateDriveNotifications(Drive);
|
||||
end;
|
||||
|
||||
procedure TDriveInfoInt.DriveRefresh;
|
||||
begin
|
||||
InvokeHandlers(dnRefresh, '');
|
||||
|
||||
Reference in New Issue
Block a user