mirror of
https://github.com/aphrody-labs/PowerShell.git
synced 2026-10-25 03:07:14 +00:00
680 lines
25 KiB
C#
680 lines
25 KiB
C#
/********************************************************************++
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
--********************************************************************/
|
|
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using Microsoft.Win32.SafeHandles;
|
|
|
|
#if CORECLR
|
|
using Microsoft.PowerShell.CoreClr.Stubs;
|
|
#endif
|
|
|
|
namespace System.Management.Automation.Internal
|
|
{
|
|
internal class CabinetExtractor : ICabinetExtractor
|
|
{
|
|
/// <summary>
|
|
/// GC handle which prevents garbage collector from collecting this delegate.
|
|
/// </summary>
|
|
private CabinetNativeApi.FdiAllocDelegate _allocDelegate;
|
|
private GCHandle _fdiAllocHandle;
|
|
private CabinetNativeApi.FdiFreeDelegate _freeDelegate;
|
|
private GCHandle _fdiFreeHandle;
|
|
private CabinetNativeApi.FdiOpenDelegate _openDelegate;
|
|
private GCHandle _fdiOpenHandle;
|
|
private CabinetNativeApi.FdiReadDelegate _readDelegate;
|
|
private GCHandle _fdiReadHandle;
|
|
private CabinetNativeApi.FdiWriteDelegate _writeDelegate;
|
|
private GCHandle _fdiWriteHandle;
|
|
private CabinetNativeApi.FdiCloseDelegate _closeDelegate;
|
|
private GCHandle _fdiCloseHandle;
|
|
private CabinetNativeApi.FdiSeekDelegate _seekDelegate;
|
|
private GCHandle _fdiSeekHandle;
|
|
private CabinetNativeApi.FdiNotifyDelegate _notifyDelegate;
|
|
private GCHandle _fdiNotifyHandle;
|
|
|
|
internal CabinetNativeApi.FdiContextHandle fdiContext; // HFDI
|
|
|
|
internal CabinetExtractor()
|
|
{
|
|
CabinetNativeApi.FdiERF err = new CabinetNativeApi.FdiERF();
|
|
|
|
populateDelegates();
|
|
|
|
// marshal the delegate to a unmanaged function pointer so that AppDomain reference is stored correctly.
|
|
fdiContext = CabinetNativeApi.FDICreate(
|
|
Marshal.GetFunctionPointerForDelegate(_allocDelegate),
|
|
Marshal.GetFunctionPointerForDelegate(_freeDelegate),
|
|
Marshal.GetFunctionPointerForDelegate(_openDelegate),
|
|
Marshal.GetFunctionPointerForDelegate(_readDelegate),
|
|
Marshal.GetFunctionPointerForDelegate(_writeDelegate),
|
|
Marshal.GetFunctionPointerForDelegate(_closeDelegate),
|
|
Marshal.GetFunctionPointerForDelegate(_seekDelegate),
|
|
CabinetNativeApi.FdiCreateCpuType.Cpu80386,
|
|
err);
|
|
}
|
|
|
|
#region IDisposable Methods
|
|
|
|
/// <summary>
|
|
/// Flag: Has Dispose already been called?
|
|
/// </summary>
|
|
private bool _disposed = false;
|
|
|
|
/// <summary>
|
|
/// Protected implementation of Dispose pattern.
|
|
/// </summary>
|
|
/// <param name="disposing"></param>
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (_disposed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Free managed objects within 'if (disposing)' if needed
|
|
if (null != fdiContext)
|
|
{
|
|
fdiContext.Dispose();
|
|
}
|
|
// Free unmanaged objects here
|
|
this.CleanUpDelegates();
|
|
|
|
_disposed = true;
|
|
|
|
// Call base class implementation in case it has resources to release
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finalizer to ensure destruction of unmanaged resources
|
|
/// </summary>
|
|
~CabinetExtractor()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
internal override bool Extract(string cabinetName, string srcPath, string destPath)
|
|
{
|
|
IntPtr nativeDestPath = Marshal.StringToHGlobalAnsi(destPath);
|
|
|
|
bool result = CabinetNativeApi.FDICopy(
|
|
fdiContext,
|
|
cabinetName,
|
|
srcPath,
|
|
0, // Not used
|
|
Marshal.GetFunctionPointerForDelegate(_notifyDelegate),
|
|
IntPtr.Zero,
|
|
nativeDestPath);
|
|
|
|
Marshal.FreeHGlobal(nativeDestPath);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates delegates for the FDI* operation functions.
|
|
/// </summary>
|
|
private void populateDelegates()
|
|
{
|
|
// if a delegate is re-located by a garbage collection, it will not affect
|
|
// the underlaying managed callback, so Alloc is used to add a reference
|
|
// to the delegate, allowing relocation of the delegate, but preventing
|
|
// disposal. Using GCHandle without pinning reduces fragmentation potential
|
|
// of the managed heap.
|
|
_allocDelegate = new CabinetNativeApi.FdiAllocDelegate(CabinetNativeApi.FdiAlloc);
|
|
_fdiAllocHandle = GCHandle.Alloc(_allocDelegate);
|
|
|
|
_freeDelegate = new CabinetNativeApi.FdiFreeDelegate(CabinetNativeApi.FdiFree);
|
|
_fdiFreeHandle = GCHandle.Alloc(_freeDelegate);
|
|
|
|
_openDelegate = new CabinetNativeApi.FdiOpenDelegate(CabinetNativeApi.FdiOpen);
|
|
_fdiOpenHandle = GCHandle.Alloc(_openDelegate);
|
|
|
|
_readDelegate = new CabinetNativeApi.FdiReadDelegate(CabinetNativeApi.FdiRead);
|
|
_fdiReadHandle = GCHandle.Alloc(_readDelegate);
|
|
|
|
_writeDelegate = new CabinetNativeApi.FdiWriteDelegate(CabinetNativeApi.FdiWrite);
|
|
_fdiWriteHandle = GCHandle.Alloc(_writeDelegate);
|
|
|
|
_closeDelegate = new CabinetNativeApi.FdiCloseDelegate(CabinetNativeApi.FdiClose);
|
|
_fdiCloseHandle = GCHandle.Alloc(_closeDelegate);
|
|
|
|
_seekDelegate = new CabinetNativeApi.FdiSeekDelegate(CabinetNativeApi.FdiSeek);
|
|
_fdiSeekHandle = GCHandle.Alloc(_seekDelegate);
|
|
|
|
_notifyDelegate = new CabinetNativeApi.FdiNotifyDelegate(CabinetNativeApi.FdiNotify);
|
|
_fdiNotifyHandle = GCHandle.Alloc(_notifyDelegate);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Frees all the delegate handles
|
|
/// </summary>
|
|
private void CleanUpDelegates()
|
|
{
|
|
// Free GCHandles so that the memory they point to may be unpinned (garbage collected)
|
|
if (null != _fdiAllocHandle)
|
|
{
|
|
_fdiAllocHandle.Free();
|
|
_fdiFreeHandle.Free();
|
|
_fdiOpenHandle.Free();
|
|
_fdiReadHandle.Free();
|
|
_fdiWriteHandle.Free();
|
|
_fdiCloseHandle.Free();
|
|
_fdiSeekHandle.Free();
|
|
_fdiNotifyHandle.Free();
|
|
}
|
|
}
|
|
};
|
|
|
|
// CabinetExtractor loader implementation
|
|
internal class CabinetExtractorLoader : ICabinetExtractorLoader
|
|
{
|
|
private static CabinetExtractor s_extractorInstance;
|
|
private static CabinetExtractorLoader s_instance;
|
|
private static double s_created = 0;
|
|
|
|
internal static CabinetExtractorLoader GetInstance()
|
|
{
|
|
if (0 == System.Threading.Interlocked.CompareExchange(ref s_created, 1, 0))
|
|
{
|
|
s_instance = new CabinetExtractorLoader();
|
|
s_extractorInstance = new CabinetExtractor();
|
|
}
|
|
|
|
return s_instance;
|
|
}
|
|
|
|
internal override ICabinetExtractor GetCabinetExtractor()
|
|
{
|
|
return s_extractorInstance;
|
|
}
|
|
};
|
|
|
|
internal static class CabinetNativeApi
|
|
{
|
|
#region Delegates and function definitions
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
internal delegate IntPtr FdiAllocDelegate(int size);
|
|
|
|
internal static IntPtr FdiAlloc(int size)
|
|
{
|
|
try
|
|
{
|
|
return Marshal.AllocHGlobal(size);
|
|
}
|
|
catch (OutOfMemoryException)
|
|
{
|
|
return IntPtr.Zero;
|
|
}
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
internal delegate void FdiFreeDelegate(IntPtr memblock);
|
|
|
|
internal static void FdiFree(IntPtr memblock)
|
|
{
|
|
Marshal.FreeHGlobal(memblock);
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
internal delegate IntPtr FdiOpenDelegate(
|
|
[MarshalAs(UnmanagedType.LPStr)] string filename,
|
|
int oflag,
|
|
int pmode);
|
|
|
|
internal static IntPtr FdiOpen(string filename, int oflag, int pmode)
|
|
{
|
|
FileMode mode = CabinetNativeApi.ConvertOpflagToFileMode(oflag);
|
|
FileAccess access = CabinetNativeApi.ConvertPermissionModeToFileAccess(pmode);
|
|
FileShare share = CabinetNativeApi.ConvertPermissionModeToFileShare(pmode);
|
|
|
|
try
|
|
{
|
|
FileStream stream = new FileStream(filename, mode, access, share);
|
|
|
|
if (null == stream)
|
|
{
|
|
return new IntPtr(-1);
|
|
}
|
|
|
|
return GCHandle.ToIntPtr(GCHandle.Alloc(stream));
|
|
}
|
|
catch (IOException)
|
|
{
|
|
return new IntPtr(-1);
|
|
}
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
internal delegate int FdiReadDelegate(
|
|
IntPtr fp,
|
|
[In, Out]
|
|
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2, ArraySubType = UnmanagedType.U1)]
|
|
byte[] buffer,
|
|
int count);
|
|
|
|
internal static int FdiRead(IntPtr fp, byte[] buffer, int count)
|
|
{
|
|
GCHandle handle = GCHandle.FromIntPtr(fp);
|
|
FileStream stream = (FileStream)handle.Target;
|
|
|
|
int numCharactersRead = 0;
|
|
try
|
|
{
|
|
numCharactersRead = stream.Read(buffer, 0, count);
|
|
}
|
|
catch (ArgumentNullException) { numCharactersRead = -1; }
|
|
catch (ArgumentOutOfRangeException) { numCharactersRead = -1; }
|
|
catch (NotSupportedException) { numCharactersRead = -1; }
|
|
catch (IOException) { numCharactersRead = -1; }
|
|
catch (ArgumentException) { numCharactersRead = -1; }
|
|
catch (ObjectDisposedException) { numCharactersRead = -1; }
|
|
|
|
return numCharactersRead;
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
internal delegate int FdiWriteDelegate(
|
|
IntPtr fp,
|
|
[In]
|
|
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2, ArraySubType = UnmanagedType.U1)]
|
|
byte[] buffer,
|
|
int count);
|
|
|
|
internal static int FdiWrite(IntPtr fp, byte[] buffer, int count)
|
|
{
|
|
GCHandle handle = GCHandle.FromIntPtr(fp);
|
|
FileStream stream = (FileStream)handle.Target;
|
|
|
|
int numCharactersWritten = 0;
|
|
try
|
|
{
|
|
stream.Write(buffer, 0, count);
|
|
numCharactersWritten = count; // Write doesn't return the number of bytes written. Per MSDN, if it succeeds, it will have written count bytes.
|
|
}
|
|
catch (ArgumentNullException) { numCharactersWritten = -1; }
|
|
catch (ArgumentOutOfRangeException) { numCharactersWritten = -1; }
|
|
catch (NotSupportedException) { numCharactersWritten = -1; }
|
|
catch (IOException) { numCharactersWritten = -1; }
|
|
catch (ArgumentException) { numCharactersWritten = -1; }
|
|
catch (ObjectDisposedException) { numCharactersWritten = -1; }
|
|
|
|
return numCharactersWritten;
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
internal delegate int FdiCloseDelegate(IntPtr fp);
|
|
|
|
internal static int FdiClose(IntPtr fp)
|
|
{
|
|
GCHandle handle = GCHandle.FromIntPtr(fp);
|
|
FileStream stream = (FileStream)handle.Target;
|
|
|
|
if (null == stream)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
stream.Dispose();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
internal delegate int FdiSeekDelegate(IntPtr fp, int offset, int origin);
|
|
|
|
internal static int FdiSeek(IntPtr fp, int offset, int origin)
|
|
{
|
|
GCHandle handle = GCHandle.FromIntPtr(fp);
|
|
FileStream stream = (FileStream)handle.Target;
|
|
|
|
SeekOrigin seekOrigin = CabinetNativeApi.ConvertOriginToSeekOrigin(origin);
|
|
long status = 0;
|
|
try
|
|
{
|
|
status = stream.Seek(offset, seekOrigin);
|
|
}
|
|
catch (NotSupportedException) { status = -1; }
|
|
catch (IOException) { status = -1; }
|
|
catch (ArgumentException) { status = -1; }
|
|
catch (ObjectDisposedException) { status = -1; }
|
|
|
|
return (int)status;
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
internal delegate IntPtr FdiNotifyDelegate(FdiNotificationType fdint, FdiNotification fdin);
|
|
|
|
// Handles FDI notification
|
|
internal static IntPtr FdiNotify(FdiNotificationType fdint, FdiNotification fdin)
|
|
{
|
|
switch (fdint)
|
|
{
|
|
case FdiNotificationType.FdintCOPY_FILE:
|
|
{
|
|
// TODO: Should I catch exceptions for the new functions?
|
|
|
|
// Copy target directory
|
|
string destPath = Marshal.PtrToStringAnsi(fdin.pv);
|
|
|
|
// Split the path to a filename and path
|
|
string fileName = Path.GetFileName(fdin.psz1);
|
|
string remainingPsz1Path = Path.GetDirectoryName(fdin.psz1);
|
|
destPath = Path.Combine(destPath, remainingPsz1Path);
|
|
|
|
Directory.CreateDirectory(destPath); // Creates all intermediate directories if necessary.
|
|
|
|
// Create the file
|
|
string absoluteFilePath = Path.Combine(destPath, fileName);
|
|
return CabinetNativeApi.FdiOpen(absoluteFilePath, (int)OpFlags.Create, (int)(PermissionMode.Read | PermissionMode.Write)); // TODO: OK to ignore _O_SEQUENTIAL, WrOnly, and _O_BINARY?
|
|
}
|
|
case FdiNotificationType.FdintCLOSE_FILE_INFO:
|
|
{
|
|
// Close the file
|
|
CabinetNativeApi.FdiClose(fdin.hf);
|
|
|
|
// Set the file attributes
|
|
string destPath = Marshal.PtrToStringAnsi(fdin.pv);
|
|
string absoluteFilePath = Path.Combine(destPath, fdin.psz1);
|
|
|
|
IntPtr hFile = PlatformInvokes.CreateFile(
|
|
absoluteFilePath,
|
|
PlatformInvokes.FileDesiredAccess.GenericRead | PlatformInvokes.FileDesiredAccess.GenericWrite,
|
|
PlatformInvokes.FileShareMode.Read,
|
|
IntPtr.Zero,
|
|
PlatformInvokes.FileCreationDisposition.OpenExisting,
|
|
PlatformInvokes.FileAttributes.Normal,
|
|
IntPtr.Zero);
|
|
|
|
if (hFile != IntPtr.Zero)
|
|
{
|
|
PlatformInvokes.FILETIME ftFile = new PlatformInvokes.FILETIME();
|
|
if (PlatformInvokes.DosDateTimeToFileTime(fdin.date, fdin.time, ftFile))
|
|
{
|
|
PlatformInvokes.FILETIME ftLocal = new PlatformInvokes.FILETIME();
|
|
if (PlatformInvokes.LocalFileTimeToFileTime(ftFile, ftLocal))
|
|
{
|
|
PlatformInvokes.SetFileTime(hFile, ftLocal, null, ftLocal);
|
|
}
|
|
}
|
|
|
|
PlatformInvokes.CloseHandle(hFile);
|
|
}
|
|
|
|
PlatformInvokes.SetFileAttributesW(
|
|
absoluteFilePath,
|
|
(PlatformInvokes.FileAttributes)fdin.attribs & (PlatformInvokes.FileAttributes.ReadOnly | PlatformInvokes.FileAttributes.Hidden | PlatformInvokes.FileAttributes.System | PlatformInvokes.FileAttributes.Archive));
|
|
|
|
// Call notification function
|
|
return new IntPtr(1);
|
|
}
|
|
}
|
|
return new IntPtr(0);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Helper methods for non-trivial conversions
|
|
|
|
/// <summary>
|
|
/// Converts an unmanaged define into a known managed value
|
|
/// </summary>
|
|
/// <param name="origin">Defined in stdio.h.</param>
|
|
/// <returns>The appropriate System.IO.SeekOrigin value.</returns>
|
|
internal static SeekOrigin ConvertOriginToSeekOrigin(int origin)
|
|
{
|
|
switch (origin)
|
|
{
|
|
case 0x0: // SEEK_SET
|
|
return SeekOrigin.Begin;
|
|
case 0x1: // SEEK_CUR
|
|
return SeekOrigin.Current;
|
|
case 0x2: // SEEK_END
|
|
return SeekOrigin.End;
|
|
default:
|
|
return SeekOrigin.Current;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts an unmanaged define into a known managed type.
|
|
/// </summary>
|
|
/// <param name="oflag">Operation mode defined in fcntl.h</param>
|
|
/// <returns>The appropriate System.IO.FileMode type.</returns>
|
|
internal static FileMode ConvertOpflagToFileMode(int oflag)
|
|
{
|
|
// Note: This is not done in a switch because the order of tests matters.
|
|
|
|
if ((int)(OpFlags.Create | OpFlags.Excl) == (oflag & (int)(OpFlags.Create | OpFlags.Excl)))
|
|
{
|
|
return FileMode.CreateNew;
|
|
}
|
|
else if ((int)(OpFlags.Create | OpFlags.Truncate) == (oflag & (int)(OpFlags.Create | OpFlags.Truncate)))
|
|
{
|
|
return FileMode.OpenOrCreate;
|
|
}
|
|
else if (0 != (oflag & (int)OpFlags.Append))
|
|
{
|
|
return FileMode.Append;
|
|
}
|
|
else if (0 != (oflag & (int)OpFlags.Create))
|
|
{
|
|
return FileMode.Create;
|
|
}
|
|
else if (0 != (oflag & (int)OpFlags.RdWr))
|
|
{
|
|
return FileMode.Open;
|
|
}
|
|
else if (0 != (oflag & (int)OpFlags.Truncate))
|
|
{
|
|
return FileMode.Truncate;
|
|
}
|
|
else
|
|
{
|
|
return FileMode.OpenOrCreate; // This seemed the safest way to handled unrecognized types
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts an unmanaged define into a known managed type.
|
|
/// </summary>
|
|
/// <param name="pmode">Permission mode defined in stat.h</param>
|
|
/// <returns>The appropriate System.IO.FileAccess type.</returns>
|
|
internal static FileAccess ConvertPermissionModeToFileAccess(int pmode)
|
|
{
|
|
// Note: This is not done in a switch because the order of tests matters.
|
|
|
|
if ((int)(PermissionMode.Read | PermissionMode.Write) == (pmode & (int)(PermissionMode.Read | PermissionMode.Write)))
|
|
{
|
|
return FileAccess.ReadWrite;
|
|
}
|
|
else if (0 != (pmode & (int)PermissionMode.Read))
|
|
{
|
|
return FileAccess.Read;
|
|
}
|
|
else if (0 != (pmode & (int)PermissionMode.Write))
|
|
{
|
|
return FileAccess.Write;
|
|
}
|
|
else
|
|
{
|
|
return FileAccess.Read;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts an unmanaged define into a known managed type.
|
|
/// </summary>
|
|
/// <param name="pmode">Permission mode defined in stat.h</param>
|
|
/// <returns>The appropriate System.IO.FileShare type.</returns>
|
|
internal static FileShare ConvertPermissionModeToFileShare(int pmode)
|
|
{
|
|
// Note: This is not done in a switch because the order of tests matters.
|
|
|
|
if ((int)(PermissionMode.Read | PermissionMode.Write) == (pmode & (int)(PermissionMode.Read | PermissionMode.Write)))
|
|
{
|
|
return FileShare.ReadWrite;
|
|
}
|
|
else if (0 != (pmode & (int)PermissionMode.Read))
|
|
{
|
|
return FileShare.Read;
|
|
}
|
|
else if (0 != (pmode & (int)PermissionMode.Write))
|
|
{
|
|
return FileShare.Write;
|
|
}
|
|
else
|
|
{
|
|
return FileShare.Read;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IO classes, structures, and enums
|
|
|
|
[FlagsAttribute]
|
|
internal enum PermissionMode : int
|
|
{
|
|
None = 0x0000,
|
|
Write = 0x0080,
|
|
Read = 0x0100
|
|
}
|
|
|
|
[FlagsAttribute]
|
|
internal enum OpFlags : int
|
|
{
|
|
RdOnly = 0x0000,
|
|
WrOnly = 0x0001,
|
|
RdWr = 0x0002,
|
|
Append = 0x0008,
|
|
Create = 0x0100,
|
|
Truncate = 0x0200,
|
|
Excl = 0x0400
|
|
}
|
|
|
|
internal enum FdiCreateCpuType : int
|
|
{
|
|
CpuUnknown = -1,
|
|
Cpu80286 = 0,
|
|
Cpu80386 = 1
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
|
internal class FdiNotification
|
|
{
|
|
internal int cb; // LONG
|
|
internal string psz1; // char FAR *
|
|
internal string psz2; //char FAR *
|
|
internal string psz3; // char FAR *
|
|
internal IntPtr pv; // void FAR * // In this case, it is the destination path
|
|
internal IntPtr hf; // INT_PTR
|
|
internal short date; // USHORT
|
|
internal short time; // USHORT
|
|
internal short attribs; // USHORT
|
|
internal short setID; // USHORT
|
|
internal short iCabinet; // USHORT
|
|
internal short iFolder; // USHORT
|
|
internal int fdie; // FDIERROR
|
|
};
|
|
|
|
internal enum FdiNotificationType : int
|
|
{
|
|
FdintCABINET_INFO = 0x0,
|
|
FdintPARTIAL_FILE = 0x1,
|
|
FdintCOPY_FILE = 0x2,
|
|
FdintCLOSE_FILE_INFO = 0x3,
|
|
FdintNEXT_CABINET = 0x4,
|
|
FdintENUMERATE = 0x5
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
internal class FdiERF
|
|
{
|
|
internal int erfOper;
|
|
internal int erfType;
|
|
internal bool fError;
|
|
};
|
|
|
|
internal sealed class FdiContextHandle : SafeHandleZeroOrMinusOneIsInvalid
|
|
{
|
|
private FdiContextHandle()
|
|
: base(true)
|
|
{
|
|
}
|
|
|
|
protected override bool ReleaseHandle()
|
|
{
|
|
return CabinetNativeApi.FDIDestroy(this.handle);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PInvoke Definitions
|
|
|
|
/// <summary>
|
|
/// Creates an FDI context
|
|
/// </summary>
|
|
/// <param name="pfnalloc">_In_ PFNALLOC - Memory allocation delegate</param>
|
|
/// <param name="pfnfree">_In_ PFNFREE - Memory free delegate</param>
|
|
/// <param name="pfnopen">_In_ PFNOPEN - File open delegate</param>
|
|
/// <param name="pfnread">_In_ PFNREAD - File read delegate</param>
|
|
/// <param name="pfnwrite">_In_ PFNWRITE - File write delegate</param>
|
|
/// <param name="pfnclose">_In_ PFNCLOSE - File close delegate</param>
|
|
/// <param name="pfnseek">_In_ PFNSEEK - File seek delegate</param>
|
|
/// <param name="cpuType">_In_ int - CPU type</param>
|
|
/// <param name="erf">_Inout_ PERF - Error structure containing error information</param>
|
|
/// <returns></returns>
|
|
[DllImport("cabinet.dll", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
|
|
internal static extern FdiContextHandle FDICreate(
|
|
IntPtr pfnalloc,
|
|
IntPtr pfnfree,
|
|
IntPtr pfnopen,
|
|
IntPtr pfnread,
|
|
IntPtr pfnwrite,
|
|
IntPtr pfnclose,
|
|
IntPtr pfnseek,
|
|
CabinetNativeApi.FdiCreateCpuType cpuType,
|
|
FdiERF erf);
|
|
|
|
/// <summary>
|
|
/// Extracts files from cabinets
|
|
/// </summary>
|
|
/// <param name="hfdi">_In_ HFDI - A valid FDI context handle returned by FDICreate</param>
|
|
/// <param name="pszCabinet">_In_ LPSTR - The name of the cabinet file</param>
|
|
/// <param name="pszCabPath">_In_ LPSTR - The path to the cabinet file excluding the file name</param>
|
|
/// <param name="flags">_In_ int - Not defined</param>
|
|
/// <param name="pfnfdin">_In_ PFNFDINOTIFY - Pointer to the notification callback delegate</param>
|
|
/// <param name="pfnfdid">_In_ PFNFDIDECRYPT - Not used</param>
|
|
/// <param name="pvUser">_In_opt_ void FAR * - Path string passed to the notification function</param>
|
|
/// <returns></returns>
|
|
[DllImport("cabinet.dll", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, SetLastError = true, BestFitMapping = false)]
|
|
internal static extern bool FDICopy(
|
|
FdiContextHandle hfdi,
|
|
[MarshalAs(UnmanagedType.LPStr)] string pszCabinet,
|
|
[MarshalAs(UnmanagedType.LPStr)] string pszCabPath,
|
|
int flags,
|
|
IntPtr pfnfdin,
|
|
IntPtr pfnfdid,
|
|
IntPtr pvUser);
|
|
|
|
/// <summary>
|
|
/// Deletes an open FDI context
|
|
/// </summary>
|
|
/// <param name="hfdi">_In_ HFDI - The FDI context handle to destroy</param>
|
|
/// <returns></returns>
|
|
[DllImport("cabinet.dll", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
|
|
internal static extern bool FDIDestroy(
|
|
IntPtr hfdi);
|
|
|
|
#endregion
|
|
}
|
|
}
|