function WriteFileFromBuffer(const AFileName: string; AFileSize: Cardinal; var AData; AIsAppend: Boolean = False): Boolean;typePTQWord = ^TQWord;TQWord = packed record case Boolean of False: (QWORD: Int64); True: (LODWORD: DWORD; HIDWORD: DWORD);end;
varDriveName: string;MappingName: string;DiskFreeSize: Int64;FileHandle: THandle;MappingHandle: THandle;IsNewFile, IsMapping: Boolean;FindData: TWin32FindData;TheCreationTime: TFileTime;FileAttrs: DWORD;OpenMode: DWORD;ExistsSize, ThisSize: TQWord;PFileData, P, PSource: Pointer;Segment: Cardinal;Offset: Cardinal;OffsetSize: Cardinal;CommitSize: Cardinal;
function MoveDataTo(ASource, ADest: Pointer; ASize: Cardinal): Boolean;begin Result := False; try CriticalSectionLock; Windows.VirtualAlloc(PFileData, CommitSize, MEM_COMMIT, PAGE_READWRITE); Windows.VirtualLock(PFileData, CommitSize); try System.Move(ASource^, ADest^, ASize); except on EAccessViolation do Exit; end; finally Windows.VirtualUnlock(PFileData, CommitSize); Windows.VirtualFree(PFileData, CommitSize, MEM_DECOMMIT); CriticalSectionUnlock; end; Result := True;end;
beginResult := False;if PPointer(@AData)^ = nil then Exit;if AFileSize = 0 then Exit;
try PFileData := nil; MappingHandle := 0; FileHandle := INVALID_HANDLE_VALUE;
ThisSize.QWORD := 0; ExistsSize.QWORD := 0;
DriveName := ExtractFileDrive(AFileName); if DriveName = '' then DriveName := ExtractFileDrive(ParamStr(0)); DiskFreeSize := DiskFree(Byte(UpCase(DriveName[1])) - $40); FileHandle := Windows.FindFirstFile(PChar(AFileName), FindData); if FileHandle = INVALID_HANDLE_VALUE then begin if DiskFreeSize < AFileSize then Exit; OpenMode := CREATE_NEW; IsNewFile := True; ThisSize.QWORD := AFileSize;
FileHandle := Windows.CreateFile(PChar(AFileName), Const_FileAccess, Const_FileShare, nil, OpenMode, 0, 0); if FileHandle = INVALID_HANDLE_VALUE then Exit;
try CriticalSectionLock; Windows.SetFilePointer(FileHandle, ThisSize.LODWORD, @ThisSize.HIDWORD, FILE_BEGIN); Windows.SetEndOfFile(FileHandle); finally CriticalSectionUnlock; end; Windows.CloseHandle(FileHandle);
FileHandle := Windows.FindFirstFile(PChar(AFileName), FindData); if FileHandle = INVALID_HANDLE_VALUE then Exit; end else IsNewFile := False;
Windows.FindClose(FileHandle);
TheCreationTime := FindData.ftCreationTime; MappingName := GetFileNameExcludeExt(AFileName) + Format('_%.8x%.8x', [TheCreationTime.dwHighDateTime, TheCreationTime.dwLowDateTime]); if AIsAppend then begin if not IsNewFile then begin ExistsSize.HIDWORD := FindData.nFileSizeHigh; ExistsSize.LODWORD := FindData.nFileSizeLow; ThisSize.QWORD := AFileSize + ExistsSize.QWORD; end else ThisSize.QWORD := AFileSize; if DiskFreeSize < (AFileSize + ExistsSize.QWORD) then Exit; OpenMode := OPEN_ALWAYS end else begin if DiskFreeSize < AFileSize then Exit; OpenMode := TRUNCATE_EXISTING; ThisSize.QWORD := AFileSize; end;
FileAttrs := Windows.GetFileAttributes(PChar(AFileName)); if (FileAttrs and FILE_ATTRIBUTE_READONLY) <> 0 then begin if not Windows.SetFileAttributes(PChar(AFileName), FileAttrs xor FILE_ATTRIBUTE_READONLY) then Exit; end;
try FileHandle := Windows.CreateFile(PChar(AFileName), Const_FileAccess, Const_FileShare, nil, OpenMode, 0, 0); if FileHandle = INVALID_HANDLE_VALUE then Exit;
MappingHandle := Windows.OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar(MappingName)); IsMapping := MappingHandle <> 0; if not IsMapping then begin MappingHandle := Windows.CreateFileMapping(FileHandle, nil, PAGE_READWRITE or SEC_RESERVE, ThisSize.HIDWORD, ((((ThisSize.LODWORD and $FFFF0000) shr 16) + 1) shl 16), PChar(MappingName)); if (MappingHandle = 0) or (Windows.GetLastError <> ERROR_SUCCESS) then Exit; end;
PSource := PPointer(@AData)^; PFileData := nil; Segment := 0; if AIsAppend then begin Offset := ExistsSize.LODWORD and $0000FFFF; if Offset > 0 then begin Segment := ExistsSize.LODWORD and $FFFF0000; if ((Offset + AFileSize) and $FFFF0000) > 0 then begin PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, $00010000); if PFileData = nil then Exit; CommitSize := $00010000; OffsetSize := ((Offset xor $FFFFFFFF) and $0000FFFF) + 1 end else begin OffsetSize := (((Offset + AFileSize) shr 12) + 1) shl 12; PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, OffsetSize); if PFileData = nil then Exit; CommitSize := OffsetSize; OffsetSize := AFileSize; end; P := Pointer(DWORD(PFileData) + Offset); if not MoveDataTo(PSource, P, OffsetSize) then Exit; Windows.UnmapViewOfFile(PFileData); PSource := Pointer(DWORD(PSource) + OffsetSize ); Dec(AFileSize, OffsetSize); if AFileSize > 0 then Segment := ((Segment shr 16) + 1) shl 16; end; end;
while AFileSize <> 0 do begin if AFileSize and $FFFF0000 > 0 then begin PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, $00010000); if PFileData = nil then Exit; CommitSize := $00010000; if not MoveDataTo(PSource, PFileData, $00010000) then Exit; Windows.UnmapViewOfFile(PFileData); PSource := Pointer(DWORD(PSource) + $00010000); Dec(AFileSize, $00010000); if AFileSize > 0 then Segment := ((Segment shr 16) + 1) shl 16; end else begin PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, AFileSize); if PFileData = nil then Exit; CommitSize := ((AFileSize shr 12) + 1) shl 12; if not MoveDataTo(PSource, PFileData, AFileSize) then Exit; Windows.UnmapViewOfFile(PFileData); Dec(AFileSize, AFileSize); end; end;
PFileData := nil; Result := True; finally if PFileData <> nil then Windows.UnmapViewOfFile(PFileData); if MappingHandle <> 0 then Windows.CloseHandle(MappingHandle); if FileHandle <> INVALID_HANDLE_VALUE then begin if Result then begin try CriticalSectionLock; Windows.SetFilePointer(FileHandle, ThisSize.LODWORD, @ThisSize.HIDWORD, FILE_BEGIN); Windows.SetEndOfFile(FileHandle); finally CriticalSectionUnlock; end; end; Windows.CloseHandle(FileHandle); end; end;except on Exception do begin if PFileData <> nil then Windows.UnmapViewOfFile(PFileData); if MappingHandle <> 0 then Windows.CloseHandle(MappingHandle); if FileHandle <> INVALID_HANDLE_VALUE then Windows.CloseHandle(FileHandle); Exit; end;end;end;