CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7
  1. #1
    Join Date
    Jan 2001
    Location
    Oregon, USA
    Posts
    8

    Unique ID of a computer

    Is their a unique identification number associated with each computer?

    I know that each network controller has a unique ID number programmed in to it that is used to generate GUID numbers. Does anyone know how to obtain the network controller ID number through software? or better yet, a unique number that identifies a computer even if it doesn't have a network controller?

    Thanks in advance for any help.
    Dave


  2. #2
    Join Date
    Aug 2000
    Posts
    124

    Re: Unique ID of a computer


  3. #3
    Join Date
    Aug 1999
    Location
    Canada
    Posts
    2,076

    Re: Unique ID of a computer

    Previous post is O.K, but it works only on IDE devices with S.M.A.R.T support. Better solution is read CPU serial number or BIOS serial number. For example. Take a look to WMI ( or SMBIOS, DMI....) in MSDN.

    Here are some links.
    http://msdn.microsoft.com/library/pe...riod00/wmi.htm

    WMI is supported on WIN98 and 2000, if you need help with SMBIOS( or DMI ) implementation on WIN95 or NT , let me know.

    Here you can find SMBIOS specification:

    http://www.intel.com/ial/WfM/wfm20/design/smbios/

    In case of CPU serial number you can check this site:

    http://support.intel.com/support/pro...d/24161812.htm

    But there is small problem in implementation, it can be disabled in CMOS setup.

    Good luck


  4. #4
    Join Date
    May 2000
    Location
    Lancashire, England
    Posts
    42

    Re: Unique ID of a computer


    //Unique PCID.h
    #include "smart.h"
    struct SPentiumIIISerialNumber
    {
    DWORD high;
    DWORD middle;
    DWORD low;
    };

    class CUniquePCID
    {
    public:

    //returns the MAC address of the FIRST network card in the PC
    bool GetMACAddress(__int64 & iMACAddress);

    //returns 0 if disabled
    bool CPUID(SPentiumIIISerialNumber & serialnumber) const;

    //returns serial # of drive C - 0 indicates no drive C
    //this function returns the number, as C: should always be there!
    DWORD HardDiskVolume() const {return m_dwHD;}

    bool GetIDESerialNo(CString & csSerialNumber,CString & csError);



    CUniquePCID();
    virtual ~CUniquePCID();

    private:
    DWORD m_dwHD;

    //returns 0, and gives error message if fails
    HANDLE OpenSMART(CString & csError,bool bWindows9X = true);//not entirerly sure that it works under NT - but worth a try!

    bool DoEnableSMART(HANDLE hSMARTIOCTL, PSENDCMDINPARAMS pSCIP, PSENDCMDOUTPARAMS pSCOP, BYTE bDriveNum, PDWORD lpcbBytesReturned);
    bool DoIDENTIFY(HANDLE hSMARTIOCTL, PSENDCMDINPARAMS pSCIP,PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum, PDWORD lpcbBytesReturned);
    void ChangeByteOrder(PCHAR szString, USHORT uscStrSize);



    };


    //smart.h
    /****************************************************************************
    * *
    * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY *
    * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE *
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR *
    * PURPOSE. *
    * *
    * Copyright 1993-98 Microsoft Corporation. All Rights Reserved. *
    * *
    ****************************************************************************/

    /****************************************************************************
    *
    * PROGRAM: SMART.H
    *
    * PURPOSE: Structure definitions for an application that calls SMART Ioctls
    *
    ****************************************************************************/

    #ifndef SMARTIOCTL_INCLUDED
    #define SMARTIOCTL_INCLUDED

    // Miscellaneous

    #define MAX_IDE_DRIVES 4 // Max number of drives assuming primary/secondary, master/slave topology
    #define READ_ATTRIBUTE_BUFFER_SIZE 512
    #define IDENTIFY_BUFFER_SIZE 512
    #define READ_THRESHOLD_BUFFER_SIZE 512

    //
    // IOCTL commands
    //
    #define DFP_GET_VERSION 0x00074080
    #define DFP_SEND_DRIVE_COMMAND 0x0007c084
    #define DFP_RECEIVE_DRIVE_DATA 0x0007c088

    //---------------------------------------------------------------------
    // GETVERSIONOUTPARAMS contains the data returned from the
    // Get Driver Version function.
    //---------------------------------------------------------------------
    typedef struct _GETVERSIONOUTPARAMS {
    BYTE bVersion; // Binary driver version.
    BYTE bRevision; // Binary driver revision.
    BYTE bReserved; // Not used.
    BYTE bIDEDeviceMap; // Bit map of IDE devices.
    DWORD fCapabilities; // Bit mask of driver capabilities.
    DWORD dwReserved[4]; // For future use.
    } GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS;

    //
    // Bits returned in the fCapabilities member of GETVERSIONOUTPARAMS
    //
    #define CAP_IDE_ID_FUNCTION 1 // ATA ID command supported
    #define CAP_IDE_ATAPI_ID 2 // ATAPI ID command supported
    #define CAP_IDE_EXECUTE_SMART_FUNCTION 4 // SMART commannds supported

    //---------------------------------------------------------------------
    // IDE registers
    //---------------------------------------------------------------------
    typedef struct _IDEREGS {
    BYTE bFeaturesReg; // Used for specifying SMART "commands".
    BYTE bSectorCountReg; // IDE sector count register
    BYTE bSectorNumberReg; // IDE sector number register
    BYTE bCylLowReg; // IDE low order cylinder value
    BYTE bCylHighReg; // IDE high order cylinder value
    BYTE bDriveHeadReg; // IDE drive/head register
    BYTE bCommandReg; // Actual IDE command.
    BYTE bReserved; // reserved for future use. Must be zero.
    } IDEREGS, *PIDEREGS, *LPIDEREGS;

    //---------------------------------------------------------------------
    // SENDCMDINPARAMS contains the input parameters for the
    // Send Command to Drive function.
    //---------------------------------------------------------------------
    typedef struct _SENDCMDINPARAMS {
    DWORD cBufferSize; // Buffer size in bytes
    IDEREGS irDriveRegs; // Structure with drive register values.
    BYTE bDriveNumber; // Physical drive number to send
    // command to (0,1,2,3).
    BYTE bReserved[3]; // Reserved for future expansion.
    DWORD dwReserved[4]; // For future use.
    BYTE bBuffer[1]; // Input buffer.
    } SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;

    //
    // Valid values for the bCommandReg member of IDEREGS.
    //
    #define IDE_ATAPI_ID 0xA1 // Returns ID sector for ATAPI.
    #define IDE_ID_FUNCTION 0xEC // Returns ID sector for ATA.
    #define IDE_EXECUTE_SMART_FUNCTION 0xB0 // Performs SMART cmd.
    // Requires valid bFeaturesReg,
    // bCylLowReg, and bCylHighReg
    //
    // Cylinder register values required when issuing SMART command
    //
    #define SMART_CYL_LOW 0x4F
    #define SMART_CYL_HI 0xC2

    //---------------------------------------------------------------------
    // Status returned from driver
    //---------------------------------------------------------------------
    typedef struct _DRIVERSTATUS {
    BYTE bDriverError; // Error code from driver,
    // or 0 if no error.
    BYTE bIDEStatus; // Contents of IDE Error register.
    // Only valid when bDriverError
    // is SMART_IDE_ERROR.
    BYTE bReserved[2]; // Reserved for future expansion.
    DWORD dwReserved[2]; // Reserved for future expansion.
    } DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;

    //
    // bDriverError values
    //
    #define SMART_NO_ERROR 0 // No error
    #define SMART_IDE_ERROR 1 // Error from IDE controller
    #define SMART_INVALID_FLAG 2 // Invalid command flag
    #define SMART_INVALID_COMMAND 3 // Invalid command byte
    #define SMART_INVALID_BUFFER 4 // Bad buffer (null, invalid addr..)
    #define SMART_INVALID_DRIVE 5 // Drive number not valid
    #define SMART_INVALID_IOCTL 6 // Invalid IOCTL
    #define SMART_ERROR_NO_MEM 7 // Could not lock user's buffer
    #define SMART_INVALID_REGISTER 8 // Some IDE Register not valid
    #define SMART_NOT_SUPPORTED 9 // Invalid cmd flag set
    #define SMART_NO_IDE_DEVICE 10 // Cmd issued to device not present
    // although drive number is valid
    // 11-255 reserved

    //---------------------------------------------------------------------
    // Structure returned by SMART IOCTL for several commands
    //---------------------------------------------------------------------
    typedef struct _SENDCMDOUTPARAMS {
    DWORD cBufferSize; // Size of bBuffer in bytes
    DRIVERSTATUS DriverStatus; // Driver status structure.
    char bBuffer[1]; // Buffer of arbitrary length in which to store the data read from the // drive.
    } SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;


    //---------------------------------------------------------------------
    // Feature register defines for SMART "sub commands"
    //---------------------------------------------------------------------
    #define SMART_READ_ATTRIBUTE_VALUES 0xD0 // ATA4: Renamed
    // SMART READ DATA
    #define SMART_READ_ATTRIBUTE_THRESHOLDS 0xD1 // Obsoleted in ATA4!
    #define SMART_ENABLE_DISABLE_ATTRIBUTE_AUTOSAVE 0xD2
    #define SMART_SAVE_ATTRIBUTE_VALUES 0xD3
    #define SMART_EXECUTE_OFFLINE_IMMEDIATE 0xD4 // ATA4
    // Vendor specific commands:
    #define SMART_ENABLE_SMART_OPERATIONS 0xD8
    #define SMART_DISABLE_SMART_OPERATIONS 0xD9
    #define SMART_RETURN_SMART_STATUS 0xDA

    #endif

    //---------------------------------------------------------------------
    // The following structure defines the structure of a Drive Attribute
    //---------------------------------------------------------------------
    typedef struct _DRIVEATTRIBUTE {
    BYTE bAttrID; // Identifies which attribute
    WORD wStatusFlags; // see bit definitions below
    BYTE bAttrValue; // Current normalized value
    BYTE bWorstValue; // How bad has it ever been?
    BYTE bRawValue[6]; // Un-normalized value
    BYTE bReserved; // ...
    } DRIVEATTRIBUTE, *PDRIVEATTRIBUTE, *LPDRIVEATTRIBUTE;

    //---------------------------------------------------------------------
    // The following structure defines the structure of a Warranty Threshold
    // Obsoleted in ATA4!
    //---------------------------------------------------------------------
    typedef struct _ATTRTHRESHOLD {
    BYTE bAttrID; // Identifies which attribute
    BYTE bWarrantyThreshold; // Triggering value
    BYTE bReserved[10]; // ...
    } ATTRTHRESHOLD, *PATTRTHRESHOLD, *LPATTRTHRESHOLD;

    //---------------------------------------------------------------------
    // The following struct defines the interesting part of the IDENTIFY
    // buffer:
    //---------------------------------------------------------------------
    typedef struct _IDSECTOR {
    USHORT wGenConfig;
    USHORT wNumCyls;
    USHORT wReserved;
    USHORT wNumHeads;
    USHORT wBytesPerTrack;
    USHORT wBytesPerSector;
    USHORT wSectorsPerTrack;
    USHORT wVendorUnique[3];
    CHAR szSerialNumber[20];
    USHORT wBufferType;
    USHORT wBufferSize;
    USHORT wECCSize;
    CHAR sFirmwareRev[8];
    CHAR sModelNumber[40];
    USHORT wMoreVendorUnique;
    USHORT wDoubleWordIO;
    USHORT wCapabilities;
    USHORT wReserved1;
    USHORT wPIOTiming;
    USHORT wDMATiming;
    USHORT wBS;
    USHORT wNumCurrentCyls;
    USHORT wNumCurrentHeads;
    USHORT wNumCurrentSectorsPerTrack;
    ULONG ulCurrentSectorCapacity;
    USHORT wMultSectorStuff;
    ULONG ulTotalAddressableSectors;
    USHORT wSingleWordDMA;
    USHORT wMultiWordDMA;
    BYTE bReserved[128];
    } IDSECTOR, *PIDSECTOR;

    //---------------------------------------------------------------------
    // Valid Attribute IDs
    //---------------------------------------------------------------------
    #define ATTR_INVALID 0
    #define ATTR_READ_ERROR_RATE 1
    #define ATTR_THROUGHPUT_PERF 2
    #define ATTR_SPIN_UP_TIME 3
    #define ATTR_START_STOP_COUNT 4
    #define ATTR_REALLOC_SECTOR_COUNT 5
    #define ATTR_READ_CHANNEL_MARGIN 6
    #define ATTR_SEEK_ERROR_RATE 7
    #define ATTR_SEEK_TIME_PERF 8
    #define ATTR_POWER_ON_HRS_COUNT 9
    #define ATTR_SPIN_RETRY_COUNT 10
    #define ATTR_CALIBRATION_RETRY_COUNT 11
    #define ATTR_POWER_CYCLE_COUNT 12

    //---------------------------------------------------------------------
    // Status Flags Values
    //---------------------------------------------------------------------
    #define PRE_FAILURE_WARRANTY 0x1
    #define ON_LINE_COLLECTION 0x2
    #define PERFORMANCE_ATTRIBUTE 0x4
    #define ERROR_RATE_ATTRIBUTE 0x8
    #define EVENT_COUNT_ATTRIBUTE 0x10
    #define SELF_PRESERVING_ATTRIBUTE 0x20

    #define NUM_ATTRIBUTE_STRUCTS 30



    //uniquepcid.cpp
    #pragma pack(1) // Required to ensure correct SMART IOCTL structure setup
    #include "UniquePCID.h"
    #include "nb30.h"
    #include "winosver.h"

    #ifdef _DEBUG
    #undef THIS_FILE
    static char THIS_FILE[]=__FILE__;
    #define new DEBUG_NEW
    #endif





    //////////////////////////////////////////////////////////////////////
    // Construction/Destruction
    //////////////////////////////////////////////////////////////////////
    // http://support.microsoft.com/support.../Q208/0/48.ASP
    CUniquePCID::CUniquePCID()
    {

    UINT uiOldMode = SetErrorMode(SEM_FAILCRITICALERRORS);

    //collect the drive volume info on construction, as it doesn't take long.
    //the other calls are more likely to fail and/or take longer to calculate

    if (!GetVolumeInformation("C:\\",0,0,&m_dwHD,0,0,0,0))
    {
    m_dwHD = 0;
    }

    SetErrorMode(uiOldMode);


    }

    CUniquePCID::~CUniquePCID()
    {

    }

    bool CUniquePCID::CPUID(SPentiumIIISerialNumber & serialnumber) const
    {


    SPentiumIIISerialNumber * pSerialNumber = &serialnumber;

    serialnumber.high = 0;
    serialnumber.middle = 0;
    serialnumber.low = 0;




    BOOL bGotSerialNumber = FALSE;
    BOOL bSupportsCpuID = FALSE;



    __asm
    {
    //
    // The CPUID instruction is supported only if bit 21 of
    // EFLAGS can be changed.
    //
    pushfd
    pop eax // get current EFLAGS

    mov ecx, eax
    xor eax, 200000h // toggle bit 21

    push eax
    popfd // set new EFLAGS

    pushfd
    pop eax // retrieve EFLAGS again

    xor eax, ecx // did bit 21 change?
    jz restore_eflags // no, CPUID not supported
    mov dword ptr [bSupportsCpuID], TRUE

    restore_eflags:
    push ecx
    popfd // restore original EFLAGS

    cmp dword ptr [bSupportsCpuID], FALSE
    jz exit_function

    //
    // CPUID uses the value in EAX to determine what info to
    // return. When EAX is 0 on input, CPUID returns the
    // highest value allowed for EAX. The return value _must_
    // be >= 3, or the serial number is not supported.
    //
    mov eax, 0
    cpuid
    cmp eax, 3 // function "3" supported?
    jl exit_function // no, there's no serial #

    //
    // Check bit 18 of the processor "feature flags" to
    // determine if the processor serial number is available
    // and enabled. The "feature flags" are returned in EDX
    // after executing CPUID with EAX=1.
    //
    mov eax, 1
    cpuid
    test edx, 40000h // is bit 18 set?
    jz exit_function // no, serial # disabled
    // or not available
    //
    // 96-bit processor serial number is available:
    // high 32 bits are in EAX after CPUID with EAX=1
    // middle 32 bits are in EDX after CPUID with EAX=3
    // low 32 bits are in ECX after CPUID with EAX=3
    //
    mov edi, dword ptr [pSerialNumber]
    mov dword ptr [edi.high], eax

    mov eax, 3
    cpuid
    mov dword ptr [edi.middle], edx
    mov dword ptr [edi.low], ecx
    mov dword ptr [bGotSerialNumber], TRUE
    }
    exit_function:




    return bGotSerialNumber;
    }


    bool CUniquePCID::GetMACAddress(__int64 & iMACAddress)
    {
    bool bResult = false;

    struct ASTAT
    {

    ADAPTER_STATUS adapt;
    NAME_BUFFER NameBuff [30];
    };

    ASTAT Adapter;


    //firstly enumerate all the network cards
    //not good to just assume that one is there
    NCB Ncb;
    UCHAR uRetCode;

    LANA_ENUM lenum;

    memset( &Ncb, 0, sizeof(Ncb) );
    Ncb.ncb_command = NCBENUM;
    Ncb.ncb_buffer = (UCHAR *)&lenum;
    Ncb.ncb_length = sizeof(lenum);
    uRetCode = Netbios( &Ncb );


    if (uRetCode == 0)
    {

    //reset the card - don't fret you won't lose network traffic!
    memset( &Ncb, 0, sizeof(Ncb) );
    Ncb.ncb_command = NCBRESET;
    Ncb.ncb_lana_num = lenum.lana[0];

    uRetCode = Netbios( &Ncb );


    //getnet card status

    memset( &Ncb, 0, sizeof (Ncb) );
    Ncb.ncb_command = NCBASTAT;
    Ncb.ncb_lana_num = lenum.lana[0];

    strcpy( (char*)Ncb.ncb_callname, "* " );
    (Ncb.ncb_buffer) = (PUCHAR)&Adapter;
    Ncb.ncb_length = sizeof(Adapter);

    uRetCode = Netbios( &Ncb );

    if ( uRetCode == 0 )
    {

    for (int i = 0;i<6; i++)
    {
    __int64 iCurVal = Adapter.adapt.adapter_address[i];

    iCurVal = iCurVal * pow(0x100 , 5-i);
    iMACAddress += iCurVal;
    }

    bResult = true;

    }

    }

    return bResult;

    }







    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


    bool CUniquePCID::GetIDESerialNo(CString & csSerialNumber,CString & csError)
    {
    bool bResult = false;
    SENDCMDINPARAMS scip;
    SENDCMDOUTPARAMS OutCmd;
    BYTE byDfpDriveMap = 0;
    BYTE byIDCmd;
    DWORD cbBytesReturned;
    BYTE IdOutCmd[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];

    CWinOSVer osversion;

    bool bWindows9x = !osversion.WinNT();
    HANDLE hSMARTIOCtrl = OpenSMART(csError,bWindows9x);

    #ifdef _DEBUG
    if (!hSMARTIOCtrl)
    {
    AfxMessageBox(csError,MB_OK);
    }
    #endif


    if (hSMARTIOCtrl)
    {
    GETVERSIONOUTPARAMS VersionParams;
    memset(&VersionParams, 0, sizeof(VersionParams));

    if ( DeviceIoControl(hSMARTIOCtrl, DFP_GET_VERSION,
    NULL,
    0,
    &VersionParams,
    sizeof(VersionParams),
    &cbBytesReturned, NULL) )
    {

    for (BYTE i = 0; i < MAX_IDE_DRIVES; i++)
    {
    //
    // If there is a IDE device at number "i" issue commands
    // to the device.
    if (VersionParams.bIDEDeviceMap >> i & 1)
    {
    // Try to enable SMART so we can tell if a drive supports it.
    // Ignore ATAPI devices.
    //

    if (!(VersionParams.bIDEDeviceMap >> i & 0x10))
    {
    memset(&scip, 0, sizeof(scip));
    memset(&OutCmd, 0, sizeof(OutCmd));

    if (DoEnableSMART(hSMARTIOCtrl, &scip, &OutCmd, i, &cbBytesReturned))
    {

    // Mark the drive as SMART enabled
    byDfpDriveMap |= (1 << i);
    //Not needed in this app - but may be usefull to have a list of drives later on...
    }
    }

    }

    // Now, get the ID sector for all IDE devices in the system.
    // If the device is ATAPI use the IDE_ATAPI_ID command,
    // otherwise use the IDE_ID_FUNCTION command.
    byIDCmd = (VersionParams.bIDEDeviceMap >> i & 0x10) ? IDE_ATAPI_ID : IDE_ID_FUNCTION;


    memset(&scip, 0, sizeof(scip));
    memset(IdOutCmd, 0,sizeof(IdOutCmd) );


    if ( DoIDENTIFY(hSMARTIOCtrl, &scip, (PSENDCMDOUTPARAMS)&IdOutCmd, byIDCmd, i, &cbBytesReturned))
    {

    PIDSECTOR pIDS = (PIDSECTOR) ((PSENDCMDOUTPARAMS)IdOutCmd)->bBuffer;

    //change word array to byte array
    ChangeByteOrder(pIDS->szSerialNumber,sizeof pIDS->szSerialNumber);

    char szTempSerialNo[41];

    memset(szTempSerialNo,0, sizeof(szTempSerialNo));

    strncpy(szTempSerialNo,pIDS->szSerialNumber,sizeof(pIDS->szSerialNumber));
    csSerialNumber = szTempSerialNo;

    bResult = true;
    }


    }



    }
    else
    {
    csError = "DFP_GET_VERSION failed";
    }


    }


    if (hSMARTIOCtrl)
    {
    CloseHandle(hSMARTIOCtrl);
    hSMARTIOCtrl = 0;
    }


    return bResult;
    }




    void CUniquePCID::ChangeByteOrder(PCHAR szString, USHORT uscStrSize)
    {
    USHORT i;
    CHAR temp;

    for (i = 0; i < uscStrSize; i+=2)
    {
    temp = szString[i];
    szString[i] = szString[i+1];
    szString[i+1] = temp;
    }
    }

    HANDLE CUniquePCID::OpenSMART(CString & csError,bool bWindows9X)
    {
    HANDLE hSMARTIOCTL = 0;

    if (bWindows9X)
    {
    hSMARTIOCTL = CreateFile("\\\\.\\SMARTVSD", 0,0,0,CREATE_NEW, 0, 0);
    // Version Windows 95 OSR2, Windows 98
    if (hSMARTIOCTL == INVALID_HANDLE_VALUE)
    {
    csError.Format("Unable to open SMARTVSD, error code: 0x%lX\n", GetLastError());
    hSMARTIOCTL = 0;
    }
    }
    else
    {
    // Windows NT, Windows 2000
    hSMARTIOCTL = CreateFile("\\\\.\\PhysicalDrive0",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,
    OPEN_EXISTING,0,NULL);
    if ( hSMARTIOCTL == INVALID_HANDLE_VALUE)
    {
    csError.Format("Unable to open physical drive, error code: 0x%lX\n", GetLastError());
    hSMARTIOCTL = 0;
    }

    }

    return hSMARTIOCTL;

    }
    /****************************************************************************
    *
    * DoEnableSMART
    *
    * FUNCTION: Send a SMART_ENABLE_SMART_OPERATIONS command to the drive
    * bDriveNum = 0-3
    *
    ****************************************************************************/
    bool CUniquePCID:oEnableSMART(HANDLE hSMARTIOCTL, PSENDCMDINPARAMS pSCIP, PSENDCMDOUTPARAMS pSCOP, BYTE bDriveNum, PDWORD lpcbBytesReturned)
    {
    //
    // Set up data structures for Enable SMART Command.
    //
    pSCIP->cBufferSize = 0;

    pSCIP->irDriveRegs.bFeaturesReg = SMART_ENABLE_SMART_OPERATIONS;
    pSCIP->irDriveRegs.bSectorCountReg = 1;
    pSCIP->irDriveRegs.bSectorNumberReg = 1;
    pSCIP->irDriveRegs.bCylLowReg = SMART_CYL_LOW;
    pSCIP->irDriveRegs.bCylHighReg = SMART_CYL_HI;

    //
    // Compute the drive number.
    //
    pSCIP->irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4);
    pSCIP->irDriveRegs.bCommandReg = IDE_EXECUTE_SMART_FUNCTION;
    pSCIP->bDriveNumber = bDriveNum;


    bool bResult = ( DeviceIoControl(hSMARTIOCTL, DFP_SEND_DRIVE_COMMAND,
    (LPVOID)pSCIP, sizeof(SENDCMDINPARAMS) - 1,
    (LPVOID)pSCOP, sizeof(SENDCMDOUTPARAMS) - 1,
    lpcbBytesReturned, NULL) !=0 );



    return bResult;
    }
    /****************************************************************************
    *
    * DoIDENTIFY
    *
    * FUNCTION: Send an IDENTIFY command to the drive
    * bDriveNum = 0-3
    * bIDCmd = IDE_ID_FUNCTION or IDE_ATAPI_ID
    *
    ****************************************************************************/
    bool CUniquePCID:oIDENTIFY(HANDLE hSMARTIOCTL, PSENDCMDINPARAMS pSCIP,PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum, PDWORD lpcbBytesReturned)
    {
    //
    // Set up data structures for IDENTIFY command.
    //

    pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE;

    pSCIP->irDriveRegs.bFeaturesReg = 0;
    pSCIP->irDriveRegs.bSectorCountReg = 1;
    pSCIP->irDriveRegs.bSectorNumberReg = 1;
    pSCIP->irDriveRegs.bCylLowReg = 0;
    pSCIP->irDriveRegs.bCylHighReg = 0;

    //
    // Compute the drive number.
    //
    pSCIP->irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4);

    //
    // The command can either be IDE identify or ATAPI identify.
    //
    pSCIP->irDriveRegs.bCommandReg = bIDCmd;
    pSCIP->bDriveNumber = bDriveNum;
    pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE;


    bool bResult = ( DeviceIoControl(hSMARTIOCTL, DFP_RECEIVE_DRIVE_DATA,
    (LPVOID)pSCIP, sizeof(SENDCMDINPARAMS) - 1,
    (LPVOID)pSCOP, sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,
    lpcbBytesReturned, NULL) !=0);


    return bResult;
    }





    "Take a chance while you still got a choice"

  5. #5
    Join Date
    Aug 1999
    Location
    Canada
    Posts
    2,076

    Re: Unique ID of a computer

    The code create unique PC ID but, there are some limitations.


    CPUID
    works on all CPUs with CPUID instruction. But CPU serial number can be disabled in BIOS setup.


    HardDiskVolume
    This function read volume number of HDD. This number is generated during formatting. If you reformat disk, the number is changed

    GetIDESerialNo
    Works only on IDE drive with SMART support. It doesn't work correctly on WIN98(problem with SMARTVSD)

    GetMACAddress
    This is unique number for network card identification.


  6. #6
    Join Date
    May 2000
    Location
    Lancashire, England
    Posts
    42

    Re: Unique ID of a computer

    I agree you need a network card, and a PIII (with it switched on).

    The IDE id does work under 98 - smartvsd.vxd must be in the \windows\system\iosubsys directory, reboot after copying it there.

    Have a look at
    http://support.microsoft.com/support.../Q208/0/48.ASP



    "Take a chance while you still got a choice"

  7. #7
    Join Date
    Aug 1999
    Location
    Canada
    Posts
    2,076

    Re: Unique ID of a computer

    CPUID is implemented on all Pentiums( not only PIII), but it doesn't work properly on some PII processors although this option is turned on in BIOS.

    On WIN98 smartvsd.vxd( third party VxD is used) is missing, and if you copy this file to \windows\system\iosubsys directory, on some machines it doesn't works. I tested it on some laptops -> the same machine under WIN2000 works without any problem, on WIN 98 doesn't....






Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured