2017-02-23 2 views
1

J'essaie d'utiliser DeviceIoControl avec le code de contrôle FSCTL_SET_ZERO_DATA en C#.DeviceIoControl avec FSCTL_SET_ZERO_DATA renvoie ERROR_INVALID_PARAMETER

J'ai créé le fichier C:\tmp\test.txt et à l'intérieur j'ai mis le texte "aaaa".

J'ai couru le code et j'ai reçu le numéro d'erreur: 87
Selon MSDN: "Le paramètre est incorrect."

enter image description here

Je suppose que le problème est parce que j'envoie tampon d'entrée (numéro de paramètre 3 DeviceIoControl) sans aucune donnée.

Le DeviceIoControl renvoie false.
Comment puis-je insérer des paramètres valides à DeviceIoControl avec FSCTL_SET_ZERO_DATA qui le fera retourner true?

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading.Tasks; 

namespace ConsoleApplication1 
{ 
    class Program2 
    { 
     [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)] 
     static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, 
IntPtr lpInBuffer, uint nInBufferSize, 
IntPtr lpOutBuffer, uint nOutBufferSize, 
out uint lpBytesReturned, IntPtr lpOverlapped); 

     [Flags] 
     public enum EMethod : uint 
     { 
      Buffered = 0, 
      InDirect = 1, 
      OutDirect = 2, 
      Neither = 3 
     } 

     [Flags] 
     public enum EFileDevice : uint 
     { 
      FileSystem = 0x00000009 
     } 

     [Flags] 
     public enum EIOControlCode : uint 
     { 
      FsctlSetZeroData = (EFileDevice.FileSystem << 16) | (50 << 2) | EMethod.Buffered | (FileAccess.Write << 14), 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     struct FILE_ZERO_DATA_INFORMATION 
     { 
      public FILE_ZERO_DATA_INFORMATION(long offset, long count) 
      { 
       FileOffset = offset; 
       BeyondFinalZero = offset + count; 
      } 

      public long FileOffset; 
      public long BeyondFinalZero; 
     } 

     [DllImport("kernel32.dll")] 
     public static extern uint GetLastError(); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern IntPtr CreateFile(
     [MarshalAs(UnmanagedType.LPTStr)] string filename, 
     [MarshalAs(UnmanagedType.U4)] FileAccess access, 
     [MarshalAs(UnmanagedType.U4)] FileShare share, 
     IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero 
     [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, 
     uint flagsAndAttributes, 
     IntPtr templateFile); 

     static void Main(string[] args) 
     { 
      IntPtr handle = CreateFile(@"C:\tmp\test.txt", FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, (int)FileAttributes.Normal, IntPtr.Zero); 

      long length = 2; 
      FILE_ZERO_DATA_INFORMATION data = new FILE_ZERO_DATA_INFORMATION(0, length); 
      uint structSize = (uint)Marshal.SizeOf(data); 
      IntPtr pBuffer = Marshal.AllocHGlobal((int)structSize); 


      uint bytesReturned = 0; 
      bool succeed = DeviceIoControl(handle, (uint)EIOControlCode.FsctlSetZeroData, pBuffer, 5, IntPtr.Zero, 5, out bytesReturned, IntPtr.Zero); 

      // bool succeed = DeviceIoControl(handle, (uint)EIOControlCode.FsctlSetZeroData, IntPtr.Zero, 0, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); 
      if (succeed) 
      { 
       Console.WriteLine("Works fine"); 
      } 
      else 
      { 
       uint err = GetLastError(); 
       Console.WriteLine("Error number: {0}", err); 
      } 
     } 

    } 
} 
+1

'nInBufferSize' est la taille de' FILE_ZERO_DATA_INFORMATION', donc '16',' nOutBufferSize' devrait être zéro, voir les docs. – Aybe

+0

Merci, maintenant ça marche. Soumettez-le comme une réponse et je vais le marquer comme une réponse. J'ai changé l'appel à: 'uint pBufferSize = 16; bool réussie = DeviceIoControl (handle, (uint) EIOControlCode.FsctlSetZeroData, pBuffer, pBufferSize, IntPtr.Zero, 0, out octetsReturned, IntPtr.Zero); ' – E235

Répondre

1

Crédit à @Aybe.

Le correctif est:

uint pBufferSize = 16; 
Marshal.StructureToPtr(data, pBuffer, false); 
bool succeed = DeviceIoControl(handle, (uint)EIOControlCode.FsctlSetZeroData, pBuffer, pBufferSize, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); 
  • très important d'ajouter Marshal.StructureToPtr(data, pBuffer, false);

Si vous ne l'ajouter, parfois la fonction retourne vrai et parfois faux.

Here est une référence au code qui utilise également FSCTL avec C#.

+0

Voici quelques représentants supplémentaires. points pour vous :) – Aybe