home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 February / PCO_0299.ISO / filesbbs / w95 / diskspe.exe / Q137176.TXT < prev    next >
Encoding:
Text File  |  1996-01-15  |  11.7 KB  |  353 lines

  1. DOCUMENT:Q137176  09-JAN-1996  [win32sdk]
  2. TITLE   :PRB: DeviceIoControl Int 13h Does Not Support Hard Disks
  3. PRODUCT :Microsoft Win32 Software Development Kit
  4. PROD/VER:4.00
  5. OPER/SYS:WINDOWS
  6. KEYWORDS:kbprg kbprb
  7.  
  8. -------------------------------------------------------------------------
  9. The information in this article applies to:
  10.  
  11.  - Microsoft Win32 Application Programming Interface (API) included with:
  12.  
  13.     - Microsoft Windows 95 version 4.0
  14. -------------------------------------------------------------------------
  15.  
  16. SYMPTOMS
  17. ========
  18.  
  19. Win32-based applications running under Windows 95 use CreateFile to open
  20. VWIN32 and then use DeviceIoControl with the VWIN32_DIOC_DOS_INT13 flag to
  21. perform low-level BIOS disk functions. The functions work on floppy
  22. disks but always fail on hard disks.
  23.  
  24. CAUSE
  25. =====
  26.  
  27. Windows 95, like previous versions of Windows, does not support
  28. calling BIOS disk functions to gain access to hard disks from protected
  29. mode Windows- and Win32-based applications. The cause of this lack of
  30. support for hard disks is that BIOSXLAT.VXD does not translate BIOS
  31. requests from protected-mode into V86 mode, and this causes the ROM BIOS to
  32. be called with an invalid address.
  33.  
  34. RESOLUTION
  35. ==========
  36.  
  37. To work around this problem, Win32-based applications must thunk to a
  38. Windows 16-bit DLL and have that DLL call the DOS Protected Mode Interface
  39. (DPMI) Simulate Real Mode Interrupt function to call Int 13h BIOS disk
  40. functions on hard disks. When you use DPMI to call Int 13h BIOS disk
  41. functions, you bypass BIOSXLAT.VXD and call the real-mode BIOS. Note
  42. that you cannot call DPMI from 32-bit code.
  43.  
  44. STATUS
  45. ======
  46.  
  47. This behavior is by design.
  48.  
  49. MORE INFORMATION
  50. ================
  51.  
  52. The following example code shows how a Win32-based application running
  53. under Windows 95 can read the first physical sector of a hard disk, which
  54. contains the disk's partition tables. This code requires a flat thunk, so
  55. parts of it must be placed in a Win32 DLL and other parts must be placed
  56. in a Windows 16-bit DLL. The relevant code for each DLL is labeled.
  57.  
  58. Execution starts from a Win32-based application calling the Win32 DLL and
  59. proceeds as follows. The Win32 DLL function, CallReadPhysicalSector1, calls
  60. the 16-bit DLL's ReadPhysicalSector1 function by way of a thunk. Then
  61. ReadPhysicalSector1, which is exported by the 16-bit DLL, calls DPMI
  62. to call the BIOS Read Track function to read the first sector of the
  63. specified hard disk. After ReadPhysicalSector1 returns, the contents
  64. of the first sector of the hard disk, including the hard disk's
  65. partition table and bootstrap program, will be in the buffer pointed
  66. to by lpBuff.
  67.  
  68. Code Sample
  69. -----------
  70.  
  71. //--------------------------------------------------------------------
  72. // Code in the 32-bit DLL
  73.  
  74. // Prototype for function in 16-bit DLL.
  75. BOOL FAR PASCAL ReadPhysicalSector1 (BYTE   bDrive,
  76.                                      LPBYTE lpBuffer,
  77.                                      DWORD  cbBuffSize);
  78.  
  79. /*--------------------------------------------------------------------
  80.  CallReadPhysicalSector1()
  81.  
  82.  Reads the first sector of the first hard disk.
  83.  
  84.  Return Value
  85.     Returns TRUE if the first sector was read, and FALSE if it
  86.     wasn't.
  87. --------------------------------------------------------------------*/
  88. __declspec(dllexport) BOOL WINAPI CallReadPhysicalSector1()
  89. {
  90.     char lpBuff[512];
  91.     BOOL fResult;
  92.  
  93.     // Read the first sector of the first hard disk.
  94.     fResult = ReadPhysicalSector1 (0x80, lpBuff, 512);
  95.  
  96.     if (fResult)
  97.        {
  98.         // lpBuff contains the sector data.  Use it here
  99.        }
  100.  
  101.     return fResult;
  102. }
  103.  
  104.  
  105. //--------------------------------------------------------------------
  106. // Thunk Script
  107.  
  108. enablemapdirect3216 = true;
  109.  
  110. typedef unsigned long   DWORD;
  111. typedef unsigned char   BYTE, * LPBYTE;
  112. typedef bool            BOOL;
  113.  
  114. BOOL ReadPhysicalSector1 (BYTE   bDrive,
  115.                           LPBYTE lpBuffer,
  116.                           DWORD  cbBuffSize)
  117. {
  118.    lpBuffer = inout;
  119. }
  120.  
  121.  
  122. //--------------------------------------------------------------------
  123. // Code in the 16-bit DLL
  124.  
  125. // Converts two BYTEs into a WORD.  This is useful for working with
  126. // a RMCS, but was not provided in WINDOWS.H.
  127.  
  128. //#define MAKEWORD(low, high) \
  129.            ((WORD)((((WORD)(high)) << 8) | ((BYTE)(low))))
  130.  
  131. #define SECTOR_SIZE 512       // Size, in bytes, of a disk sector
  132. #define CARRY_FLAG  0x0001
  133.  
  134. typedef BYTE FAR *LPBYTE;
  135.  
  136. typedef struct tagRMCS
  137. {
  138.    DWORD edi, esi, ebp, RESERVED, ebx, edx, ecx, eax;
  139.    WORD  wFlags, es, ds, fs, gs, ip, cs, sp, ss;
  140. } RMCS, FAR* LPRMCS;
  141.  
  142. BOOL FAR PASCAL SimulateRM_Int (BYTE bIntNum, LPRMCS lpCallStruct);
  143. void FAR PASCAL BuildRMCS (LPRMCS lpCallStruct);
  144. BOOL FAR PASCAL __export ReadPhysicalSector1 (BYTE   bDrive,
  145.                                               LPBYTE lpBuffer,
  146.                                               DWORD  cbBuffSize);
  147.  
  148. /*--------------------------------------------------------------------
  149.   ReadPhysicalSector1()
  150.  
  151.   Calls DPMI to call the BIOS Int 13h Read Track function to read the
  152.   first physical sector of a physical drive. This function is used to
  153.   read partition tables, for example.
  154.  
  155.   Parameters
  156.      bDrive
  157.         The Int 13h device unit,
  158.            0x00 for floppy drive 0
  159.            0x00 for floppy drive 1
  160.            0x80 for physical hard disk 0
  161.            0x81 for physical hard disk 1
  162.            etc.
  163.  
  164.      lpBuffer
  165.         Pointer to a buffer that receives the sector data.  The buffer
  166.         must be at least SECTOR_SIZE bytes long.
  167.  
  168.      cbBuffSize
  169.         Actual size of lpBuffer.
  170.  
  171.   Return Value
  172.      Returns TRUE if the first sector was read into the buffer pointed
  173.      to by lpBuffer, or FALSE otherwise.
  174.  
  175.   Assumptions
  176.      Assumes that sectors are at least SECTOR_SIZE bytes long.
  177. --------------------------------------------------------------------*/
  178.  
  179. BOOL FAR PASCAL __export ReadPhysicalSector1 (BYTE   bDrive,
  180.                                               LPBYTE lpBuffer,
  181.                                               DWORD  cbBuffSize)
  182. {
  183.    BOOL   fResult;
  184.    RMCS   callStruct;
  185.    DWORD  gdaBuffer;     // Return value of GlobalDosAlloc().
  186.    LPBYTE RMlpBuffer;    // Real-mode buffer pointer
  187.    LPBYTE PMlpBuffer;    // Protected-mode buffer pointer
  188.  
  189.    /*
  190.      Validate params:
  191.         bDrive should be int 13h device unit -- let the BIOS validate
  192.            this parameter -- user could have a special controller with
  193.            its own BIOS.
  194.         lpBuffer must not be NULL
  195.         cbBuffSize must be large enough to hold a single sector
  196.    */
  197.  
  198.    if (lpBuffer == NULL || cbBuffSize < SECTOR_SIZE)
  199.       return FALSE;
  200.  
  201.    /*
  202.      Allocate the buffer that the Int 13h function will put the sector
  203.      data into. As this function uses DPMI to call the real-mode BIOS, it
  204.      must allocate the buffer below 1 MB, and must use a real-mode
  205.      paragraph-segment address.
  206.  
  207.      After the memory has been allocated, create real-mode and
  208.      protected-mode pointers to the buffer. The real-mode pointer
  209.      will be used by the BIOS, and the protected-mode pointer will be
  210.      used by this function because it resides in a Windows 16-bit DLL,
  211.      which runs in protected mode.
  212.    */
  213.  
  214.    gdaBuffer = GlobalDosAlloc (cbBuffSize);
  215.  
  216.    if (!gdaBuffer)
  217.       return FALSE;
  218.  
  219.    RMlpBuffer = (LPBYTE)MAKELONG(0, HIWORD(gdaBuffer));
  220.    PMlpBuffer = (LPBYTE)MAKELONG(0, LOWORD(gdaBuffer));
  221.  
  222.    /*
  223.      Initialize the real-mode call structure and set all values needed
  224.      to read the first sector of the specified physical drive.
  225.    */
  226.  
  227.    BuildRMCS (&callStruct);
  228.  
  229.    callStruct.eax = 0x0201;                // BIOS read, 1 sector
  230.    callStruct.ecx = 0x0001;                // Sector 1, Cylinder 0
  231.    callStruct.edx = MAKEWORD(bDrive, 0);   // Head 0, Drive #
  232.    callStruct.ebx = LOWORD(RMlpBuffer);    // Offset of sector buffer
  233.    callStruct.es  = HIWORD(RMlpBuffer);    // Segment of sector buffer
  234.  
  235.    /*
  236.       Call Int 13h BIOS Read Track and check both the DPMI call
  237.       itself and the BIOS Read Track function result for success.  If
  238.       successful, copy the sector data retrieved by the BIOS into the
  239.       caller's buffer.
  240.    */
  241.  
  242.    if (fResult = SimulateRM_Int (0x13, &callStruct))
  243.       if (!(callStruct.wFlags & CARRY_FLAG))
  244.          {
  245.          _fmemcpy (lpBuffer, PMlpBuffer, (size_t)cbBuffSize);
  246.          fResult = TRUE;
  247.          }
  248.       else
  249.          fResult = FALSE;
  250.  
  251.    // Free the sector data buffer this function allocated
  252.    GlobalDosFree (LOWORD(gdaBuffer));
  253.  
  254.    return fResult;
  255. }
  256.  
  257.  
  258. /*--------------------------------------------------------------------
  259.   SimulateRM_Int()
  260.  
  261.   Allows protected mode software to execute real mode interrupts such
  262.   as calls to DOS TSRs, DOS device drivers, etc.
  263.  
  264.   This function implements the "Simulate Real Mode Interrupt" function
  265.   of the DPMI specification v0.9.
  266.  
  267.   Parameters
  268.      bIntNum
  269.         Number of the interrupt to simulate
  270.  
  271.      lpCallStruct
  272.         Call structure that contains params (register values) for
  273.         bIntNum.
  274.  
  275.   Return Value
  276.      SimulateRM_Int returns TRUE if it succeeded or FALSE if it
  277.      failed.
  278.  
  279.   Comments
  280.      lpCallStruct is a protected-mode selector:offset address, not a
  281.      real-mode segment:offset address.
  282. --------------------------------------------------------------------*/
  283.  
  284. BOOL FAR PASCAL SimulateRM_Int (BYTE bIntNum, LPRMCS lpCallStruct)
  285.    {
  286.    BOOL fRetVal = FALSE;      // Assume failure
  287.  
  288.    _asm {
  289.          push di
  290.  
  291.          mov  ax, 0300h         ; DPMI Simulate Real Mode Int
  292.          mov  bl, bIntNum       ; Number of the interrupt to simulate
  293.          mov  bh, 01h           ; Bit 0 = 1; all other bits must be 0
  294.          xor  cx, cx            ; No words to copy
  295.          les  di, lpCallStruct
  296.          int  31h                   ; Call DPMI
  297.          jc   END1                  ; CF set if error occurred
  298.          mov  fRetVal, TRUE
  299.       END1:
  300.          pop di
  301.         }
  302.    return (fRetVal);
  303.    }
  304.  
  305. /*--------------------------------------------------------------------
  306.   BuildRMCS()
  307.  
  308.   Initializes a real mode call structure to contain zeros in all its
  309.   members.
  310.  
  311.   Parameters:
  312.      lpCallStruct
  313.         Points to a real mode call structure
  314.  
  315.   Comments:
  316.      lpCallStruct is a protected-mode selector:offset address, not a
  317.      real-mode segment:offset address.
  318. --------------------------------------------------------------------*/
  319.  
  320. void FAR PASCAL BuildRMCS (LPRMCS lpCallStruct)
  321.    {
  322.    _fmemset (lpCallStruct, 0, sizeof (RMCS));
  323.    }
  324.  
  325. REFERENCES
  326. ==========
  327.  
  328. Information on using DPMI may be found in the DOS Protected Mode
  329. Interface (DPMI) Specification Version 0.9.
  330.  
  331. Flat thunks are documented in "The Microsoft Programmer's Guide To
  332. Windows 95" topic in the Win32 Software Development Kit online
  333. documentation.
  334.  
  335. Additional reference words: 4.00 Windows 95 sector table physical
  336. KBCategory: kbprg kbprb
  337. KBSubcategory: BseFileio
  338.  
  339. =============================================================================
  340.  
  341. THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS
  342. PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.  MICROSOFT DISCLAIMS
  343. ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES
  344. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO
  345. EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR
  346. ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL,
  347. CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF
  348. MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE
  349. POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO NOT ALLOW THE EXCLUSION
  350. OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES
  351. SO THE FOREGOING LIMITATION MAY NOT APPLY.
  352.  
  353. Copyright Microsoft Corporation 1996.