mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
Also GetWindowLongPtr and GWLP_USERDATA https://winscp.net/tracker/618 Source commit: c85fdf15e50ce8a6f35b1c4d2a0125a0b9c4f1f0
670 lines
20 KiB
C++
670 lines
20 KiB
C++
//---------------------------------------------------------------------------
|
|
#include <WinPCH.h>
|
|
#pragma hdrstop
|
|
|
|
#include <SessionData.h>
|
|
#include "EditorManager.h"
|
|
//---------------------------------------------------------------------------
|
|
TEditedFileData::TEditedFileData()
|
|
{
|
|
ForceText = false;
|
|
Terminal = NULL;
|
|
SessionData = NULL;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
TEditedFileData::~TEditedFileData()
|
|
{
|
|
delete SessionData;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TEditorManager::TEditorManager()
|
|
{
|
|
FSection = new TCriticalSection();
|
|
FOnFileChange = NULL;
|
|
FOnFileReload = NULL;
|
|
FOnFileEarlyClosed = NULL;
|
|
FOnFileUploadComplete = NULL;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TEditorManager::~TEditorManager()
|
|
{
|
|
unsigned int Count = SizeToUIntChecked(FFiles.size());
|
|
for (unsigned int i = Count; i > 0; i--)
|
|
{
|
|
int Index = i - 1;
|
|
TFileData * FileData = &FFiles[Index];
|
|
|
|
// pending should be only external editors and files being uploaded
|
|
DebugAssert(FileData->Closed || FileData->External);
|
|
|
|
if (!FileData->Closed)
|
|
{
|
|
if (!CloseFile(Index, true, true))
|
|
{
|
|
ReleaseFile(Index);
|
|
}
|
|
}
|
|
}
|
|
delete FSection;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TEditorManager::Empty(bool IgnoreClosed)
|
|
{
|
|
TGuard Guard(FSection);
|
|
bool Result;
|
|
|
|
if (!IgnoreClosed)
|
|
{
|
|
Result = (FFiles.size() == 0);
|
|
}
|
|
else
|
|
{
|
|
Result = true;
|
|
for (unsigned int i = 0; i < FFiles.size(); i++)
|
|
{
|
|
if (!FFiles[i].Closed)
|
|
{
|
|
Result = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TEditorManager::CanAddFile(const UnicodeString RemoteDirectory,
|
|
const UnicodeString OriginalFileName, const UnicodeString SessionName,
|
|
TObject *& Token, UnicodeString & ExistingLocalRootDirectory,
|
|
UnicodeString & ExistingLocalDirectory)
|
|
{
|
|
TGuard Guard(FSection);
|
|
bool Result = true;
|
|
|
|
Token = NULL;
|
|
for (unsigned int i = 0; i < FFiles.size(); i++)
|
|
{
|
|
TFileData * FileData = &FFiles[i];
|
|
|
|
// include even "closed" (=being uploaded) files as it is nonsense
|
|
// to download file being uploaded
|
|
if ((FileData->Data->RemoteDirectory == RemoteDirectory) &&
|
|
(FileData->Data->OriginalFileName == OriginalFileName) &&
|
|
(FileData->Data->SessionName == SessionName))
|
|
{
|
|
if (!FileData->External)
|
|
{
|
|
Result = false;
|
|
if (!FileData->Closed && (FileData->Token != NULL))
|
|
{
|
|
Token = FileData->Token;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// MDI editor?
|
|
if (FileData->Process == INVALID_HANDLE_VALUE)
|
|
{
|
|
// file is just being uploaded, do not allow new editor instance
|
|
if (FileData->Closed)
|
|
{
|
|
Result = false;
|
|
}
|
|
else
|
|
{
|
|
UnicodeString AExistingLocalDirectory = ExtractFilePath(FileData->FileName);
|
|
// If the temporary directory was deleted, behave like the file was never opened
|
|
if (DirectoryExists(AExistingLocalDirectory))
|
|
{
|
|
// get directory where the file already is so we download it there again
|
|
ExistingLocalRootDirectory = FileData->Data->LocalRootDirectory;
|
|
ExistingLocalDirectory = AExistingLocalDirectory;
|
|
}
|
|
CloseFile(i, false, false); // do not delete file
|
|
Result = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Result = false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Result)
|
|
{
|
|
if (FFiles.size() >= WinConfiguration->Editor.MaxEditors)
|
|
{
|
|
throw Exception(LoadStr(TOO_MANY_EDITORS));
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
TEditedFileData * TEditorManager::FindByUploadCompleteEvent(HANDLE UploadCompleteEvent)
|
|
{
|
|
TGuard Guard(FSection);
|
|
for (unsigned int i = 0; i < FFiles.size(); i++)
|
|
{
|
|
TFileData * FileData = &FFiles[i];
|
|
if (FileData->UploadCompleteEvent == UploadCompleteEvent)
|
|
{
|
|
return FileData->Data;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TEditorManager::ProcessFiles(TEditedFileProcessEvent Callback, void * Arg)
|
|
{
|
|
TGuard Guard(FSection);
|
|
for (unsigned int i = 0; i < FFiles.size(); i++)
|
|
{
|
|
TFileData * FileData = &FFiles[i];
|
|
Callback(FileData->FileName, FileData->Data,
|
|
(FileData->Closed ? NULL : FileData->Token), Arg);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TEditorManager::CloseInternalEditors(TNotifyEvent CloseCallback)
|
|
{
|
|
TGuard Guard(FSection);
|
|
// Traverse from end, as closing internal editor causes deletion of
|
|
// respective file vector element.
|
|
TObject * PrevToken = NULL;
|
|
for (unsigned int i = SizeToUIntChecked(FFiles.size()); i > 0; i--)
|
|
{
|
|
// Note that element may be deleted by external cause (like if external editor
|
|
// is closed while "save confirmation" message is displayed).
|
|
if (i <= FFiles.size())
|
|
{
|
|
TFileData * FileData = &FFiles[i - 1];
|
|
// PrevToken is simple check not to ask same editor twice, however
|
|
// it does not solve all posibilities
|
|
if (!FileData->Closed && (FileData->Token != NULL) &&
|
|
(FileData->Token != PrevToken))
|
|
{
|
|
CloseCallback(FileData->Token);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Result = true;
|
|
for (unsigned int i = 0; i < FFiles.size(); i++)
|
|
{
|
|
TFileData * FileData = &FFiles[i];
|
|
|
|
if (!FileData->Closed && (FileData->Token != NULL))
|
|
{
|
|
Result = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TEditorManager::CloseExternalFilesWithoutProcess()
|
|
{
|
|
TGuard Guard(FSection);
|
|
for (unsigned int i = SizeToUIntChecked(FFiles.size()); i > 0; i--)
|
|
{
|
|
TFileData * FileData = &FFiles[i - 1];
|
|
|
|
if (!FileData->Closed && FileData->External &&
|
|
(FileData->Process == INVALID_HANDLE_VALUE))
|
|
{
|
|
CloseFile(i - 1, true, true);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TEditorManager::AddFileInternal(const UnicodeString FileName,
|
|
TEditedFileData * AData, TObject * Token)
|
|
{
|
|
TGuard Guard(FSection);
|
|
std::unique_ptr<TEditedFileData> Data(AData);
|
|
TFileData FileData;
|
|
FileData.FileName = FileName;
|
|
FileData.External = false;
|
|
FileData.Process = INVALID_HANDLE_VALUE;
|
|
FileData.Token = Token;
|
|
|
|
AddFile(FileData, Data.release());
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TEditorManager::AddFileExternal(const UnicodeString FileName,
|
|
TEditedFileData * AData, HANDLE Process)
|
|
{
|
|
TGuard Guard(FSection);
|
|
std::unique_ptr<TEditedFileData> Data(AData);
|
|
TFileData FileData;
|
|
FileData.FileName = FileName;
|
|
FileData.External = true;
|
|
FileData.Process = Process;
|
|
FileData.Token = NULL;
|
|
UnicodeString FilePath = ExtractFilePath(FileData.FileName);
|
|
if (Process != INVALID_HANDLE_VALUE)
|
|
{
|
|
FProcesses.push_back(Process);
|
|
}
|
|
AddFile(FileData, Data.release());
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TEditorManager::Check()
|
|
{
|
|
TGuard Guard(FSection);
|
|
int Index;
|
|
|
|
for (Index = 0; Index < static_cast<int>(FFiles.size()); Index++)
|
|
{
|
|
TDateTime NewTimestamp;
|
|
if (HasFileChanged(Index, NewTimestamp))
|
|
{
|
|
TDateTime N = NormalizeTimestamp(Now());
|
|
// Let the editor finish writing to the file
|
|
// (first to avoid uploading partially saved file, second
|
|
// because the timestamp may change more than once during saving).
|
|
// WORKAROUND WithinPastMilliSeconds seems buggy that it return true even if NewTimestamp is within future
|
|
if ((NewTimestamp <= N) &&
|
|
!WithinPastMilliSeconds(N, NewTimestamp, GUIConfiguration->KeepUpToDateChangeDelay))
|
|
{
|
|
CheckFileChange(Index, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FProcesses.size() > 0)
|
|
{
|
|
do
|
|
{
|
|
Index = WaitFor(SizeToUIntChecked(FProcesses.size()), &(FProcesses[0]), PROCESS);
|
|
|
|
if (Index >= 0)
|
|
{
|
|
try
|
|
{
|
|
CheckFileChange(Index, false);
|
|
}
|
|
__finally
|
|
{
|
|
if (!EarlyClose(Index))
|
|
{
|
|
// CheckFileChange may fail,
|
|
// but we want to close handles anyway
|
|
CloseFile(Index, false, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while ((Index >= 0) && (FProcesses.size() > 0));
|
|
}
|
|
|
|
if (FUploadCompleteEvents.size() > 0)
|
|
{
|
|
do
|
|
{
|
|
Index = WaitFor(SizeToUIntChecked(FUploadCompleteEvents.size()), &(FUploadCompleteEvents[0]), EVENT);
|
|
|
|
if (Index >= 0)
|
|
{
|
|
UploadComplete(Index, false);
|
|
}
|
|
}
|
|
while ((Index >= 0) && (FUploadCompleteEvents.size() > 0));
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TEditorManager::EarlyClose(int Index)
|
|
{
|
|
TFileData * FileData = &FFiles[Index];
|
|
|
|
bool Result =
|
|
(FileData->Process != INVALID_HANDLE_VALUE) &&
|
|
(Now() - FileData->Opened <=
|
|
TDateTime(0, 0, static_cast<unsigned short>(WinConfiguration->Editor.EarlyClose), 0)) &&
|
|
(FOnFileEarlyClosed != NULL);
|
|
|
|
if (Result)
|
|
{
|
|
Result = false;
|
|
FOnFileEarlyClosed(FileData->Data, Result);
|
|
if (Result)
|
|
{
|
|
// forget the associated process
|
|
CloseProcess(Index);
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TEditorManager::FileChanged(TObject * Token)
|
|
{
|
|
TGuard Guard(FSection);
|
|
int Index = FindFile(Token);
|
|
|
|
DebugAssert(Index >= 0);
|
|
DebugAssert(!FFiles[Index].External);
|
|
|
|
CheckFileChange(Index, true);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TEditorManager::FileReload(TObject * Token)
|
|
{
|
|
TGuard Guard(FSection);
|
|
int Index = FindFile(Token);
|
|
|
|
DebugAssert(Index >= 0);
|
|
TFileData * FileData = &FFiles[Index];
|
|
DebugAssert(!FileData->External);
|
|
TAutoFlag ReloadingFlag(FileData->Reloading);
|
|
|
|
OnFileReload(FileData->FileName, FileData->Data);
|
|
GetFileTimestamp(FileData->FileName, FileData->Timestamp);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TEditorManager::FileClosed(TObject * Token, bool Forced)
|
|
{
|
|
TGuard Guard(FSection);
|
|
int Index = FindFile(Token);
|
|
|
|
DebugAssert(Index >= 0);
|
|
DebugAssert(!FFiles[Index].External);
|
|
|
|
CheckFileChange(Index, false);
|
|
CloseFile(Index, false, !Forced);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TEditorManager::AddFile(TFileData & FileData, TEditedFileData * AData)
|
|
{
|
|
std::unique_ptr<TEditedFileData> Data(AData);
|
|
|
|
GetFileTimestamp(FileData.FileName, FileData.Timestamp);
|
|
FileData.Closed = false;
|
|
FileData.UploadCompleteEvent = INVALID_HANDLE_VALUE;
|
|
FileData.Opened = Now();
|
|
FileData.Reupload = false;
|
|
FileData.Reloading = false;
|
|
FileData.Saves = 0;
|
|
FileData.Data = Data.get();
|
|
|
|
FFiles.push_back(FileData);
|
|
|
|
Data.release(); // ownership passed
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void TEditorManager::UploadComplete(int Index, bool Retry)
|
|
{
|
|
TFileData * FileData = &FFiles[Index];
|
|
|
|
DebugAssert(FileData->UploadCompleteEvent != INVALID_HANDLE_VALUE);
|
|
|
|
CloseHandle(FileData->UploadCompleteEvent);
|
|
FUploadCompleteEvents.erase(std::find(FUploadCompleteEvents.begin(),
|
|
FUploadCompleteEvents.end(), FileData->UploadCompleteEvent));
|
|
FileData->UploadCompleteEvent = INVALID_HANDLE_VALUE;
|
|
|
|
if (FileData->Closed)
|
|
{
|
|
CloseFile(Index, false, true);
|
|
}
|
|
else
|
|
{
|
|
if (FileData->Reupload)
|
|
{
|
|
FileData->Reupload = false;
|
|
CheckFileChange(Index, true);
|
|
}
|
|
// so far used only to signal to the internal editor that saving was complete,
|
|
// so we do signal once an actual upload is done only
|
|
else if ((FileData->Token != NULL) && (FOnFileUploadComplete != NULL) && !Retry)
|
|
{
|
|
FOnFileUploadComplete(FileData->Token);
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TEditorManager::CloseProcess(int Index)
|
|
{
|
|
TFileData * FileData = &FFiles[Index];
|
|
|
|
FProcesses.erase(std::find(FProcesses.begin(), FProcesses.end(), FileData->Process));
|
|
DebugCheck(CloseHandle(FileData->Process));
|
|
FileData->Process = INVALID_HANDLE_VALUE;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TEditorManager::ReleaseFile(int Index)
|
|
{
|
|
TFileData * FileData = &FFiles[Index];
|
|
delete FileData->Data;
|
|
FileData->Data = NULL;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TEditorManager::CloseFile(int Index, bool IgnoreErrors, bool Delete)
|
|
{
|
|
bool Result = false;
|
|
TFileData * FileData = &FFiles[Index];
|
|
|
|
if (FileData->Process != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseProcess(Index);
|
|
}
|
|
|
|
if (FileData->UploadCompleteEvent != INVALID_HANDLE_VALUE)
|
|
{
|
|
FileData->Closed = true;
|
|
AppLogFmt(L"Opened/edited file \"%s\" has been closed, but the file is still being uploaded.", (FileData->FileName));
|
|
}
|
|
else
|
|
{
|
|
UnicodeString LocalRootDirectory = FileData->Data->LocalRootDirectory;
|
|
UnicodeString FileName = FileData->FileName; // Before it's released
|
|
|
|
ReleaseFile(Index);
|
|
FFiles.erase(FFiles.begin() + Index);
|
|
Result = true;
|
|
|
|
if (Delete && !LocalRootDirectory.IsEmpty())
|
|
{
|
|
if (!RecursiveDeleteFile(ExcludeTrailingBackslash(LocalRootDirectory)) &&
|
|
!IgnoreErrors)
|
|
{
|
|
throw Exception(FMTLOAD(DELETE_TEMP_EXECUTE_FILE_ERROR, (LocalRootDirectory)));
|
|
}
|
|
AppLogFmt(L"Deleted opened/edited file [%s] folder \"%s\".", (FileName, LocalRootDirectory));
|
|
}
|
|
else
|
|
{
|
|
AppLogFmt(L"Opened/edited file \"%s\" has been closed.", (FileName));
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
TDateTime TEditorManager::NormalizeTimestamp(const TDateTime & Timestamp)
|
|
{
|
|
return TTimeZone::Local->ToUniversalTime(Timestamp);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool TEditorManager::GetFileTimestamp(const UnicodeString & FileName, TDateTime & Timestamp)
|
|
{
|
|
TSearchRecSmart ASearchRec;
|
|
bool Result = FileSearchRec(FileName, ASearchRec);
|
|
if (Result)
|
|
{
|
|
Timestamp = NormalizeTimestamp(ASearchRec.GetLastWriteTime());
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TEditorManager::HasFileChanged(int Index, TDateTime & NewTimestamp)
|
|
{
|
|
TFileData * FileData = &FFiles[Index];
|
|
bool Result;
|
|
if (FileData->Reloading)
|
|
{
|
|
Result = false;
|
|
}
|
|
else
|
|
{
|
|
Result =
|
|
GetFileTimestamp(FileData->FileName, NewTimestamp) &&
|
|
(FileData->Timestamp != NewTimestamp);
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TEditorManager::CheckFileChange(int Index, bool Force)
|
|
{
|
|
TDateTime NewTimestamp;
|
|
bool Changed = HasFileChanged(Index, NewTimestamp);
|
|
if (Force || Changed)
|
|
{
|
|
TFileData * FileData = &FFiles[Index];
|
|
if (FileData->UploadCompleteEvent != INVALID_HANDLE_VALUE)
|
|
{
|
|
AppLogFmt(L"Opened/edited file \"%s\" was changed, but it still being uploaded.", (FileData->FileName));
|
|
FileData->Reupload = true;
|
|
}
|
|
else
|
|
{
|
|
if (Changed)
|
|
{
|
|
AppLogFmt(L"Opened/edited file \"%s\" was changed.", (FileData->FileName));
|
|
}
|
|
else
|
|
{
|
|
AppLogFmt(L"Forcing upload of opened/edited file \"%s\".", (FileData->FileName));
|
|
}
|
|
bool Upload = true;
|
|
if (!Force)
|
|
{
|
|
HANDLE Handle = CreateFile(ApiPath(FileData->FileName).c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
|
|
if (Handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
int Error = GetLastError();
|
|
AppLogFmt(L"Opened/edited file \"%s\" is locked, delaying upload.", (FileData->FileName));
|
|
if (Error == ERROR_ACCESS_DENIED)
|
|
{
|
|
Upload = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(Handle);
|
|
}
|
|
}
|
|
if (Upload)
|
|
{
|
|
FileData->UploadCompleteEvent = CreateEvent(NULL, false, false, NULL);
|
|
FUploadCompleteEvents.push_back(FileData->UploadCompleteEvent);
|
|
|
|
TDateTime PrevTimestamp = FileData->Timestamp;
|
|
FileData->Timestamp = NewTimestamp;
|
|
FileData->Saves++;
|
|
if (FileData->Saves == 1)
|
|
{
|
|
Configuration->Usage->Inc(L"RemoteFilesSaved");
|
|
}
|
|
Configuration->Usage->Inc(L"RemoteFileSaves");
|
|
|
|
try
|
|
{
|
|
DebugAssert(OnFileChange != NULL);
|
|
bool Retry = false;
|
|
AppLogFmt(L"Uploading opened/edited file \"%s\".", (FileData->FileName));
|
|
OnFileChange(FileData->FileName, FileData->Timestamp, FileData->Data, FileData->UploadCompleteEvent, Retry);
|
|
if (Retry)
|
|
{
|
|
AppLogFmt(L"Will retry uploading opened/edited file \"%s\".", (FileData->FileName));
|
|
UploadComplete(Index, true);
|
|
FileData->Timestamp = PrevTimestamp;
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
AppLogFmt(L"Failed to upload opened/edited file \"%s\".", (FileData->FileName));
|
|
// upload failed (was not even started)
|
|
if (FileData->UploadCompleteEvent != INVALID_HANDLE_VALUE)
|
|
{
|
|
UploadComplete(Index, false);
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TEditorManager::FindFile(const TObject * Token)
|
|
{
|
|
int Index = -1;
|
|
for (unsigned int i = 0; i < FFiles.size(); i++)
|
|
{
|
|
if (!FFiles[i].Closed && (FFiles[i].Token == Token))
|
|
{
|
|
Index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Index;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TEditorManager::WaitFor(unsigned int Count, const HANDLE * Handles,
|
|
TWaitHandle WaitFor)
|
|
{
|
|
static const unsigned int Offset = MAXIMUM_WAIT_OBJECTS;
|
|
int Result = -1;
|
|
unsigned int Start = 0;
|
|
while ((Result < 0) && (Start < Count))
|
|
{
|
|
unsigned int C = (Count - Start > Offset ? Offset : Count - Start);
|
|
unsigned int WaitResult = WaitForMultipleObjects(C, Handles + Start, false, 0);
|
|
|
|
if (WaitResult == WAIT_FAILED)
|
|
{
|
|
throw Exception(LoadStr(WATCH_ERROR_GENERAL));
|
|
}
|
|
else if (WaitResult != WAIT_TIMEOUT)
|
|
{
|
|
// WAIT_OBJECT_0 is zero
|
|
DebugAssert(WaitResult < WAIT_OBJECT_0 + Count);
|
|
|
|
HANDLE Handle = Handles[WaitResult - WAIT_OBJECT_0];
|
|
|
|
for (unsigned int i = 0; i < FFiles.size(); i++)
|
|
{
|
|
TFileData * Data = &FFiles[i];
|
|
HANDLE FHandle;
|
|
switch (WaitFor)
|
|
{
|
|
case PROCESS:
|
|
FHandle = Data->Process;
|
|
break;
|
|
|
|
case EVENT:
|
|
FHandle = Data->UploadCompleteEvent;
|
|
break;
|
|
};
|
|
|
|
if (FHandle == Handle)
|
|
{
|
|
Result = Start + i;
|
|
break;
|
|
}
|
|
}
|
|
DebugAssert(Result >= 0);
|
|
}
|
|
|
|
Start += C;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|