////////////////////////////////////////////////////////////////////////////// // // Description: // // This module contains the entry and exit functions for windows DLL // initialization and the 16 bit net functions. // ////////////////////////////////////////////////////////////////////////////// // // History: // // jennymc 8/2/95 Initial version // jennymc 1/8/98 modified for wbem // // Copyright (c) 1995-2001 Microsoft Corporation, All Rights Reserved // ////////////////////////////////////////////////////////////////////////////// // These are specific data types defined in the thunk ////////////////////////////////////////////////////////////////////////////// #define WIN32_LEAN_AND_MEAN 1 #define NOWINDOWSX 1 #include #include #include #define LANMAN_BUFFER_SIZE 0x0800 #define INCL_NETUSER #define INCL_NETGROUP #define INCL_NETERRORS #define INCL_NETDOMAIN #define INCL_NETUSE #include "lan.h" #define Not_VxD typedef unsigned long ULONG; #include "vmm.h" #define MIDL_PASS #include "configmg.h" #include // #define MAKEWORD(low, high) \ ((WORD)((((WORD)(high)) << 8) | ((BYTE)(low)))) #define SECTOR_SIZE 512 // Size, in bytes, of a disk sector #define CARRY_FLAG 0x0001 #define __export _export typedef BYTE FAR *LPBYTE; typedef struct tagRMCS { DWORD edi, esi, ebp, RESERVED, ebx, edx, ecx, eax; WORD wFlags, es, ds, fs, gs, ip, cs, sp, ss; } RMCS, FAR* LPRMCS; BOOL FAR PASCAL SimulateRM_Int (BYTE bIntNum, LPRMCS lpCallStruct); void FAR PASCAL BuildRMCS (LPRMCS lpCallStruct); ////////////////////////////////////////////////////////////////////////////// BOOL WINAPI _export DllEntryPoint (DWORD dwReason, WORD hInst, WORD wDS, WORD wHeapSize, DWORD dwReserved1, WORD wReserved2); BOOL WINAPI _export win32thk_ThunkConnect16(LPSTR pszDll16, LPSTR pszDll32, WORD hInst, DWORD dwReason); ////////////////////////////////////////////////////////////////////////////// // NET FUNCTIONS ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // Function: // // WEP(int) // // Description: // // This function is called when the DLL is unloaded by the last application // which has it open. // ////////////////////////////////////////////////////////////////////////////// VOID FAR PASCAL WEP(int bSystemExit) { return; } ////////////////////////////////////////////////////////////////////// ULONG WINAPI _export CIM16GetUserInfo1(LPSTR Name, LPSTR HomeDirectory, LPSTR Comment, LPSTR ScriptPath, LPULONG PasswordAge, LPUSHORT Privileges, LPUSHORT Flags ) { // Used to get the the data struct user_info_1 * lpUserInfo1; char szBuffer[LANMAN_BUFFER_SIZE]; char szLogon[LANMAN_BUFFER_SIZE]; USHORT uSize = LANMAN_BUFFER_SIZE,uTotal=0; ULONG apiRc; apiRc = NetGetDCName(NULL,NULL,szLogon,uSize); if( apiRc == NERR_Success ){ //*********************************************************** // Get info for User Info 1 //*********************************************************** apiRc = NetUserGetInfo(szLogon,Name,1,szBuffer,uSize,&uTotal ); if (apiRc == NERR_Success){ //*********************************************************** // Assign the stuff we got from the user_info_1 struct //*********************************************************** lpUserInfo1 = (struct user_info_1 * ) szBuffer; strcpy( HomeDirectory, lpUserInfo1->usri1_home_dir); strcpy( ScriptPath, lpUserInfo1->usri1_script_path); strcpy( Comment,lpUserInfo1->usri1_comment); *PasswordAge = lpUserInfo1->usri1_password_age; *Privileges = lpUserInfo1->usri1_priv; *Flags = lpUserInfo1->usri1_flags; } } return apiRc; } ////////////////////////////////////////////////////////////////////// ULONG WINAPI __export CIM16GetUserInfo2(LPSTR Name, LPSTR FullName, LPSTR UserComment, LPSTR Parameters, LPSTR Workstations, LPSTR LogonServer, LPLOGONDETAILS LogonDetails ) { // Used to get the the data struct user_info_2 * lpUserInfo2; char szBuffer[LANMAN_BUFFER_SIZE]; char szLogon[LANMAN_BUFFER_SIZE]; USHORT uSize = LANMAN_BUFFER_SIZE,uTotal=0; ULONG apiRc; apiRc = NetGetDCName(NULL,NULL,szLogon,uSize); if( apiRc == NERR_Success ){ //*********************************************************** // Get the user_info_2 struct stuff //*********************************************************** apiRc = NetUserGetInfo(szLogon,Name,2,szBuffer,uSize,&uTotal ); if (apiRc == NERR_Success){ //*********************************************************** // Assign the stuff we got from the user_info_1 struct //*********************************************************** lpUserInfo2 = (struct user_info_2 * ) szBuffer; strcpy( FullName,lpUserInfo2->usri2_full_name ); strcpy( UserComment,lpUserInfo2->usri2_usr_comment); strcpy( Parameters,lpUserInfo2->usri2_parms); strcpy( Workstations,lpUserInfo2->usri2_workstations); strcpy( LogonServer,lpUserInfo2->usri2_logon_server); strcpy(LogonDetails->LogonHours,lpUserInfo2->usri2_logon_hours); LogonDetails->AuthorizationFlags = lpUserInfo2->usri2_auth_flags; LogonDetails->LastLogon = lpUserInfo2->usri2_last_logon; LogonDetails->LastLogoff = lpUserInfo2->usri2_last_logoff; LogonDetails->AccountExpires = lpUserInfo2->usri2_acct_expires; LogonDetails->MaximumStorage = lpUserInfo2->usri2_max_storage; LogonDetails->UnitsPerWeek = lpUserInfo2->usri2_units_per_week; LogonDetails->BadPasswordCount = lpUserInfo2->usri2_bad_pw_count; LogonDetails->NumberOfLogons = lpUserInfo2->usri2_num_logons; LogonDetails->CountryCode = lpUserInfo2->usri2_country_code; LogonDetails->CodePage = lpUserInfo2->usri2_code_page; } } return apiRc; } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ULONG WINAPI __export CIM16GetUserInfo1Ex(LPSTR Domain, LPSTR Name, DWORD fGetDC, LPSTR HomeDirectory, LPSTR Comment, LPSTR ScriptPath, LPULONG PasswordAge, LPUSHORT Privileges, LPUSHORT Flags ) { // Used to get the the data struct user_info_1 * lpUserInfo1; char szBuffer[LANMAN_BUFFER_SIZE]; char szLogon[LANMAN_BUFFER_SIZE]; USHORT uSize = LANMAN_BUFFER_SIZE,uTotal=0; ULONG apiRc = 1; // If a domain was specified, use it to get the dc. Otherwise, // go straight to the NetUserGetInfoCall with the name of the // local machine for szLogon... if(fGetDC != 0) { apiRc = NetGetDCName(NULL,Domain,szLogon,uSize); apiRc = NetUserGetInfo(szLogon,Name,1,szBuffer,uSize,&uTotal ); } else { apiRc = NetUserGetInfo(NULL,Name,1,szBuffer,uSize,&uTotal ); } if( apiRc == NERR_Success ) { //*********************************************************** // Assign the stuff we got from the user_info_1 struct //*********************************************************** lpUserInfo1 = (struct user_info_1 * ) szBuffer; strcpy( HomeDirectory, lpUserInfo1->usri1_home_dir); strcpy( ScriptPath, lpUserInfo1->usri1_script_path); strcpy( Comment,lpUserInfo1->usri1_comment); *PasswordAge = lpUserInfo1->usri1_password_age; *Privileges = lpUserInfo1->usri1_priv; *Flags = lpUserInfo1->usri1_flags; } return apiRc; } ////////////////////////////////////////////////////////////////////// ULONG WINAPI __export CIM16GetUserInfo2Ex(LPSTR Domain, LPSTR Name, DWORD fGetDC, LPSTR FullName, LPSTR UserComment, LPSTR Parameters, LPSTR Workstations, LPSTR LogonServer, LPLOGONDETAILS LogonDetails ) { // Used to get the the data struct user_info_2 * lpUserInfo2; char szBuffer[LANMAN_BUFFER_SIZE]; char szLogon[LANMAN_BUFFER_SIZE]; USHORT uSize = LANMAN_BUFFER_SIZE,uTotal=0; ULONG apiRc; // If a domain was specified, use it to get the dc. Otherwise, // go straight to the NetUserGetInfoCall with the name of the // local machine for szLogon... if(fGetDC != 0) { apiRc = NetGetDCName(NULL,Domain,szLogon,uSize); apiRc = NetUserGetInfo(szLogon,Name,2,szBuffer,uSize,&uTotal ); } else { apiRc = NetUserGetInfo(NULL,Name,2,szBuffer,uSize,&uTotal ); } if( apiRc == NERR_Success ) { //*********************************************************** // Assign the stuff we got from the user_info_2 struct //*********************************************************** lpUserInfo2 = (struct user_info_2 * ) szBuffer; strcpy( FullName,lpUserInfo2->usri2_full_name ); strcpy( UserComment,lpUserInfo2->usri2_usr_comment); strcpy( Parameters,lpUserInfo2->usri2_parms); strcpy( Workstations,lpUserInfo2->usri2_workstations); strcpy( LogonServer,lpUserInfo2->usri2_logon_server); strcpy(LogonDetails->LogonHours,lpUserInfo2->usri2_logon_hours); LogonDetails->AuthorizationFlags = lpUserInfo2->usri2_auth_flags; LogonDetails->LastLogon = lpUserInfo2->usri2_last_logon; LogonDetails->LastLogoff = lpUserInfo2->usri2_last_logoff; LogonDetails->AccountExpires = lpUserInfo2->usri2_acct_expires; LogonDetails->MaximumStorage = lpUserInfo2->usri2_max_storage; LogonDetails->UnitsPerWeek = lpUserInfo2->usri2_units_per_week; LogonDetails->BadPasswordCount = lpUserInfo2->usri2_bad_pw_count; LogonDetails->NumberOfLogons = lpUserInfo2->usri2_num_logons; LogonDetails->CountryCode = lpUserInfo2->usri2_country_code; LogonDetails->CodePage = lpUserInfo2->usri2_code_page; } return apiRc; } ////////////////////////////////////////////////////////////////////// API_RET_TYPE WINAPI __export CIM16GetUseInfo1( LPSTR Name, LPSTR Local, LPSTR Remote, LPSTR Password, LPULONG pdwStatus, LPULONG pdwType, LPULONG pdwRefCount, LPULONG pdwUseCount) { char szBuffer[LANMAN_BUFFER_SIZE]; USHORT uSize = sizeof(szBuffer), uTotal = 0; API_RET_TYPE ret; ret = NetUseGetInfo(NULL, Name, 1, szBuffer, uSize, &uTotal); if (ret == NERR_Success) { struct use_info_1 *pInfo = (struct use_info_1 *) szBuffer; lstrcpy(Local, pInfo->ui1_local); lstrcpy(Remote, pInfo->ui1_remote); lstrcpy(Password, pInfo->ui1_password); *pdwStatus = pInfo->ui1_status; *pdwType = pInfo->ui1_asg_type; *pdwRefCount = pInfo->ui1_refcount; *pdwUseCount = pInfo->ui1_usecount; } return ret; } // pbBuffer is used internally as a work buffer. It should be allocated and // freed by the caller, and should be the same length as pBuffer2, which // is a pointer to an array of use_info_1Out structures. // The reason we need to do this, is because if we just send back a LPSTR, the // ui1_remote pointer in the use_info_1 structure won't get adjusted correctly // by the thunking layer. So, we make a fixed length structure, and send // the value back in it. API_RET_TYPE WINAPI __export CIM16NetUseEnum( LPCSTR pszServer, short sLevel, LPSTR pbBuffer, use_info_1Out far *pBuffer2, unsigned short cbBuffer, unsigned short far *pcEntriesRead, unsigned short far *pcTotalAvail ) { API_RET_TYPE art; use_info_1 *pBuffer3; unsigned int x; art = NetUseEnum(pszServer, sLevel, pbBuffer, cbBuffer, pcEntriesRead, pcTotalAvail); if (art == NERR_Success) { if (*pcEntriesRead <= (cbBuffer / sizeof(use_info_1Out))) { pBuffer3 = (use_info_1 *)pbBuffer; for (x=0; x < *pcEntriesRead; x++) { strcpy(pBuffer2[x].ui1_local, pBuffer3[x].ui1_local); pBuffer2[x].ui1_pad_1 = pBuffer3[x].ui1_pad_1; strcpy(pBuffer2[x].ui1_remote, pBuffer3[x].ui1_remote); pBuffer2[x].ui1_status = pBuffer3[x].ui1_status; pBuffer2[x].ui1_asg_type = pBuffer3[x].ui1_asg_type; pBuffer2[x].ui1_refcount = pBuffer3[x].ui1_refcount; pBuffer2[x].ui1_usecount = pBuffer3[x].ui1_usecount; } } else { // This means that although the pbBuffer was big enough // to hold the data, pBuffer2 didn't have enough entries. // Remember that pBuffer2 uses fixed lengths. art = ERROR_MORE_DATA; } } return art; } ////////////////////////////////////////////////////////////////////// ULONG WINAPI __export CIM16GetConfigManagerStatus(LPSTR HardwareKey) { // Used to get the the data DEVNODE Devnode; ULONG ulStatus = 0L; ULONG ulProblem = 0L; memset(&Devnode,NULL,sizeof(Devnode)); if( CR_SUCCESS == CM_Locate_DevNode(&Devnode,HardwareKey,0)){ CM_Get_DevNode_Status(&ulStatus,&ulProblem,Devnode,0); } return ulStatus; } WORD WINAPI __export CIM16_CM_Locate_DevNode( PDEVNODE pdn, LPSTR HardwareKey, ULONG ulFlags ) { return CM_Locate_DevNode( pdn, HardwareKey, 0 ); } WORD WINAPI __export CIM16_CM_Get_Parent( PDEVNODE pdn, DEVNODE dnChild, ULONG ulFlags ) { return CM_Get_Parent( pdn, dnChild, 0 ); } WORD WINAPI __export CIM16_CM_Get_Child( PDEVNODE pdn, DEVNODE dnParent, ULONG ulFlags ) { return CM_Get_Child( pdn, dnParent, 0 ); } WORD WINAPI __export CIM16_CM_Get_Sibling( PDEVNODE pdn, DEVNODE dnParent, ULONG ulFlags ) { return CM_Get_Sibling( pdn, dnParent, 0 ); } WORD WINAPI __export CIM16_CM_Read_Registry_Value( DEVNODE dnDevNode, LPSTR pszSubKey, LPSTR pszValueName, ULONG ulExpectedType, LPVOID Buffer, LPULONG pulLength, ULONG ulFlags ) { return CM_Read_Registry_Value( dnDevNode, pszSubKey, pszValueName, ulExpectedType, Buffer, pulLength, ulFlags ); } WORD WINAPI __export CIM16_CM_Get_DevNode_Status( LPULONG pulStatus, LPULONG pulProblemNumber, DEVNODE dnDevNode, ULONG ulFlags ) { return CM_Get_DevNode_Status( pulStatus, pulProblemNumber, dnDevNode, ulFlags ); } WORD WINAPI __export CIM16_CM_Get_Device_ID( DEVNODE dnDevNode, LPVOID Buffer, ULONG BufferLen, ULONG ulFlags ) { return CM_Get_Device_ID( dnDevNode, Buffer, BufferLen, ulFlags ); } WORD WINAPI __export CIM16_CM_Get_Device_ID_Size( LPULONG pulLen, DEVNODE dnDevNode, ULONG ulFlags ) { return CM_Get_Device_ID_Size( pulLen, dnDevNode, ulFlags ); } WORD WINAPI __export CIM16_CM_Get_First_Log_Conf( PLOG_CONF plcLogConf, DEVNODE dnDevNode, ULONG ulFlags ) { return CM_Get_First_Log_Conf( plcLogConf, dnDevNode, ulFlags ); } WORD WINAPI __export CIM16_CM_Get_Next_Res_Des( PRES_DES prdResDes, RES_DES rdResDes, RESOURCEID ForResource, PRESOURCEID pResourceID, ULONG ulFlags ) { return CM_Get_Next_Res_Des( prdResDes, rdResDes, ForResource, pResourceID, ulFlags ); } WORD WINAPI __export CIM16_CM_Get_Res_Des_Data_Size( LPULONG pulSize, RES_DES rdResDes, ULONG ulFlags ) { return CM_Get_Res_Des_Data_Size( pulSize, rdResDes, ulFlags ); } WORD WINAPI __export CIM16_CM_Get_Res_Des_Data( RES_DES rdResDes, LPVOID Buffer, ULONG BufferLen, ULONG ulFlags ) { return CM_Get_Res_Des_Data( rdResDes, Buffer, BufferLen, ulFlags ); } WORD WINAPI __export CIM16_CM_Get_Bus_Info(DEVNODE dnDevNode, PCMBUSTYPE pbtBusType, LPULONG pulSizeOfInfo, LPVOID pInfo, ULONG ulFlags) { return CM_Get_Bus_Info( dnDevNode, pbtBusType, pulSizeOfInfo, pInfo, ulFlags ); } WORD WINAPI __export CIM16_CM_Query_Arbitrator_Free_Data(LPVOID pData, ULONG DataLen, DEVNODE dnDevInst, RESOURCEID ResourceID, ULONG ulFlags) { return CM_Query_Arbitrator_Free_Data(pData, DataLen, dnDevInst, ResourceID, ulFlags); } WORD WINAPI __export CIM16_CM_Delete_Range(ULONG ulStartValue, ULONG ulEndValue, RANGE_LIST rlh, ULONG ulFlags) { return CM_Delete_Range(ulStartValue, ulEndValue, rlh, ulFlags); } WORD WINAPI __export CIM16_CM_First_Range(RANGE_LIST rlh, LPULONG pulStart, LPULONG pulEnd, PRANGE_ELEMENT preElement, ULONG ulFlags) { return CM_First_Range(rlh, pulStart, pulEnd, preElement, ulFlags); } WORD WINAPI __export CIM16_CM_Next_Range(PRANGE_ELEMENT preElement, LPULONG pulStart, LPULONG pullEnd, ULONG ulFlags) { return CM_Next_Range(preElement, pulStart, pullEnd, ulFlags); } WORD WINAPI __export CIM16_CM_Free_Range_List(RANGE_LIST rlh, ULONG ulFlags) { return CM_Free_Range_List(rlh, ulFlags); } // Use int13 to read drive parameters BYTE FAR PASCAL __export CIM16GetDriveParams (BYTE bDrive, pInt13DriveParams pParams) { typedef struct { WORD wInfo_size; WORD wFlags; // information flags DWORD dwCylinders; // number of cylinders on disk DWORD dwHeads; // number of heads on disk DWORD dwSec_per_track; // number of sectors per track DWORD dwSectors[2]; // number of sectors on requested disk WORD sector_size; // number of bytes per sector } stGetDriveParmsEx, *pstGetDriveParmsEx; BYTE cResult; RMCS callStruct; DWORD gdaBuffer; // Return value of GlobalDosAlloc(). LPBYTE RMlpBuffer; // Real-mode buffer pointer LPBYTE PMlpBuffer; // Protected-mode buffer pointer BOOL bFound; pstGetDriveParmsEx pExParams; memset(pParams, 0, sizeof(Int13DriveParams)); /* Validate params: bDrive should be int 13h device unit -- let the BIOS validate this parameter -- user could have a special controller with its own BIOS. */ if (pParams == NULL) return 0xee; bFound = FALSE; /* Initialize the real-mode call structure and set all values needed to read the first sector of the specified physical drive. */ BuildRMCS (&callStruct); // First let's see if we can use extended int13 stuff callStruct.eax = 0x4100; // GET DRIVE PARAMETERS callStruct.ebx = 0; callStruct.edx = MAKEWORD(bDrive, 0); // Drive # pParams->wExtStep = 1; if (SimulateRM_Int (0x13, &callStruct) && // Did the DPMI call succeed? (!(callStruct.wFlags & CARRY_FLAG)) && // Did the int13 call succeed? (callStruct.ebx == 0xaa55) && // Did it set the signature for int13 extensions? (callStruct.ecx & 1)) // Does the extended int13 support the api we need? { pParams->wExtStep = 2; // Yes, we can use extended int13. Now, let's set up to do so. First allocate some // memory that can be accessed from real mode gdaBuffer = GlobalDosAlloc (sizeof(stGetDriveParmsEx)); if (!gdaBuffer) return 0xee; // Next, make a real mode and protected mode pointer to this memory RMlpBuffer = (LPBYTE)MAKELONG(0, HIWORD(gdaBuffer)); PMlpBuffer = (LPBYTE)MAKELONG(0, LOWORD(gdaBuffer)); // Now, we need to set a data member in that memory block to the size of the memory block pExParams = (pstGetDriveParmsEx) PMlpBuffer; pExParams->wInfo_size = sizeof(stGetDriveParmsEx); callStruct.eax = 0x4800; // Extended GET DRIVE PARAMETERS callStruct.edx = MAKEWORD(bDrive, 0); // Drive # callStruct.esi = LOWORD(RMlpBuffer); // Offset of sector buffer callStruct.ds = HIWORD(RMlpBuffer); // Segment of sector buffer if (SimulateRM_Int (0x13, &callStruct) && // Did the DPMI call succeed? (!(callStruct.wFlags & CARRY_FLAG)) // Did the int13 call succeed? // Actually, experience shows that this seems to indicate whether the NON-extended // call returns the correct information. // (pExParams->wFlags & 2) // Did the CHS stuff get populated? ) { pParams->wExtStep = 3; // Cylinder and head are returned from the interrupt zero based, sector is returned one based cResult = (BYTE)((callStruct.eax >> 8) & 0xff); pParams->dwMaxCylinder = pExParams->dwCylinders; pParams->dwMaxSector = pExParams->dwSec_per_track; pParams->dwMaxHead = pExParams->dwHeads; pParams->wSectorSize = pExParams->sector_size; pParams->wFlags = pExParams->wFlags; pParams->dwSectors[0] = pExParams->dwSectors[0]; pParams->dwSectors[0] = pExParams->dwSectors[0]; bFound = TRUE; } // Free the sector data buffer this function allocated GlobalDosFree (LOWORD(gdaBuffer)); } if (!bFound) { // No extended int13. Take what we can get callStruct.eax = 0x0800; // GET DRIVE PARAMETERS callStruct.edx = MAKEWORD(bDrive, 0); // Drive # /* Call Int 13h BIOS and check both the DPMI call itself and the BIOS function result for success. */ if (SimulateRM_Int (0x13, &callStruct)) // Did the DPMI call succeed? { if (!(callStruct.wFlags & CARRY_FLAG)) { // It might also be necessary to make sure that bDrive <= DL after the call is made. // Cylinder and head are returned from the interrupt zero based, sector is returned one based cResult = (BYTE)((callStruct.eax >> 8) & 0xff); pParams->dwMaxCylinder = (WORD)(((callStruct.ecx & 0xff00) >> 8) | ((callStruct.ecx & 0xc0) << 2)) + 1; pParams->dwMaxSector = (WORD)(callStruct.ecx & 0x3f); pParams->dwMaxHead = (WORD)((callStruct.edx & 0xff00) >> 8)+1; pParams->wSectorSize = SECTOR_SIZE; } else { cResult = (BYTE)((callStruct.eax >> 8) & 0xff); } } else { cResult = 0xef; } } return cResult; } // This routine (and the dpmi routines below) shamelessly stolen from Q137176 // It will read the MasterBootSector and return it. BYTE FAR PASCAL __export CIM16GetDrivePartitions (BYTE bDrive, pMasterBootSector pMBS) { BYTE cResult; RMCS callStruct; DWORD gdaBuffer; // Return value of GlobalDosAlloc(). LPBYTE RMlpBuffer; // Real-mode buffer pointer LPBYTE PMlpBuffer; // Protected-mode buffer pointer /* Validate params: bDrive should be int 13h device unit -- let the BIOS validate this parameter -- user could have a special controller with its own BIOS. pMBS must not be NULL */ if (pMBS == NULL) return 0xee; /* Allocate the buffer that the Int 13h function will put the sector data into. As this function uses DPMI to call the real-mode BIOS, it must allocate the buffer below 1 MB, and must use a real-mode paragraph-segment address. After the memory has been allocated, create real-mode and protected-mode pointers to the buffer. The real-mode pointer will be used by the BIOS, and the protected-mode pointer will be used by this function because it resides in a Windows 16-bit DLL, which runs in protected mode. */ gdaBuffer = GlobalDosAlloc (sizeof(MasterBootSector)); if (!gdaBuffer) return 0xee; RMlpBuffer = (LPBYTE)MAKELONG(0, HIWORD(gdaBuffer)); PMlpBuffer = (LPBYTE)MAKELONG(0, LOWORD(gdaBuffer)); /* Initialize the real-mode call structure and set all values needed to read the first sector of the specified physical drive. */ BuildRMCS (&callStruct); callStruct.eax = 0x0201; // BIOS read, 1 sector callStruct.ecx = 0x0001; // Sector 1, Cylinder 0 callStruct.edx = MAKEWORD(bDrive, 0); // Head 0, Drive # callStruct.ebx = LOWORD(RMlpBuffer); // Offset of sector buffer callStruct.es = HIWORD(RMlpBuffer); // Segment of sector buffer /* Call Int 13h BIOS Read Track and check both the DPMI call itself and the BIOS Read Track function result for success. If successful, copy the sector data retrieved by the BIOS into the caller's buffer. */ if (SimulateRM_Int (0x13, &callStruct)) { if (!(callStruct.wFlags & CARRY_FLAG)) { _fmemcpy (pMBS, PMlpBuffer, (size_t)sizeof(MasterBootSector)); cResult = (BYTE)((callStruct.eax >> 8) & 0xff); } else { cResult = (BYTE)((callStruct.eax >> 8) & 0xff); } } else { cResult = 0xef; } // Free the sector data buffer this function allocated GlobalDosFree (LOWORD(gdaBuffer)); return cResult; } /*-------------------------------------------------------------------- SimulateRM_Int() Allows protected mode software to execute real mode interrupts such as calls to DOS TSRs, DOS device drivers, etc. This function implements the "Simulate Real Mode Interrupt" function of the DPMI specification v0.9. Parameters bIntNum Number of the interrupt to simulate lpCallStruct Call structure that contains params (register values) for bIntNum. Return Value SimulateRM_Int returns TRUE if it succeeded or FALSE if it failed. Comments lpCallStruct is a protected-mode selector:offset address, not a real-mode segment:offset address. --------------------------------------------------------------------*/ BOOL FAR PASCAL SimulateRM_Int (BYTE bIntNum, LPRMCS lpCallStruct) { BOOL fRetVal = FALSE; // Assume failure _asm { push di mov ax, 0300h ; DPMI Simulate Real Mode Int mov bl, bIntNum ; Number of the interrupt to simulate mov bh, 01h ; Bit 0 = 1; all other bits must be 0 xor cx, cx ; No words to copy les di, lpCallStruct int 31h ; Call DPMI jc END1 ; CF set if error occurred mov fRetVal, TRUE END1: pop di } return (fRetVal); } /*-------------------------------------------------------------------- BuildRMCS() Initializes a real mode call structure to contain zeros in all its members. Parameters: lpCallStruct Points to a real mode call structure Comments: lpCallStruct is a protected-mode selector:offset address, not a real-mode segment:offset address. --------------------------------------------------------------------*/ void FAR PASCAL BuildRMCS (LPRMCS lpCallStruct) { _fmemset (lpCallStruct, 0, sizeof (RMCS)); } WORD WINAPI __export CIM16GetBiosUnit(LPSTR lpDeviceID) { WORD btAddress[2]; WORD wRetVal, wSeg = HIWORD(lpDeviceID), wOffset = LOWORD(lpDeviceID); _asm { PUSH BX PUSH DI PUSH ES // Get the pointer to IOS MOV AX,0x1684 // Get VXD Entry Point MOV BX,0x0010 // for IOS service MOV DI,0x0000 // Empty register MOV ES,DI // Empty register INT 0x2F // Check to make sure it worked. Result returned in es:di MOV AX,ES OR AX,0x0000 JE failed // Move it to a memory location to allow for the indirect call MOV [btAddress],DI MOV [btAddress + 2],ES // Set up to call ios. Parameters are as follows: /* (from Bill Parry) It is added as a VxD PM usermode API. David, you need to find out how to call VxD PM API's from your app, as I've never done this and don't remember the details of how it works. I do recall that you can either reference the VxD by name or device ID. To call the function, you need to use vxd name "IOS" (or use IOS_DEVICE_ID from IOS.H), and pass in: AX = 7 ES:BX -> PNP ID string to compare, null terminated. If the API succeeds, it returns clear carry and DL = INT 13 unit # if the device is an int 13 device, or DL = -1 if not. If the API fails, carry is set upon return and DL is undefined. */ MOV AX,0x0007 LEA DI,btAddress MOV BX,wSeg MOV ES,BX MOV BX,wOffset MOV DL,0xff CALL DWORD PTR ss:[di] // Value comes back in dl MOV AH,0 MOV AL,DL JNC done // We either jump here on failure, or fall through from lack of success failed: MOV AX,0xffff done: MOV wRetVal, AX POP ES POP DI POP BX } return wRetVal; } DWORD WINAPI __export CIM16GetFreeSpace ( UINT option ) { return GetFreeSpace ( option ) ; } /////////////////////////////////////////////////////////////////////// // // This is required to setup the thunking to the 32 bit dll // /////////////////////////////////////////////////////////////////////// BOOL FAR PASCAL __export DllEntryPoint (DWORD dwReason, WORD hInst, WORD wDS, WORD wHeapSize, DWORD dwReserved1, WORD wReserved2) { if (!win32thk_ThunkConnect16(CIM16NET_DLL, CIM32NET_DLL, hInst, dwReason)) return FALSE; return TRUE; }