.net - paragon - ver disco de mac en windows 10
¿Cómo leo un disco directamente con.Net? (4)
Genial, gracias Mark, había olvidado que CreateFile abre las cosas también. Estaba mirando la API de administración de volúmenes y no veía cómo abrir cosas.
Aquí hay una pequeña clase que resume las cosas. También es posible / correcto pasar el SafeFileHandle a FileStream.
using System;
using System.Runtime.InteropServices;
using System.IO;
using Microsoft.Win32.SafeHandles;
namespace ReadFromDevice
{
public class DeviceStream : Stream, IDisposable
{
public const short FILE_ATTRIBUTE_NORMAL = 0x80;
public const short INVALID_HANDLE_VALUE = -1;
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const uint CREATE_NEW = 1;
public const uint CREATE_ALWAYS = 2;
public const uint OPEN_EXISTING = 3;
// Use interop to call the CreateFile function.
// For more information about CreateFile,
// see the unmanaged MSDN reference library.
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadFile(
IntPtr hFile, // handle to file
byte[] lpBuffer, // data buffer
int nNumberOfBytesToRead, // number of bytes to read
ref int lpNumberOfBytesRead, // number of bytes read
IntPtr lpOverlapped
//
// ref OVERLAPPED lpOverlapped // overlapped buffer
);
private SafeFileHandle handleValue = null;
private FileStream _fs = null;
public DeviceStream(string device)
{
Load(device);
}
private void Load(string Path)
{
if (string.IsNullOrEmpty(Path))
{
throw new ArgumentNullException("Path");
}
// Try to open the file.
IntPtr ptr = CreateFile(Path, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
handleValue = new SafeFileHandle(ptr, true);
_fs = new FileStream(handleValue, FileAccess.Read);
// If the handle is invalid,
// get the last Win32 error
// and throw a Win32Exception.
if (handleValue.IsInvalid)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override void Flush()
{
return;
}
public override long Length
{
get { return -1; }
}
public override long Position
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
/// <summary>
/// </summary>
/// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and
/// (offset + count - 1) replaced by the bytes read from the current source. </param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream. </param>
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
/// <returns></returns>
public override int Read(byte[] buffer, int offset, int count)
{
int BytesRead =0;
var BufBytes = new byte[count];
if (!ReadFile(handleValue.DangerousGetHandle(), BufBytes, count, ref BytesRead, IntPtr.Zero))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
for (int i = 0; i < BytesRead; i++)
{
buffer[offset + i] = BufBytes[i];
}
return BytesRead;
}
public override int ReadByte()
{
int BytesRead = 0;
var lpBuffer = new byte[1];
if (!ReadFile(
handleValue.DangerousGetHandle(), // handle to file
lpBuffer, // data buffer
1, // number of bytes to read
ref BytesRead, // number of bytes read
IntPtr.Zero
))
{ Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); ;}
return lpBuffer[0];
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
public override void Close()
{
handleValue.Close();
handleValue.Dispose();
handleValue = null;
base.Close();
}
private bool disposed = false;
new void Dispose()
{
Dispose(true);
base.Dispose();
GC.SuppressFinalize(this);
}
private new void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this.disposed)
{
if (disposing)
{
if (handleValue != null)
{
_fs.Dispose();
handleValue.Close();
handleValue.Dispose();
handleValue = null;
}
}
// Note disposing has been done.
disposed = true;
}
}
}
}
Y un ejemplo de usar la clase
static void Main(string[] args)
{
var reader = new BinaryReader(new DeviceStream(@"//./PhysicalDrive3"));
var writer = new BinaryWriter(new FileStream(@"g:/test.dat", FileMode.Create));
var buffer = new byte[MB];
int count;
int loopcount=0;
try{
while((count=reader.Read(buffer,0,MB))>0)
{
writer.Write(buffer,0,count);
System.Console.Write(''.'');
if(loopcount%100==0)
{
System.Console.WriteLine();
System.Console.WriteLine("100MB written");
writer.Flush();
}
loopcount++;
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
reader.Close();
writer.Flush();
writer.Close();
}
Se aplican cláusulas de exención de responsabilidad estándar, este código puede ser peligroso para su salud.
¿Es posible leer un disco directamente con .Net? Me refiero directamente a través del dispositivo pasando por alto el sistema de archivos. Creo que iría sobre esto abriendo el dispositivo de alguna manera "/ Device / Ide / IdeDeviceP2T0L0-1" por ejemplo.
Si no puedo abrir el dispositivo con una API api, saber qué API de Win32 usar sería útil.
Hombre. Con toda esa clasificación y cosas así, ¿por qué no simplemente escribir un dll en C y renunciar a .NET
A continuación, puede p / invocar a su dll y tener un tiempo mucho más fácil de todo
CreateFile tiene soporte para el acceso directo al disco. Lea las notas en "Discos y volúmenes físicos". Debería poder P / invocar la llamada.
Tenga en cuenta que Vista y Server 2008 han restringido esto severamente .
Estoy de acuerdo con la respuesta de Mark. Tenga en cuenta que si el Control de cuentas de usuario está habilitado (que es el predeterminado en Windows Vista y superior), su programa debe estar ejecutándose elevado (con privilegios administrativos). Si su programa solo se usa para unos pocos usuarios, puede solicitar al usuario que haga clic con el botón derecho en los archivos ejecutables y seleccione "Ejecutar como administrador". De lo contrario, puede compilar un archivo de manifiesto en el programa y, en el manifiesto, especificar que el programa debe ejecutarse de manera elevada (busque "requiredExecutionLevel requireAdministrator" para obtener más información).