2017-04-21 4 views
1

J'utilise dans mon programme la fonctionnalité "Kernel32.dll" pour accéder aux secteurs de disque bruts sur le système d'exploitation WinXP SP3 (disque dur externe). Tout fonctionne bien jusqu'à ce que le programme atteigne le numéro de secteur 8388607 - ce qui signifie que le décalage d'octets dans SetFilePointer dépasse 32 bits (uint!). Mais mon code, comme ci-dessous, utilise toutes les variables comme "long". Qu'est ce que je fais mal?C# - Accès aux secteurs bruts en décalage supérieur (supérieur à 4G) sur le disque dur externe

Le code (sur "Dump" bouton clic):

int drive = DRV.SelectedIndex; // DRV is the drive combo box 
long bps = BytesPerSector(drive), spt = GetTotalSectors(drive); 
string dr = DRV.SelectedItem.ToString(); 
int moveToHigh, read = 0; 

uint GENERIC_READ = 0x80000000; 
uint OPEN_EXISTING = 3; 
SafeFileHandle handleValue = CreateFile(dr, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); 
if (handleValue.IsInvalid) 
    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 

// idx = Loop starting index 
// FS = The starting sector index 
// TS = The final sector index 
long idx = (FS == -1) ? 0 : FS, tot = (TS == -1) ? spt : TS; 

for (; idx < tot; idx++) 
{ 
     byte[] b = new byte[bps]; 

     // HERE IS THE ISSUE!!! 
     SetFilePointer(handleValue, idx*bps), out moveToHigh, EMoveMethod.Current); 

     if (ReadFile(handleValue, b, bps, out read, IntPtr.Zero) == 0) 
      Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 



     if (this.IsDisposed == true) { handleValue.Close(); break; } 
      Application.DoEvents(); 
    } 
    handleValue.Close(); 

Les fonctions externes Kernel32.dll:

[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
static extern uint SetFilePointer(
     [In] SafeFileHandle hFile, 
     [In] long lDistanceToMove, 
     [Out] out int lpDistanceToMoveHigh, 
     [In] EMoveMethod dwMoveMethod); 

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, 
     uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, 
     uint dwFlagsAndAttributes, IntPtr hTemplateFile); 

[DllImport("kernel32", SetLastError = true)] 
internal extern static int ReadFile(SafeFileHandle handle, byte[] bytes, 
     int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero); 

J'ai essayé beaucoup de choses, mais aucune idée de ce qui ne va pas, l'application juste se terminant par une exception fatale demandant d'envoyer un rapport de bug

Merci beaucoup

+0

Que se passe-t-il alors? Les erreurs? Et pourquoi utiliseriez-vous des doubles pour les entiers? Aussi longtemps dans .NET n'est pas la même que la longue dans Win32API. –

Répondre

1

Votre définition de P/Invoke est erronée. La fonction prend une valeur de 32 bits, mais vous l'avez définie comme une valeur de 64 bits. Il ne fonctionnera pas correctement et certainement pas passé la plage de valeurs de 32 bits.

Voir la définition et par exemple sur la façon d'utiliser au pinvoke.net:

[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
private static extern int SetFilePointer(IntPtr handle, int lDistanceToMove, out int lpDistanceToMoveHigh, uint dwMoveMethod); 


int lo = (int)(offset & 0xffffffff); 
int hi = (int)(offset >> 32); 

lo = SetFilePointer(handle, lo, out hi, moveMethod); 

Vous avez donc besoin de diviser la valeur de 64 bits en deux et fournir les deux parties pour la fonction.

N'utilisez pas non plus de doubles pour les entiers. Vous aurez des ennuis lorsque la précision se termine et il n'y a aucune raison de les utiliser.

+0

Je l'ai corrigé, mais ensuite sur le secteur # 8388636 J'obtiens l'exception "HRESULT: 0x80070017" sans aucune explication claire de ce qui s'est exactement passé. Que cela veut-il dire? – Xerix

+0

Je l'ai trouvé: Je cherchais depuis le début, j'ai changé pour Begin. – Xerix