using System;
using System.Runtime.InteropServices;
namespace Vanara.PInvoke
{
/// Items from the cabinet.dll
public static partial class Cabinet
{
///
/// The FNCLOSE macro provides the declaration for the application-defined callback function to close a file in an FDI context.
///
/// The file handle.
/// Returns 0 if the file was successfully closed. A return value of –1 indicates an error.
/// The function accepts parameters similar to _close.
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/nf-fdi-fnclose
[PInvokeData("fdi.h", MSDNShortId = "89db9c2a-42ab-410d-a427-60d282385c2b")]
public delegate int PFNCLOSE(HFILE hf);
///
/// The FNFDINOTIFY macro provides the declaration for the application-defined callback notification function to update the
/// application on the status of the decoder.
///
/// the FDIDECRYPT structure.
/// Success returns 1; Failure returns 0; -1 if FDICopy() is aborted.
///
/// If this function is passed on the FDICopy() call, then FDI calls it at various times to update the decryption state and to
/// decrypt FCDATA blocks.
///
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/nf-fdi-fnfdinotify
[PInvokeData("fdi.h", MSDNShortId = "7655ddb2-7cd4-4012-913c-9909fcea639a")]
public delegate int PFNFDINOTIFY(ref FDIDECRYPT pfdid);
///
/// The FNOPEN macro provides the declaration for the application-defined callback function to open a file in an FDI context.
///
/// File name.
/// The kind of operations allowed.
/// Permission mode.
/// Return value is file handle of open file to read, or INVALID_FILE_HANDLE on failure.
/// The function accepts parameters similar to _open.
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/nf-fdi-fnopen
[PInvokeData("fdi.h", MSDNShortId = "45bd2d23-1f6d-42a6-8afb-86227da6118f")]
public delegate HFILE PFNOPEN(string pszFile, int oflag, int pmode);
///
/// The FNREAD macro provides the declaration for the application-defined callback function to read data from a file in an FDI context.
///
/// File descriptor referring to the open file.
/// Storage location for data.
/// Maximum number of bytes to read.
/// returns the number of bytes read
/// The function accepts parameters similar to _read.
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/nf-fdi-fnread
[PInvokeData("fdi.h", MSDNShortId = "0a8c6c9f-051c-43a0-b43b-1fd8b4fef10c")]
public delegate uint PFNREAD(HFILE hf, IntPtr memory, uint cb);
///
/// The FNSEEK macro provides the declaration for the application-defined callback function to move a file pointer to the
/// specified location in an FDI context.
///
/// File descriptor referring to an open file.
/// Number of bytes from origin.
/// Initial position..
/// returns the offset, in bytes, of the new position from the beginning of the file.
/// The function accepts parameters similar to _lseek.
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/nf-fdi-fnseek
[PInvokeData("fdi.h", MSDNShortId = "e49b5086-6b89-40ce-b6fa-905d21593dec")]
public delegate int PFNSEEK(HFILE hf, int dist, int seektype);
///
/// The FNWRITE macro provides the declaration for the application-defined callback function to write data to a file in an FDI context.
///
/// File descriptor of file into which data is written.
/// Data to be written.
/// Number of bytes.
/// returns the number of bytes actually written.
/// The function accepts parameters similar to _write.
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/nf-fdi-fnwrite
[PInvokeData("fdi.h", MSDNShortId = "e15d4293-2955-48cd-b8c9-77669a1e6436")]
public delegate uint PFNWRITE(HFILE hf, IntPtr memory, uint cb);
public enum FDIDECRYPTTYPE
{
fdidtNEW_CABINET, // New cabinet
fdidtNEW_FOLDER, // New folder
fdidtDECRYPT, // Decrypt a data block
}
[PInvokeData("fdi.h")]
public enum FDIERROR
{
///
/// Description: No error
/// Cause: Function was successfull.
/// Response: Keep going!
///
FDIERROR_NONE,
///
/// Description: Cabinet not found
/// Cause: Bad file name or path passed to FDICopy(), or returned to fdintNEXT_CABINET.
/// Response: To prevent this error, validate the existence of the the cabinet *before* passing the path to FDI.
///
FDIERROR_CABINET_NOT_FOUND,
///
/// Description: Cabinet file does not have the correct format
/// Cause: File passed to to FDICopy(), or returned to fdintNEXT_CABINET, is too small to be a cabinet file, or does not
/// have the cabinet signature in its first four bytes.
/// Response: To prevent this error, call FDIIsCabinet() to check a cabinet before calling FDICopy() or returning the cabinet
/// path to fdintNEXT_CABINET.
///
FDIERROR_NOT_A_CABINET,
///
/// Description: Cabinet file has an unknown version number.
/// Cause: File passed to to FDICopy(), or returned to fdintNEXT_CABINET, has what looks like a cabinet file header, but
/// the version of the cabinet file format is not one understood by this version of FDI. The erf.erfType field is filled in with
/// the version number found in the cabinet file.
/// Response: To prevent this error, call FDIIsCabinet() to check a cabinet before calling FDICopy() or returning the cabinet
/// path to fdintNEXT_CABINET.
///
FDIERROR_UNKNOWN_CABINET_VERSION,
///
/// Description: Cabinet file is corrupt
/// Cause: FDI returns this error any time it finds a problem with the logical format of a cabinet file, and any time one
/// of the passed-in file I/O calls fails when operating on a cabinet (PFNOPEN, PFNSEEK, PFNREAD, or PFNCLOSE). The client can
/// distinguish these two cases based upon whether the last file I/O call failed or not.
/// Response: Assuming this is not a real corruption problem in a cabinet file, the file I/O functions could attempt to do
/// retries on failure (for example, if there is a temporary network connection problem). If this does not work, and the file I/O
/// call has to fail, then the FDI client will have to clean up and call the FDICopy() function again.
///
FDIERROR_CORRUPT_CABINET,
///
/// Description: Could not allocate enough memory
/// Cause: FDI tried to allocate memory with the PFNALLOC function, but it failed.
/// Response: If possible, PFNALLOC should take whatever steps are possible to allocate the memory requested. If memory is not
/// immediately available, it might post a dialog asking the user to free memory, for example. Note that the bulk of FDI's memory
/// allocations are made at FDICreate() time and when the first cabinet file is opened during FDICopy().
///
FDIERROR_ALLOC_FAIL,
///
/// Description: Unknown compression type in a cabinet folder
/// Cause: [Should never happen.] A folder in a cabinet has an unknown compression type. This is probably caused by a
/// mismatch between the version of Diamond used to create the cabinet and the FDI. LIB used to read the cabinet.
/// Response: Abort.
///
FDIERROR_BAD_COMPR_TYPE,
///
/// Description: Failure decompressing data from a cabinet file
/// Cause: The decompressor found an error in the data coming from the file cabinet. The cabinet file was corrupted.
/// [11-Apr-1994 bens When checksuming is turned on, this error should never occur.]
/// Response: Probably should abort; only other choice is to cleanup and call FDICopy() again, and hope there was some
/// intermittent data error that will not reoccur.
///
FDIERROR_MDI_FAIL,
///
/// Description: Failure writing to target file
/// Cause: FDI returns this error any time it gets an error back from one of the passed-in file I/O calls fails when
/// writing to a file being extracted from a cabinet.
/// Response: To avoid or minimize this error, the file I/O functions could attempt to avoid failing. A common cause might be
/// disk full -- in this case, the PFNWRITE function could have a check for free space, and put up a dialog asking the user to
/// free some disk space.
///
FDIERROR_TARGET_FILE,
///
/// Description: Cabinets in a set do not have the same RESERVE sizes
/// Cause: [Should never happen]. FDI requires that the sizes of the per-cabinet, per-folder, and per-data block RESERVE
/// sections be consistent across all the cabinet in a set. Diamond will only generate cabinet sets with these properties.
/// Response: Abort.
///
FDIERROR_RESERVE_MISMATCH,
///
/// Description: Cabinet returned on fdintNEXT_CABINET is incorrect
/// Cause: NOTE: THIS ERROR IS NEVER RETURNED BY FDICopy()! Rather, FDICopy() keeps calling the fdintNEXT_CABINET callback
/// until either the correct cabinet is specified, or you return ABORT. When FDICopy() is extracting a file that crosses a
/// cabinet boundary, it calls fdintNEXT_CABINET to ask for the path to the next cabinet. Not being very trusting, FDI then
/// checks to make sure that the correct continuation cabinet was supplied! It does this by checking the "setID" and "iCabinet"
/// fields in the cabinet. When DIAMOND.EXE creates a set of cabinets, it constructs the "setID" using the sum of the bytes of
/// all the destination file names in the cabinet set. FDI makes sure that the 16-bit setID of the continuation cabinet matches
/// the cabinet file just processed. FDI then checks that the cabinet number (iCabinet) is one more than the cabinet number for
/// the cabinet just processed.
/// Response: You need code in your fdintNEXT_CABINET (see below) handler to do retries if you get recalled with this error.
/// See the sample code (EXTRACT.C) to see how this should be handled.
///
FDIERROR_WRONG_CABINET,
///
/// Description: FDI aborted.
/// Cause: An FDI callback returned -1 (usually).
/// Response: Up to client.
///
FDIERROR_USER_ABORT,
///
/// Description: Unexpected end of file.
/// Cause: This error may be returned instead of FDIERROR_CORRUPT_CABINET if PFNREAD returned 0.
/// Response: See FDIERROR_CORRUPT_CABINET above.
///
FDIERROR_EOF,
}
/// The FDICopy function extracts files from cabinets.
/// A valid FDI context handle returned by the FDICreate function.
///
/// The name of the cabinet file, excluding any path information, from which to extract files. If a file is split over multiple
/// cabinets, FDICopy allows for subsequent cabinets to be opened.
///
///
/// The pathname of the cabinet file, but not including the name of the file itself. For example, "C:\MyCabs".
/// The contents of pszCabinet are appended to pszCabPath to create the full pathname of the cabinet.
///
/// No flags are currently defined and this parameter should be set to zero.
///
/// Pointer to an application-defined callback notification function to update the application on the status of the decoder. The
/// function should be declared using the FNFDINOTIFY macro.
///
/// Not currently used by FDI. This parameter should be set to NULL.
/// Pointer to an application-specified value to pass to the notification function.
///
/// If the function succeeds, it returns TRUE; otherwise, FALSE.
/// Extended error information is provided in the ERF structure used to create the FDI context.
///
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/nf-fdi-fdicopy BOOL DIAMONDAPI FDICopy( HFDI hfdi, LPSTR pszCabinet,
// LPSTR pszCabPath, int flags, PFNFDINOTIFY pfnfdin, PFNFDIDECRYPT pfnfdid, void *pvUser );
[DllImport(Lib.Cabinet, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Ansi)]
[PInvokeData("fdi.h", MSDNShortId = "6ec2b10b-f70a-4a22-beff-df6b6a4c4cfd")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FDICopy(HFDI hfdi, string pszCabinet, string pszCabPath, int flags, PFNFDINOTIFY pfnfdin, IntPtr pfnfdid, IntPtr pvUser);
/// The FDICreate function creates an FDI context.
///
/// Pointer to an application-defined callback function to allocate memory. The function should be declared using the FNALLOC macro.
///
///
/// Pointer to an application-defined callback function to free previously allocated memory. The function should be declared using
/// the FNFREE macro.
///
///
/// Pointer to an application-defined callback function to open a file. The function should be declared using the FNOPEN macro.
///
///
/// Pointer to an application-defined callback function to read data from a file. The function should be declared using the FNREAD macro.
///
///
/// Pointer to an application-defined callback function to write data to a file. The function should be declared using the FNWRITE macro.
///
///
/// Pointer to an application-defined callback function to close a file. The function should be declared using the FNCLOSE macro.
///
///
/// Pointer to an application-defined callback function to move a file pointer to the specified location. The function should be
/// declared using the FNSEEK macro.
///
///
/// In the 16-bit version of FDI, specifies the CPU type and can be any of the following values.
/// Note Expressing the cpuUNKNOWN value is recommended.
///
///
/// Value
/// Meaning
///
/// -
/// cpuUNKNOWN -1
/// FDI should determine the CPU type.
///
/// -
/// cpu80286 0
/// Only 80286 instructions can be used.
///
/// -
/// cpu80386 1
/// 80386 instructions can be used.
///
///
///
/// Pointer to an ERF structure that receives the error information.
///
/// If the function succeeds, it returns a non- NULL HFDI context pointer; otherwise, it returns NULL.
/// Extended error information is provided in the ERF structure.
///
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/nf-fdi-fdicreate HFDI DIAMONDAPI FDICreate( PFNALLOC pfnalloc, PFNFREE
// pfnfree, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, int cpuType, PERF perf );
[DllImport(Lib.Cabinet, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Ansi)]
[PInvokeData("fdi.h", MSDNShortId = "90634725-b7a8-4369-8a91-684debee9548")]
public static extern SafeHFDI FDICreate(PFNALLOC pfnalloc, PFNFREE pfnfree, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, int cpuType, out ERF perf);
/// The FDIDestroy function deletes an open FDI context.
/// A valid FDI context handle returned by the FDICreate function.
///
/// If the function succeeds, it returns TRUE; otherwise, FALSE.
/// Extended error information is provided in the ERF structure used to create the FDI context.
///
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/nf-fdi-fdidestroy BOOL DIAMONDAPI FDIDestroy( HFDI hfdi );
[DllImport(Lib.Cabinet, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Ansi)]
[PInvokeData("fdi.h", MSDNShortId = "fe3b8045-a476-4a21-b732-0d4799798faf")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FDIDestroy(HFDI hfdi);
///
/// The FDIIsCabinet function determines whether a file is a cabinet and, if it is, returns information about it.
///
/// A valid FDI context handle returned by FDICreate.
///
/// An application-defined value to keep track of the opened file. This value must be of the same type as values used by the File I/O
/// functions passed to FDICreate.
///
///
/// Pointer to an FDICABINETINFO structure that receives the cabinet details, in the event the file is actually a cabinet.
///
///
/// If the file is a cabinet, the function returns TRUE ; otherwise, FALSE.
/// Extended error information is provided in the ERF structure used to create the FDI context.
///
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/nf-fdi-fdiiscabinet BOOL DIAMONDAPI FDIIsCabinet( HFDI hfdi, INT_PTR hf,
// PFDICABINETINFO pfdici );
[DllImport(Lib.Cabinet, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Ansi)]
[PInvokeData("fdi.h", MSDNShortId = "01d223ca-56c6-49fa-b9e6-e5eeda88936a")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FDIIsCabinet(HFDI hfdi, IntPtr hf, out FDICABINETINFO pfdici);
/// The FDITruncateCabinet function truncates a cabinet file starting at the specified folder number.
/// A valid FDI context handle returned by the FDICreate function.
/// The full cabinet filename.
/// The index of the first folder to delete.
///
/// If the function succeeds, it returns TRUE; otherwise, FALSE.
/// Extended error information is provided in the ERF structure used to create the FDI context.
///
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/nf-fdi-fditruncatecabinet BOOL DIAMONDAPI FDITruncateCabinet( HFDI hfdi,
// LPSTR pszCabinetName, USHORT iFolderToDelete );
[DllImport(Lib.Cabinet, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Ansi)]
[PInvokeData("fdi.h", MSDNShortId = "c923b0a5-1a8d-42aa-bd05-0d318199756d")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FDITruncateCabinet(HFDI hfdi, string pszCabinetName, ushort iFolderToDelete);
/// The FDICABINETINFO structure contains details about a particular cabinet file.
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/ns-fdi-__unnamed_struct_0 typedef struct { long cbCabinet; USHORT
// cFolders; USHORT cFiles; USHORT setID; USHORT iCabinet; BOOL fReserve; BOOL hasprev; BOOL hasnext; } FDICABINETINFO;
[PInvokeData("fdi.h", MSDNShortId = "fde1a2ca-60cd-4a4d-9872-681e2f8f4fb1")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct FDICABINETINFO
{
/// The total length of the cabinet file.
public long cbCabinet;
/// The count of the folders in the cabinet.
public ushort cFolders;
/// The count of the files in the cabinet.
public ushort cFiles;
/// The identifier of the cabinet set.
public ushort setID;
/// The cabinet number in set. This index is zero based.
public ushort iCabinet;
/// If this value is set to TRUE, a reserved area is present in the cabinet.
[MarshalAs(UnmanagedType.Bool)] public bool fReserve;
///
/// If this value is set to TRUE, the cabinet is linked to a previous cabinet. This is accomplished by having a file
/// continued from the previous cabinet into the current one.
///
[MarshalAs(UnmanagedType.Bool)] public bool hasprev;
///
/// If this value is set to TRUE, the current cabinet is linked to the next cabinet by having a file continued from the
/// current cabinet into the next one.
///
[MarshalAs(UnmanagedType.Bool)] public bool hasnext;
}
[PInvokeData("fdi.h")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct FDIDECRYPT
{
///Command type (selects union below)
public FDIDECRYPTTYPE fdidt;
///Decryption context
public IntPtr pvUser;
public Union union;
[StructLayout(LayoutKind.Explicit)]
public struct Union
{
[FieldOffset(0)]
public NEW_CABINET cabinet;
[FieldOffset(0)]
public NEW_FOLDER folder;
[FieldOffset(0)]
public DECRYPT decrypt;
}
[StructLayout(LayoutKind.Sequential)]
public struct NEW_CABINET
{
///RESERVE section from CFHEADER
public IntPtr pHeaderReserve;
///Size of pHeaderReserve
public ushort cbHeaderReserve;
///Cabinet set ID
public ushort setID;
///Cabinet number in set (0 based)
public int iCabinet;
}
[StructLayout(LayoutKind.Sequential)]
public struct NEW_FOLDER
{
///RESERVE section from CFFOLDER
public IntPtr pFolderReserve;
///Size of pFolderReserve
public ushort cbFolderReserve;
///Folder number in cabinet (0 based)
public ushort iFolder;
}
[StructLayout(LayoutKind.Sequential)]
public struct DECRYPT
{
///RESERVE section from CFDATA
public IntPtr pDataReserve;
///Size of pDataReserve
public ushort cbDataReserve;
///Data buffer
public IntPtr pbData;
///Size of data buffer
public ushort cbData;
///TRUE if this is a split data block
public bool fSplit;
///0 if this is not a split block, or the first piece of a split block; Greater than 0 if this is the second piece of a split block.
public ushort cbPartial;
}
}
/// The FDINOTIFICATION structure to provide information to FNFDINOTIFY.
// https://docs.microsoft.com/en-us/windows/desktop/api/fdi/ns-fdi-fdinotification typedef struct { long cb; char *psz1; char *psz2;
// char *psz3; void *pv; INT_PTR hf; USHORT date; USHORT time; USHORT attribs; USHORT setID; USHORT iCabinet; USHORT iFolder;
// FDIERROR fdie; } FDINOTIFICATION, *PFDINOTIFICATION;
[PInvokeData("fdi.h", MSDNShortId = "8b92226e-b19a-4624-925e-4a98d037637d")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct FDINOTIFICATION
{
/// The size, in bytes, of a cabinet element.
public long cb;
/// A null-terminated string.
public Vanara.InteropServices.StrPtrAnsi psz1;
/// A null-terminated string.
public Vanara.InteropServices.StrPtrAnsi psz2;
/// A null-terminated string.
public Vanara.InteropServices.StrPtrAnsi psz3;
/// Pointer to an application-defined value.
public IntPtr pv;
/// Application-defined value used to identify the opened file.
public HFILE hf;
///
/// The MS-DOS date.
///
///
/// Bits
/// Description
///
/// -
/// 0-4
/// Day of the month (1-31)
///
/// -
/// 5-8
/// Month (1 = January, 2 = February, etc.)
///
/// -
/// 9-15
/// Year offset from 1980 (add 1980
///
///
///
public ushort date;
///
/// The MS-DOS time.
///
///
/// Bits
/// Description
///
/// -
/// 0-4
/// Second divided by 2
///
/// -
/// 5-10
/// Minute (0-59)
///
/// -
/// 11-15
/// Hour (0-23 on a 24-hour clock)
///
///
///
public ushort time;
/// The file attributes. For possible values and their descriptions, see File Attributes.
public ushort attribs;
/// The identifier for a cabinet set.
public ushort setID;
/// The number of the cabinets within a set.
public ushort iCabinet;
/// The number of folders within a cabinet.
public ushort iFolder;
///
/// An FDI error code. Possible values include:
///
///
/// Value
/// Meaning
///
/// -
/// FDIERROR_NONE 0x00
/// No error.
///
/// -
/// FDIERROR_CABINET_NOT_FOUND 0x01
/// The cabinet file was not found.
///
/// -
/// FDIERROR_NOT_A_CABINET 0x02
/// The cabinet file does not have the correct format.
///
/// -
/// FDIERROR_UNKNOWN_CABINET_VERSION 0x03
/// The cabinet file has an unknown version number.
///
/// -
/// FDIERROR_CORRUPT_CABINET 0x04
/// The cabinet file is corrupt.
///
/// -
/// FDIERROR_ALLOC_FAIL 0x05
/// Insufficient memory.
///
/// -
/// FDIERROR_BAD_COMPR_TYPE 0x06
/// Unknown compression type used in the cabinet folder.
///
/// -
/// FDIERROR_MDI_FAIL 0x07
/// Failure decompressing data from the cabinet file.
///
/// -
/// FDIERROR_TARGET_FILE 0x08
/// Failure writing to the target file.
///
/// -
/// FDIERROR_RESERVE_MISMATCH 0x09
/// The cabinets within a set do not have the same RESERVE sizes.
///
/// -
/// FDIERROR_WRONG_CABINET 0x0A
/// The cabinet returned by fdintNEXT_CABINET is incorrect.
///
/// -
/// FDIERROR_USER_ABORT 0x0B
/// FDI aborted.
///
///
///
public FDIERROR fdie;
}
/// Provides a handle to a file decompression interface.
[StructLayout(LayoutKind.Sequential)]
public struct HFDI : IHandle
{
private IntPtr handle;
/// Initializes a new instance of the struct.
/// An object that represents the pre-existing handle to use.
public HFDI(IntPtr preexistingHandle) => handle = preexistingHandle;
/// Returns an invalid handle by instantiating a object with .
public static HFDI NULL => new HFDI(IntPtr.Zero);
/// Gets a value indicating whether this instance is a null handle.
public bool IsNull => handle == IntPtr.Zero;
/// Performs an explicit conversion from to .
/// The handle.
/// The result of the conversion.
public static explicit operator IntPtr(HFDI h) => h.handle;
/// Performs an implicit conversion from to .
/// The pointer to a handle.
/// The result of the conversion.
public static implicit operator HFDI(IntPtr h) => new HFDI(h);
/// Implements the operator !=.
/// The first handle.
/// The second handle.
/// The result of the operator.
public static bool operator !=(HFDI h1, HFDI h2) => !(h1 == h2);
/// Implements the operator ==.
/// The first handle.
/// The second handle.
/// The result of the operator.
public static bool operator ==(HFDI h1, HFDI h2) => h1.Equals(h2);
///
public override bool Equals(object obj) => obj is HFDI h ? handle == h.handle : false;
///
public override int GetHashCode() => handle.GetHashCode();
///
public IntPtr DangerousGetHandle() => handle;
}
/// Provides a for that is disposed using .
public class SafeHFDI : SafeHANDLE
{
/// Initializes a new instance of the class and assigns an existing handle.
/// An object that represents the pre-existing handle to use.
///
/// to reliably release the handle during the finalization phase; otherwise, (not recommended).
///
public SafeHFDI(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }
/// Initializes a new instance of the class.
private SafeHFDI() : base() { }
/// Performs an implicit conversion from to .
/// The safe handle instance.
/// The result of the conversion.
public static implicit operator HFDI(SafeHFDI h) => h.handle;
///
protected override bool InternalReleaseHandle() => FDIDestroy(this);
}
}
}