Use submodule for stormlibsharp

This also gets CascLibSharp for free. Maybe keep that in mind
This commit is contained in:
Matt Nadareski
2021-04-02 15:48:57 -07:00
parent 6ab0fd5e3b
commit d68272a5bb
15 changed files with 7 additions and 1372 deletions

3
.gitmodules vendored
View File

@@ -7,3 +7,6 @@
[submodule "BurnOutSharp/External/hllib"]
path = BurnOutSharp/External/hllib
url = https://github.com/RavuAlHemio/hllib.git
[submodule "BurnOutSharp/External/stormlibsharp"]
path = BurnOutSharp/External/stormlibsharp
url = https://github.com/robpaveza/stormlibsharp.git

View File

@@ -38,7 +38,9 @@
External\hllib\HLLib\**\*;
External\LessIO\src\LessIO.Tests\**\*;
External\libmspack4n\lib\**\*;
External\libmspack4n\libmspack4ntest\**\*
External\libmspack4n\libmspack4ntest\**\*;
External\stormlibsharp\lib\**;
External\stormlibsharp\TestConsole\**
</DefaultItemExcludes>
</PropertyGroup>

BIN
BurnOutSharp/CascLib.dll Normal file

Binary file not shown.

View File

@@ -1,414 +0,0 @@
using StormLibSharp.Native;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp
{
public class MpqArchive : IDisposable
{
private MpqArchiveSafeHandle _handle;
private List<MpqFileStream> _openFiles = new List<MpqFileStream>();
private FileAccess _accessType;
private List<MpqArchiveCompactingEventHandler> _compactCallbacks = new List<MpqArchiveCompactingEventHandler>();
private SFILE_COMPACT_CALLBACK _compactCallback;
#region Constructors / Factories
public MpqArchive(string filePath, FileAccess accessType)
{
_accessType = accessType;
SFileOpenArchiveFlags flags = SFileOpenArchiveFlags.TypeIsFile;
if (accessType == FileAccess.Read)
flags |= SFileOpenArchiveFlags.AccessReadOnly;
else
flags |= SFileOpenArchiveFlags.AccessReadWriteShare;
// constant 2 = SFILE_OPEN_HARD_DISK_FILE
if (!NativeMethods.SFileOpenArchive(filePath, 2, flags, out _handle))
throw new Win32Exception(); // Implicitly calls GetLastError
}
public MpqArchive(MemoryMappedFile file, FileAccess accessType)
{
_accessType = accessType;
string fileName = Win32Methods.GetFileNameOfMemoryMappedFile(file);
if (fileName == null)
throw new ArgumentException("Could not retrieve the name of the file to initialize.");
SFileOpenArchiveFlags flags = SFileOpenArchiveFlags.TypeIsMemoryMapped;
if (accessType == FileAccess.Read)
flags |= SFileOpenArchiveFlags.AccessReadOnly;
else
flags |= SFileOpenArchiveFlags.AccessReadWriteShare;
// constant 2 = SFILE_OPEN_HARD_DISK_FILE
if (!NativeMethods.SFileOpenArchive(fileName, 2, flags, out _handle))
throw new Win32Exception(); // Implicitly calls GetLastError
}
private MpqArchive(string filePath, MpqArchiveVersion version, MpqFileStreamAttributes listfileAttributes, MpqFileStreamAttributes attributesFileAttributes, int maxFileCount)
{
if (maxFileCount < 0)
throw new ArgumentException("maxFileCount");
SFileOpenArchiveFlags flags = SFileOpenArchiveFlags.TypeIsFile | SFileOpenArchiveFlags.AccessReadWriteShare;
flags |= (SFileOpenArchiveFlags)version;
//SFILE_CREATE_MPQ create = new SFILE_CREATE_MPQ()
//{
// cbSize = unchecked((uint)Marshal.SizeOf(typeof(SFILE_CREATE_MPQ))),
// dwMaxFileCount = unchecked((uint)maxFileCount),
// dwMpqVersion = (uint)version,
// dwFileFlags1 = (uint)listfileAttributes,
// dwFileFlags2 = (uint)attributesFileAttributes,
// dwStreamFlags = (uint)flags,
//};
//if (!NativeMethods.SFileCreateArchive2(filePath, ref create, out _handle))
// throw new Win32Exception();
if (!NativeMethods.SFileCreateArchive(filePath, (uint)flags, int.MaxValue, out _handle))
throw new Win32Exception();
}
public static MpqArchive CreateNew(string mpqPath, MpqArchiveVersion version)
{
return CreateNew(mpqPath, version, MpqFileStreamAttributes.None, MpqFileStreamAttributes.None, int.MaxValue);
}
public static MpqArchive CreateNew(string mpqPath, MpqArchiveVersion version, MpqFileStreamAttributes listfileAttributes,
MpqFileStreamAttributes attributesFileAttributes, int maxFileCount)
{
return new MpqArchive(mpqPath, version, listfileAttributes, attributesFileAttributes, maxFileCount);
}
#endregion
#region Properties
// TODO: Move to common location.
// This is a global setting, not per-archive setting.
//public int Locale
//{
// get
// {
// throw new NotImplementedException();
// }
// set
// {
// throw new NotImplementedException();
// }
//}
public long MaxFileCount
{
get
{
VerifyHandle();
return NativeMethods.SFileGetMaxFileCount(_handle);
}
set
{
if (value < 0 || value > uint.MaxValue)
throw new ArgumentException("value");
VerifyHandle();
if (!NativeMethods.SFileSetMaxFileCount(_handle, unchecked((uint)value)))
throw new Win32Exception();
}
}
private void VerifyHandle()
{
if (_handle == null || _handle.IsInvalid)
throw new ObjectDisposedException("MpqArchive");
}
public bool IsPatchedArchive
{
get
{
VerifyHandle();
return NativeMethods.SFileIsPatchedArchive(_handle);
}
}
#endregion
public void Flush()
{
VerifyHandle();
if (!NativeMethods.SFileFlushArchive(_handle))
throw new Win32Exception();
}
public int AddListFile(string listfileContents)
{
VerifyHandle();
return NativeMethods.SFileAddListFile(_handle, listfileContents);
}
public void AddFileFromDisk(string filePath, string archiveName)
{
VerifyHandle();
if (!NativeMethods.SFileAddFile(_handle, filePath, archiveName, 0))
throw new Win32Exception();
}
public void Compact(string listfile)
{
VerifyHandle();
if (!NativeMethods.SFileCompactArchive(_handle, listfile, false))
throw new Win32Exception();
}
private void _OnCompact(IntPtr pvUserData, uint dwWorkType, ulong bytesProcessed, ulong totalBytes)
{
MpqArchiveCompactingEventArgs args = new MpqArchiveCompactingEventArgs(dwWorkType, bytesProcessed, totalBytes);
OnCompacting(args);
}
protected virtual void OnCompacting(MpqArchiveCompactingEventArgs e)
{
foreach (var cb in _compactCallbacks)
{
cb(this, e);
}
}
public event MpqArchiveCompactingEventHandler Compacting
{
add
{
VerifyHandle();
_compactCallback = _OnCompact;
if (!NativeMethods.SFileSetCompactCallback(_handle, _compactCallback, IntPtr.Zero))
throw new Win32Exception();
_compactCallbacks.Add(value);
}
remove
{
_compactCallbacks.Remove(value);
VerifyHandle();
if (_compactCallbacks.Count == 0)
{
if (!NativeMethods.SFileSetCompactCallback(_handle, null, IntPtr.Zero))
{
// Don't do anything here. Remove shouldn't fail hard.
}
}
}
}
// TODO: Determine if SFileGetAttributes/SFileSetAttributes/SFileUpdateFileAttributes deserves a projection.
// It's unclear - these seem to affect the (attributes) file but I can't figure out exactly what that means.
public void AddPatchArchive(string patchPath)
{
VerifyHandle();
if (!NativeMethods.SFileOpenPatchArchive(_handle, patchPath, null, 0))
throw new Win32Exception();
}
public void AddPatchArchives(IEnumerable<string> patchPaths)
{
if (patchPaths == null)
throw new ArgumentNullException("patchPaths");
VerifyHandle();
foreach (string path in patchPaths)
{
// Don't sublet to AddPatchArchive to avoid having to repeatedly call VerifyHandle()
if (!NativeMethods.SFileOpenPatchArchive(_handle, path, null, 0))
throw new Win32Exception();
}
}
public bool HasFile(string fileToFind)
{
VerifyHandle();
return NativeMethods.SFileHasFile(_handle, fileToFind);
}
public MpqFileStream OpenFile(string fileName)
{
VerifyHandle();
MpqFileSafeHandle fileHandle;
if (!NativeMethods.SFileOpenFileEx(_handle, fileName, 0, out fileHandle))
throw new Win32Exception();
MpqFileStream fs = new MpqFileStream(fileHandle, _accessType, this);
_openFiles.Add(fs);
return fs;
}
public void ExtractFile(string fileToExtract, string destinationPath)
{
VerifyHandle();
if (!NativeMethods.SFileExtractFile(_handle, fileToExtract, destinationPath, 0))
throw new Win32Exception();
}
public MpqFileVerificationResults VerifyFile(string fileToVerify)
{
VerifyHandle();
return (MpqFileVerificationResults)NativeMethods.SFileVerifyFile(_handle, fileToVerify, 0);
}
// TODO: Consider SFileVerifyRawData
public MpqArchiveVerificationResult VerifyArchive()
{
VerifyHandle();
return (MpqArchiveVerificationResult)NativeMethods.SFileVerifyArchive(_handle);
}
#region IDisposable implementation
public void Dispose()
{
Dispose(true);
}
~MpqArchive()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Release owned files first.
if (_openFiles != null)
{
foreach (var file in _openFiles)
{
file.Dispose();
}
_openFiles.Clear();
_openFiles = null;
}
// Release
if (_handle != null && !_handle.IsInvalid)
{
_handle.Close();
_handle = null;
}
}
}
internal void RemoveOwnedFile(MpqFileStream file)
{
_openFiles.Remove(file);
}
#endregion
}
public enum MpqArchiveVersion
{
Version1 = 0,
Version2 = 0x01000000,
Version3 = 0x02000000,
Version4 = 0x03000000,
}
[Flags]
public enum MpqFileStreamAttributes
{
None = 0x0,
}
[Flags]
public enum MpqFileVerificationResults
{
/// <summary>
/// There were no errors with the file.
/// </summary>
Verified = 0,
/// <summary>
/// Failed to open the file
/// </summary>
Error = 0x1,
/// <summary>
/// Failed to read all data from the file
/// </summary>
ReadError = 0x2,
/// <summary>
/// File has sector CRC
/// </summary>
HasSectorCrc = 0x4,
/// <summary>
/// Sector CRC check failed
/// </summary>
SectorCrcError = 0x8,
/// <summary>
/// File has CRC32
/// </summary>
HasChecksum = 0x10,
/// <summary>
/// CRC32 check failed
/// </summary>
ChecksumError = 0x20,
/// <summary>
/// File has data MD5
/// </summary>
HasMd5 = 0x40,
/// <summary>
/// MD5 check failed
/// </summary>
Md5Error = 0x80,
/// <summary>
/// File has raw data MD5
/// </summary>
HasRawMd5 = 0x100,
/// <summary>
/// Raw MD5 check failed
/// </summary>
RawMd5Error = 0x200,
}
public enum MpqArchiveVerificationResult
{
/// <summary>
/// There is no signature in the MPQ
/// </summary>
NoSignature = 0,
/// <summary>
/// There was an error during verifying signature (like no memory)
/// </summary>
VerificationFailed = 1,
/// <summary>
/// There is a weak signature and sign check passed
/// </summary>
WeakSignatureVerified = 2,
/// <summary>
/// There is a weak signature but sign check failed
/// </summary>
WeakSignatureFailed = 3,
/// <summary>
/// There is a strong signature and sign check passed
/// </summary>
StrongSignatureVerified = 4,
/// <summary>
/// There is a strong signature but sign check failed
/// </summary>
StrongSignatureFailed = 5,
}
}

