2012-03-03 5 views
1

디스크 지오메트리 정보를 가져와야하지만 잘못되어 DeviceIoControl이 false를 반환합니다. 어떤 아이디어로 그것을 고치는 법? 또는 C#과 kernel32를 사용하는 다른 예제가 감사하겠습니다.디스크 지오메트리 정보 얻기

[DllImport("kernel32.dll")] 
      public static extern IntPtr CreateFile(
      string lpFileName, int dwDesiredAccess, int dwShareMode, 
      IntPtr lpSecurityAttributes, int dwCreationDisposition, 
      int dwFlagsAndAttributes, IntPtr hTemplateFile); 

      private const int FILE_SHARE_READ = 1; 
      private const int OPEN_ALWAYS = 4; 
      private const int INVALID_HANDLE_VALUE = -1; 

      [DllImport("kernel32.dll", ExactSpelling = true)] 
      internal static extern bool DeviceIoControl(
      IntPtr hDevice, int dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize, 
      IntPtr lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned, IntPtr lpOverlapped); 

      private const int IOCTL_DISK_GET_MEDIA_TYPES = 0x00070c00; 

      static void Main(string[] args) 
      { 
       IntPtr hflp = CreateFile(@""\\.\C:", 0, FILE_SHARE_READ, IntPtr.Zero, OPEN_ALWAYS, 0, IntPtr.Zero); 
       if ((int)hflp == INVALID_HANDLE_VALUE) 
       { Console.WriteLine("CreateFile failed"); return; } 

       Type ts = typeof(DISK_GEOMETRY); 
       int ss = Marshal.SizeOf(ts); 
       int ssa = ss * 20; 
       IntPtr mptr = Marshal.AllocHGlobal(ssa); 
       int byret = 0; 
       bool ok = DeviceIoControl(hflp, IOCTL_DISK_GET_MEDIA_TYPES, IntPtr.Zero, 0, 
       mptr, ssa, ref byret, IntPtr.Zero); 
       if (!ok) 
       { Console.WriteLine("DeviceIoControl failed"); return; } 
       int count = byret/ss; 
       int run = (int)mptr; 
       DISK_GEOMETRY gem; 
       for (int i = 0; i < count; i++) 
       { 
        gem = (DISK_GEOMETRY)Marshal.PtrToStructure((IntPtr)run, ts); 
        Console.WriteLine("MediaType={0} SectorsPerTrack={1}", gem.MediaType, gem.SectorsPerTrack); 
        run += ss; 
       } 
       Marshal.FreeHGlobal(mptr); 
      } 

피씨 나는 이미 이것에 대한 msdn 도움말을 읽었습니다.

+0

당신은 당신이에 MSDN의 문서를 읽을 말했다 경우 ([GetLastError] 한 그래서 뭐 http://msdn.microsoft.com/en-us/library/windows/ desktop/ms679360 (v = vs.85) .aspx) return (_as는 MSDN docs_에서 제안 했습니까?) –

+0

실제로 ERROR_SUCCESS 또는 0을 반환합니다. – jjjojjjooo

+0

그냥 추측 할 수 있지만 설명서에'작업이 실패 *이거나 보류 중 *이면 반환 값은 0입니다. '라고 표시됩니다. 나는 그것이 후자라고 생각할 것이다. –

답변

2

IOCTL_DISK_GET_MEDIA_TYPES은 더 이상 지원되지 않는 것으로 보입니다. 적어도 그것은 내 OS (Win7 x64)의 경우입니다. DeviceIoControlIOCTL_DISK_GET_MEDIA_TYPES으로 호출하면 오류 코드 1 (ERROR_INVALID_FUNCTION)이됩니다.

대신 IOCTL_STORAGE_GET_MEDIA_TYPES_EX을 사용해야합니다.

이 상황에서 내 조언은 C++에서 API 함수를 먼저 호출하는 것입니다. 그렇게하면 p/invoke와 싸울 필요가 없으며 모든 구조와 함수 프로토 타입이 정확하다는 것을 알 수 있습니다. 특정 API 함수를 호출하는 방법을 찾았 으면 p/invoke로 변환하십시오.

제쳐두고, p/invokes에 대해 좀 더주의해야합니다. uint을 사용하여 DWORD과 일치시키고 Marshal.GetLastWin32Error()으로 오류 코드를 쿼리 할 수 ​​있도록 SetLastError=true을 사용해야합니다. 이 같은

뭔가 :

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

[DllImport("kernel32.dll", SetLastError=true)] 
internal static extern bool DeviceIoControl(
    IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer, 
    uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, 
    ref uint lpBytesReturned, IntPtr lpOverlapped); 
+0

또한 CreateFile에서 SafeFileHandle을 반환해야합니다. 같은 토큰으로 SafeFileHandle을 DeviceIoControl 함수 (hDevice 매개 변수)에 전달하십시오. – Hans