Full Version: Hardware ID
UtterAccess Discussion Forums > Microsoft® Access > Access Q and A
CyberCow
What is the most unique hardware ID obtainable from a PC with Access, and how is it obtained?

The object is to lock an Access application to ONE machine and one machine only.
Sethuhdiah
Why dont you just lock it to the pc's mac address?
Sethuhdiah
Hres an example of a vb6 program that obtains the mac address from the network card. I haven't tested it, so good luck.
r_cubed
Moo,

The Mac Address is (supposed) to be almost gauranteed to NOT be repeated for apprx 50 years (last I knew), so makes it PRETTY UNIQUE.

Here is some (Access) code that will get it for you .....

CODE
Private Const msMODULE_NAME As String = "CNetInfo"

''' declarations for MACAddress
Private Const errMemoryAllocFailed = 47900

Private Const NCBASTAT = &H33
Private Const NCBNAMSZ = 16
Private Const HEAP_ZERO_MEMORY = &H8
Private Const HEAP_GENERATE_EXCEPTIONS = &H4
Private Const NCBRESET = &H32

Private Type NCB
    ncb_command As Byte
    ncb_retcode As Byte
    ncb_lsn As Byte
    ncb_num As Byte
    ncb_buffer As Long
    ncb_length As Integer
    ncb_callname As String * NCBNAMSZ
    ncb_name As String * NCBNAMSZ
    ncb_rto As Byte
    ncb_sto As Byte
    ncb_post As Long
    ncb_lana_num As Byte
    ncb_cmd_cplt As Byte
    ncb_reserve(9) As Byte ' Reserved, must be 0
    ncb_event As Long
End Type
'
Private Type ADAPTER_STATUS
    adapter_address(5) As Byte
    rev_major As Byte
    reserved0 As Byte
    adapter_type As Byte
    rev_minor As Byte
    Duration As Integer
    frmr_recv As Integer
    frmr_xmit As Integer
    iframe_recv_err As Integer
    xmit_aborts As Integer
    xmit_success As Long
    recv_success As Long
    iframe_xmit_err As Integer
    recv_buff_unavail As Integer
    t1_timeouts As Integer
    ti_timeouts As Integer
    Reserved1 As Long
    free_ncbs As Integer
    max_cfg_ncbs As Integer
    max_ncbs As Integer
    xmit_buf_unavail As Integer
    max_dgram_size As Integer
    pending_sess As Integer
    max_cfg_sess As Integer
    max_sess As Integer
    max_sess_pkt_size As Integer
    name_count As Integer
End Type
'
Private Type NAME_BUFFER
     Name  As String * NCBNAMSZ
     name_num As Integer
     name_flags As Integer
End Type
'
Private Type ASTAT
     adapt As ADAPTER_STATUS
     NameBuff(30) As NAME_BUFFER
End Type
'
Private Declare Function Netbios Lib "netapi32.dll" (pncb As NCB) As Byte
'
Private Declare Function GetProcessHeap Lib "kernel32" () As Long
'
Private Declare Function HeapAlloc Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long
'
Private Declare Sub RtlMoveMemory Lib "kernel32" (hpvDest As Any, ByVal hpvSource&, ByVal cbCopy&)
'
Private Declare Function HeapFree Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, lpMem As Any) As Long
'

Public Function MACAddress() As String

    Const sPROC_NAME As String = "MACAddress"
    Dim myNcb As NCB
    Dim bRet As Byte
    
    On Error GoTo ErrorHandler
    
    myNcb.ncb_command = NCBRESET
    bRet = Netbios(myNcb)
    
    myNcb.ncb_command = NCBASTAT
    myNcb.ncb_lana_num = 0
    myNcb.ncb_callname = "*               "
    
    Dim myASTAT As ASTAT
    Dim pASTAT As Long
    myNcb.ncb_length = Len(myASTAT)
    
    pASTAT = HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS Or HEAP_ZERO_MEMORY, myNcb.ncb_length)
    If pASTAT = 0 Then
       Err.Raise errMemoryAllocFailed, msMODULE_NAME & "." & sPROC_NAME, "Memory allocation failed"
       Exit Function
    End If
    
    myNcb.ncb_buffer = pASTAT
    bRet = Netbios(myNcb)
    
    RtlMoveMemory myASTAT, myNcb.ncb_buffer, Len(myASTAT)
    MACAddress = Hex(myASTAT.adapt.adapter_address(0)) & ":" & _
                Hex(myASTAT.adapt.adapter_address(1)) & ":" & _
                Hex(myASTAT.adapt.adapter_address(2)) & ":" & _
                Hex(myASTAT.adapt.adapter_address(3)) & ":" & _
                Hex(myASTAT.adapt.adapter_address(4)) & ":" & _
                Hex(myASTAT.adapt.adapter_address(5))
    HeapFree GetProcessHeap(), 0, ByVal pASTAT
    
    Exit Function
    
ErrorHandler:    '
    MACAddress = "00:00:00:00:00:00"
CyberCow
Hmmmm, interesting . . .

Thanks R-Cubed ! !

What if the PC doesn't have a NIC? Any ideas?
trip
You could use the volume serial!

just specify the drive ie: C:\ and it returns the volumes hardware serial.

Attached is a module to do it.
GlenKruger
A Nic card is not the best thing to use as nic's although they have a very unique number do not last as long as drives usually do these days. The Drive Serial Number which is embeded into the drive will not change so what ever computer your program is running on will need this drive or it will not run. You can then have the program read that serial number then decide if to let the program run or you can save it to the registry and check that the value is there and run it. What I do is to record all the hard drive serial numbers not volume numbers and write them to the registry then I have the program read the current hard drives compare it to the registry enetries and if they are the same run the program. I'll let you figure out the code for that. Here is some code to read the drive letter and serial number. Save it to a .vbs file using note pad and run it. it will show you the fixed drives installed and the serial numbers. in access you would use message boxes or write it to where ever you want.

Have fun!

CODE


Set objFSO = CreateObject("Scripting.FileSystemObject")
Set colDrives = objFSO.Drives

For Each objDrive in colDrives
   If objDrive.DriveType = 2 Then

       Wscript.Echo "Drive letter: " & objDrive.DriveLetter

       Wscript.Echo "Serial number: " & objDrive.SerialNumber

    End If

Next
GlenKruger
Hi Rob,

If you are using Windows 2000 or up this works nicely too.
CODE
Public Function GetInfo()
Dim Manufacturer As String
Dim ProductName As String
Dim MACAddress As String

On Error Resume Next
' To use a computer on a network use the full path otherwise "." refer's to the
'local computer.

strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colItems = objWMIService.ExecQuery("Select * from Win32_NetworkAdapter", , 48)

For Each objItem In colItems

  
   If objItem.NetConnectionID = objItem.NetConnectionID Then

      
        Manufacturer = objItem.Manufacturer
  
        ProductName = objItem.ProductName
      
        MACAddress = objItem.MACAddress
        
        Call MsgBox(Manufacturer, vbInformation, "Mac Address Demo")
        Call MsgBox(ProductName, vbInformation, "Mac Address Demo")
        Call MsgBox(MACAddress, vbInformation, "Mac Address Demo")
              

    
   End If
Next

End Function
CyberCow
Glen & Trip,

Thank you for your input and assistance. I will play with these today!
quest4
You might want to check on some of the Environ variables, environ can find a allot of different things. Just a thought for you to think about. hth.
GlenKruger
If you need more help don't hesitate to ask moo.
CyberCow
Glen,

Happy to take you up on that offer . . .

• What are the other fields available in the objItem collection?
{When you used the "Select * from Win32_NetworkAdapter" query string to acuire the data, what are (or how do I see) the entire list of field names?}

• I'm also focusing on Set objWMIService = GetObject("winmgmts:\" & strComputer & "rootcimv2") because I've never ancountered that before. What is that?

• In your first response, you used Wscript. WHat should that be Dim'd and Set as?



Thanks man!
ScottGem
Glen,
I was looking for code like this a while back, where were you then? frown.gif

Seriously, with almost all new motherboards having onboard Ethernet adapters, there is a MAC built in to the motherboard. Wouldn't this make the MAC a more static ID to look for?

The problem I see with using a drive SN is what if the user wants to move the app to an external drive or needs to replace the drive. This would disable the app. I understand you are saying the same thing could happen with replacing a NIC, but like I said, they are built into motherboards now.

Though there is an issue of some PCs having multiple NICs. How could that be dealt with?
GlenKruger
The first one uses the file system object So you need to set references to the MS Scripting dll. Instead of using Wscript.Echo "Available space: " & objDrive.AvailableSpace in Access use
MsgBox objDrive.AvailableSpace The same goes for the second one.
CODE


Set objFSO = CreateObject("Scripting.FileSystemObject")

Set colDrives = objFSO.Drives

For Each objDrive in colDrives

    Wscript.Echo "Available space: " & objDrive.AvailableSpace

    Wscript.Echo "Drive letter: " & objDrive.DriveLetter

    Wscript.Echo "Drive type: " & objDrive.DriveType

    Wscript.Echo "File system: " & objDrive.FileSystem

    Wscript.Echo "Free space: " & objDrive.FreeSpace

    Wscript.Echo "Is ready: " & objDrive.IsReady

    Wscript.Echo "Path: " & objDrive.Path

    Wscript.Echo "Root folder: " & objDrive.RootFolder

    Wscript.Echo "Serial number: " & objDrive.SerialNumber

    Wscript.Echo "Share name: " & objDrive.ShareName

    Wscript.Echo "Total size: " & objDrive.TotalSize

    Wscript.Echo "Volume name: " & objDrive.VolumeName

Next


The second use's Windows WMI script which is how windows 2000 and up queries the operating system instead of using API Calls. You need to set a reference to the WMI Scripting dll.

CODE


strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colItems = objWMIService.ExecQuery("Select * from Win32_Volume")

For Each objItem In colItems

    WScript.Echo "Automount: " & objItem.Automount

    WScript.Echo "Block Size: " & objItem.BlockSize

    WScript.Echo "Capacity: " & objItem.Capacity

    WScript.Echo "Caption: " & objItem.Caption

    WScript.Echo "Compressed: " & objItem.Compressed

    WScript.Echo "Device ID: " & objItem.DeviceID

    WScript.Echo "Dirty Bit Set: " & objItem.DirtyBitSet

    WScript.Echo "Drive Letter: " & objItem.DriveLetter

    WScript.Echo "Drive Type: " & objItem.DriveType

    WScript.Echo "File System: " & objItem.FileSystem

    WScript.Echo "Free Space: " & objItem.FreeSpace

    WScript.Echo "Indexing Enabled: " & objItem.IndexingEnabled

    WScript.Echo "Label: " & objItem.Label

    WScript.Echo "Maximum File Name Length: " & objItem.MaximumFileNameLength

    WScript.Echo "Name: " & objItem.Name

    WScript.Echo "Quotas Enabled: " & objItem.QuotasEnabled

    WScript.Echo "Quotas Incomplete: " & objItem.QuotasIncomplete

    WScript.Echo "Quotas Rebuilding: " & objItem.QuotasRebuilding

    WScript.Echo "Serial Number: " & objItem.SerialNumber

    WScript.Echo "Supports Disk Quotas: " & objItem.SupportsDiskQuotas

    WScript.Echo "Supports File-Based Compression: " & objItem.SupportsFileBasedCompression

    WScript.Echo

Next


Both are saved as .vbs files if you want to run them as stand alone scripts.
WMI scripts can be run on any computers running Windows 98 or Windows ME with WMI Scripting installed or on any computer running Windows 2000 and up.

The Scripts are used mainly to help network administrators accomplish unattented tasks but i have found them to be usefull in Access programming as well as VB.

This site will allow you to download a help file list a variatey of scripts. Once you understand how they work you will be writing your own.

http://www.microsoft.com/technet/scriptcenter



Edited by: GlenKruger on Wed Jan 19 17:26:31 EST 2005.

Edited by: GlenKruger on Mon Jan 24 13:27:43 EST 2005.
GlenKruger
Well actually I have been ill for the last while and don't really search the site very much anymore.

To answer your question simpely no the on board Nic is not the best to use as it can be disabled in the bios and won't even show up in a scan of hardware. I understand your concern about someone replacing a drive but that is where looking at what was origionally there when you installed your app and what is there now will come into play. The code required is not for the weak at heart because you are manipulating the users registry and that is why I will not go further into detail on the site about doing that. In an unexpierenced programmers hands that type of code could cause severe damage to someones computer. To properly restrict user's from copying software from one computer to another you need to use registration key's and code in your program that sends certain data back to your server every time your program is started and connected to the internet as well as code in your install program that writes to the registry. You have to have a server running 24 hours a day to catch people trying to do this sort of activeity again to complicated to get into on the site besides if I give all my trade secrets away what good would I be to my clients .... laugh.gif

As far as having more than one Nic installed this sample will return all the Nic's installed in the computer so then you would just record them somewhere.

http://members.shaw.ca/glenk/NicCardMacAddy.zip

HTH
Glen

Edited by: GlenKruger on Wed Jan 19 17:18:17 EST 2005.
ddaddy
Hi all,
Does anyone have a demo of security based on the drive serial number?

The module posted in page 1 of this thread by trip is no longer available to download!!

Thanks
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.