View File

@@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp
{
public delegate void MpqArchiveCompactingEventHandler(MpqArchive sender, MpqArchiveCompactingEventArgs e);
public class MpqArchiveCompactingEventArgs : EventArgs
{
internal MpqArchiveCompactingEventArgs(uint dwWorkType, ulong processed, ulong total)
{
unchecked
{
WorkType = (MpqCompactingWorkType)dwWorkType;
BytesProcessed = (long)processed;
TotalBytes = (long)total;
}
}
public MpqCompactingWorkType WorkType
{
get;
private set;
}
public long BytesProcessed
{
get;
private set;
}
public long TotalBytes
{
get;
private set;
}
}
public enum MpqCompactingWorkType
{
CheckingFiles = 1,
CheckingHashTable = 2,
CopyingNonMpqData = 3,
CompactingFiles = 4,
ClosingArchive = 5,
}
}

View File

@@ -1,185 +0,0 @@
using StormLibSharp.Native;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace StormLibSharp
{
public class MpqFileStream : Stream
{
private MpqFileSafeHandle _handle;
private FileAccess _accessType;
private MpqArchive _owner;
internal MpqFileStream(MpqFileSafeHandle handle, FileAccess accessType, MpqArchive owner)
{
_handle = handle;
_accessType = accessType;
_owner = owner;
}
private void VerifyHandle()
{
if (_handle == null || _handle.IsInvalid || _handle.IsClosed)
throw new ObjectDisposedException("MpqFileStream");
}
public override bool CanRead
{
get { VerifyHandle(); return true; }
}
public override bool CanSeek
{
get { VerifyHandle(); return true; }
}
public override bool CanWrite
{
get { VerifyHandle(); return _accessType != FileAccess.Read; }
}
public override void Flush()
{
VerifyHandle();
_owner.Flush();
}
public override long Length
{
get
{
VerifyHandle();
uint high = 0;
uint low = NativeMethods.SFileGetFileSize(_handle, ref high);
ulong val = (high << 32) | low;
return unchecked((long)val);
}
}
public override long Position
{
get
{
VerifyHandle();
return NativeMethods.SFileGetFilePointer(_handle);
}
set
{
Seek(value, SeekOrigin.Begin);
}
}
public override unsafe int Read(byte[] buffer, int offset, int count)
{
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset > buffer.Length || (offset + count) > buffer.Length)
throw new ArgumentException();
if (count < 0)
throw new ArgumentOutOfRangeException("count");
VerifyHandle();
bool success;
uint read;
fixed (byte* pb = &buffer[offset])
{
NativeOverlapped overlapped = default(NativeOverlapped);
success = NativeMethods.SFileReadFile(_handle, new IntPtr(pb), unchecked((uint)count), out read, ref overlapped);
}
if (!success)
{
int lastError = Win32Methods.GetLastError();
if (lastError != 38) // EOF
throw new Win32Exception(lastError);
}
return unchecked((int)read);
}
public override long Seek(long offset, SeekOrigin origin)
{
VerifyHandle();
uint low, high;
low = unchecked((uint)(offset & 0xffffffffu));
high = unchecked((uint)(offset >> 32));
return NativeMethods.SFileSetFilePointer(_handle, low, ref high, (uint)origin);
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override unsafe void Write(byte[] buffer, int offset, int count)
{
VerifyHandle();
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset > buffer.Length || (offset + count) > buffer.Length)
throw new ArgumentException();
if (count < 0)
throw new ArgumentOutOfRangeException("count");
VerifyHandle();
bool success;
fixed (byte* pb = &buffer[offset])
{
success = NativeMethods.SFileWriteFile(_handle, new IntPtr(pb), unchecked((uint)count), 0u);
}
if (!success)
throw new Win32Exception();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
if (_handle != null && !_handle.IsInvalid)
{
_handle.Close();
_handle = null;
}
if (_owner != null)
{
_owner.RemoveOwnedFile(this);
_owner = null;
}
}
}
// TODO: Seems like the right place for SFileGetFileInfo, but will need to determine
// what value add these features have except for sophisticated debugging purposes
// (like in Ladis' MPQ Editor app).
public int ChecksumCrc32
{
get
{
throw new NotImplementedException();
}
}
public byte[] GetMd5Hash()
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate void SFILE_DOWNLOAD_CALLBACK(IntPtr pvUserData, ulong byteOffset, uint dwTotalBytes);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate void SFILE_COMPACT_CALLBACK(IntPtr pvUserData, uint dwWorkType, ulong bytesProcessed, ulong totalBytes);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate void SFILE_ADDFILE_CALLBACK(IntPtr pvUserData, uint dwBytesWritte, uint dwTotalBytes, bool bFinalCall);
}

View File

@@ -1,26 +0,0 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
internal sealed class MpqArchiveSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public MpqArchiveSafeHandle(IntPtr handle)
: base(true)
{
this.SetHandle(handle);
}
public MpqArchiveSafeHandle()
: base(true) { }
protected override bool ReleaseHandle()
{
return NativeMethods.SFileCloseArchive(this.handle);
}
}
}

View File

@@ -1,27 +0,0 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp.Native
{
internal sealed class MpqFileSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public MpqFileSafeHandle(IntPtr handle)
: base(true)
{
this.SetHandle(handle);
}
public MpqFileSafeHandle()
: base(true)
{
}
protected override bool ReleaseHandle()
{
return NativeMethods.SFileCloseFile(this.handle);
}
}
}

View File

@@ -1,497 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
internal static class NativeMethods
{
private const string STORMLIB = "stormlib.dll";
#region Functions for manipulation with StormLib global flags
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetLocale();
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileSetLocale(uint lcNewLocale);
#endregion
#region Functions for archive manipulation
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileOpenArchive(
[MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
uint dwPriority,
SFileOpenArchiveFlags dwFlags,
out MpqArchiveSafeHandle phMpq
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCreateArchive(
[MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
uint dwCreateFlags,
uint dwMaxFileCount,
out MpqArchiveSafeHandle phMpq
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCreateArchive2(
[MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
ref SFILE_CREATE_MPQ pCreateInfo,
out MpqArchiveSafeHandle phMpq
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetDownloadCallback(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.FunctionPtr)] SFILE_DOWNLOAD_CALLBACK pfnCallback,
IntPtr pvUserData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFlushArchive(MpqArchiveSafeHandle hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseArchive(IntPtr hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseArchive(MpqArchiveSafeHandle hMpq);
#endregion
#region Adds another listfile into MPQ.
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SFileAddListFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szListFile
);
#endregion
#region Archive compacting
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetCompactCallback(
MpqArchiveSafeHandle hMpq,
SFILE_COMPACT_CALLBACK compactCB,
IntPtr pvUserData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCompactArchive(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szListFile,
bool bReserved
);
#endregion
#region Maximum file count
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetMaxFileCount(MpqArchiveSafeHandle hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetMaxFileCount(MpqArchiveSafeHandle hMpq, uint dwMaxFileCount);
#endregion
#region Changing (attributes) file
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetAttributes(MpqArchiveSafeHandle hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetAttributes(MpqArchiveSafeHandle hMpq, uint dwFlags);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileUpdateFileAttributes(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName
);
#endregion
#region Functions for manipulation with patch archives
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileOpenPatchArchive(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szPatchMpqName,
[MarshalAs(UnmanagedType.LPStr)] string szPatchPathPrefix,
uint dwFlags
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileIsPatchedArchive(MpqArchiveSafeHandle hMpq);
#endregion
#region Functions for file manipulation
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileHasFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileOpenFileEx(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
uint dwSearchScope,
out MpqFileSafeHandle phFile
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetFileSize(MpqFileSafeHandle hFile, ref uint pdwFileSizeHigh);
public static unsafe uint SFileGetFilePointer(
MpqFileSafeHandle hFile
)
{
if (hFile.IsInvalid || hFile.IsClosed)
throw new InvalidOperationException();
IntPtr handle = hFile.DangerousGetHandle();
_TMPQFileHeader* header = (_TMPQFileHeader*)handle.ToPointer();
return header->dwFilePos;
}
//public static unsafe uint SFileGetFileSize(
// MpqFileSafeHandle hFile
// )
//{
// if (hFile.IsInvalid || hFile.IsClosed)
// throw new InvalidOperationException();
// IntPtr handle = hFile.DangerousGetHandle();
// _TMPQFileHeader* header = (_TMPQFileHeader*)handle.ToPointer();
// return header->pFileEntry->dwFileSize;
//}
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileSetFilePointer(
MpqFileSafeHandle hFile,
uint lFilePos,
ref uint plFilePosHigh,
uint dwMoveMethod
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileReadFile(
MpqFileSafeHandle hFile,
IntPtr lpBuffer,
uint dwToRead,
out uint pdwRead,
ref System.Threading.NativeOverlapped lpOverlapped
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseFile(IntPtr hFile);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseFile(MpqFileSafeHandle hFile);
#region Retrieving info about a file in the archive
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileInfo(
IntPtr hMpqOrFile,
SFileInfoClass InfoClass,
IntPtr pvFileInfo,
uint cbFileInfoSize,
out uint pcbLengthNeeded
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileInfo(
MpqArchiveSafeHandle hMpqOrFile,
SFileInfoClass InfoClass,
IntPtr pvFileInfo,
uint cbFileInfoSize,
out uint pcbLengthNeeded
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileInfo(
MpqFileSafeHandle hMpqOrFile,
SFileInfoClass InfoClass,
IntPtr pvFileInfo,
uint cbFileInfoSize,
out uint pcbLengthNeeded
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileName(
MpqFileSafeHandle hFile,
[MarshalAs(UnmanagedType.LPStr)] out string szFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFreeFileInfo(
IntPtr pvFileInfo,
SFileInfoClass infoClass
);
#endregion
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileExtractFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szToExtract,
[MarshalAs(UnmanagedType.LPTStr)] string szExtracted,
uint dwSearchScope
);
#endregion
#region Functions for file and archive verification
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileChecksums(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
out uint pdwCrc32,
IntPtr pMD5
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileVerifyFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
uint dwFlags
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SFileVerifyRawData(
MpqArchiveSafeHandle hMpq,
uint dwWhatToVerify,
[MarshalAs(UnmanagedType.LPStr)] string szFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileVerifyArchive(MpqArchiveSafeHandle hMpq);
#endregion
#region Functions for file searching
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern IntPtr SFileFindFirstFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szMask,
out _SFILE_FIND_DATA lpFindFileData,
[MarshalAs(UnmanagedType.LPStr)] string szListFile
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFindNextFile(
IntPtr hFind,
[In, Out] ref _SFILE_FIND_DATA lpFindFileData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFindClose(IntPtr hFind);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern IntPtr SListFileFindFirstFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szListFile,
[MarshalAs(UnmanagedType.LPStr)] string szMask,
[In, Out] ref _SFILE_FIND_DATA lpFindFileData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SListFileFindNextFile(
IntPtr hFind,
[In, Out] ref _SFILE_FIND_DATA lpFindFileData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SListFileFindClose(IntPtr hFind);
#endregion
#region Locale support
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SFileEnumLocales(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
IntPtr plcLocales,
ref uint pdwMaxLocales,
uint dwSearchScope
);
#endregion
#region Support for adding files to the MPQ
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCreateFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szArchiveName,
ulong fileTime,
uint dwFileSize,
uint lcLocale,
uint dwFlags,
out IntPtr phFile
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileWriteFile(
MpqFileSafeHandle hFile,
IntPtr pvData,
uint dwSize,
uint dwCompression
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFinishFile(MpqFileSafeHandle hFile);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileAddFileEx(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szFileName,
[MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
uint dwFlags,
uint dwCompression,
uint dwCompressionNext
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileAddFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szFileName,
[MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
uint dwFlags
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileAddWave(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szFileName,
[MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
uint dwFlags,
uint dwQuality
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileRemoveFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
uint dwSearchScope
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileRenameFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szOldFileName,
[MarshalAs(UnmanagedType.LPStr)] string szNewFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetFileLocale(
MpqFileSafeHandle hFile,
uint lcNewLocale
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetDataCompression(uint DataCompression);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetAddFileCallback(
MpqArchiveSafeHandle hMpq,
SFILE_ADDFILE_CALLBACK AddFileCB,
IntPtr pvUserData
);
#endregion
#region Compression and decompression
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompImplode(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompExplode(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompCompress(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer,
uint uCompressionMask,
int nCmpType,
int nCmpLevel
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompDecompress(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompDecompress2(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
#endregion
}
#pragma warning disable 0169,0649
internal struct SFILE_CREATE_MPQ
{
public uint cbSize;
public uint dwMpqVersion;
private IntPtr pvUserData;
private uint cbUserData;
public uint dwStreamFlags;
public uint dwFileFlags1;
public uint dwFileFlags2;
public uint dwAttrFlags;
public uint dwSectorSize;
public uint dwRawChunkSize;
public uint dwMaxFileCount;
}
internal unsafe struct _SFILE_FIND_DATA
{
public fixed char cFileName[260]; // Full name of the found file
public IntPtr szPlainName; // Plain name of the found file
public uint dwHashIndex; // Hash table index for the file
public uint dwBlockIndex; // Block table index for the file
public uint dwFileSize; // File size in bytes
public uint dwFileFlags; // MPQ file flags
public uint dwCompSize; // Compressed file size
public uint dwFileTimeLo; // Low 32-bits of the file time (0 if not present)
public uint dwFileTimeHi; // High 32-bits of the file time (0 if not present)
public uint lcLocale; // Locale version
}
internal unsafe struct _TFileEntry
{
public ulong FileNameHash;
public ulong ByteOffset;
public ulong FileTime;
public uint dwHashIndex;
public uint dwFileSize;
public uint dwCmpSize;
public uint dwFlags;
public ushort lcLocale;
public ushort wPlatform;
public uint dwCrc32;
public fixed byte md5[16];
public IntPtr szFileName;
}
// Provides enough of _TMPQFile to get to the file size and current position.
internal unsafe struct _TMPQFileHeader
{
public IntPtr pStream;
public IntPtr ha;
public _TFileEntry* pFileEntry;
public uint dwFileKey;
public uint dwFilePos;
}
#pragma warning restore 0169,0649
}

View File

@@ -1,70 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp.Native
{
internal enum SFileInfoClass
{
// Info classes for archives
SFileMpqFileName, // Name of the archive file (TCHAR [])
SFileMpqStreamBitmap, // Array of bits, each bit means availability of one block (BYTE [])
SFileMpqUserDataOffset, // Offset of the user data header (ULONGLONG)
SFileMpqUserDataHeader, // Raw (unfixed) user data header (TMPQUserData)
SFileMpqUserData, // MPQ USer data, without the header (BYTE [])
SFileMpqHeaderOffset, // Offset of the MPQ header (ULONGLONG)
SFileMpqHeaderSize, // Fixed size of the MPQ header
SFileMpqHeader, // Raw (unfixed) archive header (TMPQHeader)
SFileMpqHetTableOffset, // Offset of the HET table, relative to MPQ header (ULONGLONG)
SFileMpqHetTableSize, // Compressed size of the HET table (ULONGLONG)
SFileMpqHetHeader, // HET table header (TMPQHetHeader)
SFileMpqHetTable, // HET table as pointer. Must be freed using SFileFreeFileInfo
SFileMpqBetTableOffset, // Offset of the BET table, relative to MPQ header (ULONGLONG)
SFileMpqBetTableSize, // Compressed size of the BET table (ULONGLONG)
SFileMpqBetHeader, // BET table header, followed by the flags (TMPQBetHeader + DWORD[])
SFileMpqBetTable, // BET table as pointer. Must be freed using SFileFreeFileInfo
SFileMpqHashTableOffset, // Hash table offset, relative to MPQ header (ULONGLONG)
SFileMpqHashTableSize64, // Compressed size of the hash table (ULONGLONG)
SFileMpqHashTableSize, // Size of the hash table, in entries (DWORD)
SFileMpqHashTable, // Raw (unfixed) hash table (TMPQBlock [])
SFileMpqBlockTableOffset, // Block table offset, relative to MPQ header (ULONGLONG)
SFileMpqBlockTableSize64, // Compressed size of the block table (ULONGLONG)
SFileMpqBlockTableSize, // Size of the block table, in entries (DWORD)
SFileMpqBlockTable, // Raw (unfixed) block table (TMPQBlock [])
SFileMpqHiBlockTableOffset, // Hi-block table offset, relative to MPQ header (ULONGLONG)
SFileMpqHiBlockTableSize64, // Compressed size of the hi-block table (ULONGLONG)
SFileMpqHiBlockTable, // The hi-block table (USHORT [])
SFileMpqSignatures, // Signatures present in the MPQ (DWORD)
SFileMpqStrongSignatureOffset, // Byte offset of the strong signature, relative to begin of the file (ULONGLONG)
SFileMpqStrongSignatureSize, // Size of the strong signature (DWORD)
SFileMpqStrongSignature, // The strong signature (BYTE [])
SFileMpqArchiveSize64, // Archive size from the header (ULONGLONG)
SFileMpqArchiveSize, // Archive size from the header (DWORD)
SFileMpqMaxFileCount, // Max number of files in the archive (DWORD)
SFileMpqFileTableSize, // Number of entries in the file table (DWORD)
SFileMpqSectorSize, // Sector size (DWORD)
SFileMpqNumberOfFiles, // Number of files (DWORD)
SFileMpqRawChunkSize, // Size of the raw data chunk for MD5
SFileMpqStreamFlags, // Stream flags (DWORD)
SFileMpqIsReadOnly, // Nonzero if the MPQ is read only (DWORD)
// Info classes for files
SFileInfoPatchChain, // Chain of patches where the file is (TCHAR [])
SFileInfoFileEntry, // The file entry for the file (TFileEntry)
SFileInfoHashEntry, // Hash table entry for the file (TMPQHash)
SFileInfoHashIndex, // Index of the hash table entry (DWORD)
SFileInfoNameHash1, // The first name hash in the hash table (DWORD)
SFileInfoNameHash2, // The second name hash in the hash table (DWORD)
SFileInfoNameHash3, // 64-bit file name hash for the HET/BET tables (ULONGLONG)
SFileInfoLocale, // File locale (DWORD)
SFileInfoFileIndex, // Block index (DWORD)
SFileInfoByteOffset, // File position in the archive (ULONGLONG)
SFileInfoFileTime, // File time (ULONGLONG)
SFileInfoFileSize, // Size of the file (DWORD)
SFileInfoCompressedSize, // Compressed file size (DWORD)
SFileInfoFlags, // File flags from (DWORD)
SFileInfoEncryptionKey, // File encryption key
SFileInfoEncryptionKeyRaw, // Unfixed value of the file key
}
}

View File

@@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp.Native
{
[Flags]
internal enum SFileOpenArchiveFlags : uint
{
None = 0,
TypeIsFile = None,
TypeIsMemoryMapped = 1,
TypeIsHttp = 2,
AccessReadOnly = 0x100,
AccessReadWriteShare = 0x200,
AccessUseBitmap = 0x400,
DontOpenListfile = 0x10000,
DontOpenAttributes = 0x20000,
DontSearchHeader = 0x40000,
ForceVersion1 = 0x80000,
CheckSectorCRC = 0x100000,
}
}

View File

@@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
internal static class Win32Methods
{
[DllImport("kernel32", ExactSpelling = false, SetLastError = true)]
public static extern uint GetMappedFileName(
IntPtr hProcess,
IntPtr fileHandle,
IntPtr lpFilename,
uint nSize
);
[DllImport("kernel32", ExactSpelling = false, SetLastError = true)]
public static extern uint GetFinalPathNameByHandle(
IntPtr hFile,
IntPtr lpszFilePath,
uint cchFilePath,
uint dwFlags
);
[DllImport("kernel32", SetLastError = false, ExactSpelling = false)]
public static extern int GetLastError();
public static string GetFileNameOfMemoryMappedFile(MemoryMappedFile file)
{
const uint size = 522;
IntPtr path = Marshal.AllocCoTaskMem(unchecked((int)size)); // MAX_PATH + 1 char
string result = null;
try
{
// constant 0x2 = VOLUME_NAME_NT
uint test = GetFinalPathNameByHandle(file.SafeMemoryMappedFileHandle.DangerousGetHandle(), path, size, 0x2);
if (test != 0)
throw new Win32Exception();
result = Marshal.PtrToStringAuto(path);
}
catch
{
uint test = GetMappedFileName(Process.GetCurrentProcess().Handle, file.SafeMemoryMappedFileHandle.DangerousGetHandle(), path, size);
if (test != 0)
throw new Win32Exception();
result = Marshal.PtrToStringAuto(path);
}
return result;
}
}
}

Binary file not shown.