Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Get MAC address programmatically

512 views
Skip to first unread message

Robb Williams

unread,
Dec 11, 2001, 1:42:29 PM12/11/01
to
I need to programmatically (using C++) obtain the network
adapter(s) physical address. I currently use the services of
NetBios. Unfortunately, when an adapter is disconnected via
Windows, NetBios no longer returns the physical address for
the adapter. The 'ipconfig /all' command does continue to
report the correct physical address.

Is there an alternative method to get a network adapter MAC
address that works when the adapter is offline? I would prefer
to not parse the output of 'ipconfig /all'. I am looking for a
Win98/NT+ API type solution.

thanks in advance,

Robb

Si Thu

unread,
Dec 11, 2001, 7:20:40 PM12/11/01
to
Not sure if this will help you in the least; I only use Visual Basic
for programming, but if you can see the entry points in the DLL, I
think you might be able to convert these calls to C++ equivalents??

This is what I use to get MAC Address on VB. I call EthernetAddress
passing the value "0" (zero). Hope this helps!

---------------------

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 Sub CopyMemory Lib "Kernel32" Alias "RtlMoveMemory"
(hpvDest As Any, ByVal hpvSource As Long, ByVal cbCopy As Long)
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 Function HeapFree Lib "Kernel32" (ByVal hHeap As Long,
ByVal dwFlags As Long, lpMem As Any) As Long

Public Function EthernetAddress(LanaNumber As Long) As String
On Error GoTo LANErr
Dim udtNCB As NCB
Dim bytResponse As Byte
Dim udtASTAT As ASTAT
Dim udtTempASTAT As ASTAT
Dim lngASTAT As Long
Dim strOut As String
Dim x As Integer

udtNCB.ncb_command = NCBRESET
bytResponse = Netbios(udtNCB)
udtNCB.ncb_command = NCBASTAT
udtNCB.ncb_lana_num = LanaNumber
udtNCB.ncb_callname = "* "
udtNCB.ncb_length = Len(udtASTAT)
lngASTAT = HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS Or
HEAP_ZERO_MEMORY, udtNCB.ncb_length)
strOut = ""
If lngASTAT Then
udtNCB.ncb_buffer = lngASTAT
bytResponse = Netbios(udtNCB)
CopyMemory udtASTAT, udtNCB.ncb_buffer, Len(udtASTAT)
With udtASTAT.adapt
For x = 0 To 5
strOut = strOut & Right$("00" &
Hex$(.adapter_address(x)), 2)
Next x
End With
HeapFree GetProcessHeap(), 0, lngASTAT
End If
EthernetAddress = strOut
Exit Function
LANErr:
EthernetAddress = "MAC Address Error!"
End Function


========================================

ro...@sensor.com (Robb Williams) wrote in message news:<d2288a30.01121...@posting.google.com>...

Robb Williams

unread,
Dec 12, 2001, 12:18:04 PM12/12/01
to
Thank you for your reply but this is also the method (NetBios)
I use to get the MAC. It appears to only work if the Ethernet
adapter is online. Have you found that this isn't the case
using your code?

-Robb

st_s...@hotmail.com (Si Thu) wrote in message news:<d06d3ccc.0112...@posting.google.com>...

Larry D'Cunha

unread,
Dec 13, 2001, 6:35:11 PM12/13/01
to
Hello Rob,
I am trying to solve the exact same problem, and you posted your
message 1 day after mine, it is scary!! My post has the subject
"Retrieve IP address from registry ?(when network down Win2K, WinNT
SP5 only)" And I've found a lot of info through google groups, but
not a solution yet. The problem is ONLY when network cable is
disconnected (win2K) I also found one other guy who had our problem.
His post has subject "How to determine a MAC address ipconfig-style?"
And I just contacted him via email to see if he ended up getting a
solution. Pleeeese let me know if you find out how to do this.

Thanks

Larry

Julie Random

unread,
Dec 13, 2001, 10:19:14 PM12/13/01
to
taken from the great site http://www.allapi.net
after I searched for mac

get their api guide while your there

will run as is within your vba editor in excel
so you can see what its doing

Visual Basic Example - Network Specs
'Paste this code into a module and set the Startup Object
'to 'Sub Main'
'(To set the startup object, go to
'Project->Project Properties->General Tab->Startup Object)

Public Const MAX_HOSTNAME_LEN = 132
Public Const MAX_DOMAIN_NAME_LEN = 132
Public Const MAX_SCOPE_ID_LEN = 260
Public Const MAX_ADAPTER_NAME_LENGTH = 260
Public Const MAX_ADAPTER_ADDRESS_LENGTH = 8
Public Const MAX_ADAPTER_DESCRIPTION_LENGTH = 132
Public Const ERROR_BUFFER_OVERFLOW = 111
Public Const MIB_IF_TYPE_ETHERNET = 1
Public Const MIB_IF_TYPE_TOKENRING = 2
Public Const MIB_IF_TYPE_FDDI = 3
Public Const MIB_IF_TYPE_PPP = 4
Public Const MIB_IF_TYPE_LOOPBACK = 5
Public Const MIB_IF_TYPE_SLIP = 6

Type IP_ADDR_STRING
Next As Long
IpAddress As String * 16
IpMask As String * 16
Context As Long
End Type

Type IP_ADAPTER_INFO
Next As Long
ComboIndex As Long
AdapterName As String * MAX_ADAPTER_NAME_LENGTH
Description As String * MAX_ADAPTER_DESCRIPTION_LENGTH
AddressLength As Long
Address(MAX_ADAPTER_ADDRESS_LENGTH - 1) As Byte
Index As Long
Type As Long
DhcpEnabled As Long
CurrentIpAddress As Long
IpAddressList As IP_ADDR_STRING
GatewayList As IP_ADDR_STRING
DhcpServer As IP_ADDR_STRING
HaveWins As Boolean
PrimaryWinsServer As IP_ADDR_STRING
SecondaryWinsServer As IP_ADDR_STRING
LeaseObtained As Long
LeaseExpires As Long
End Type

Type FIXED_INFO
HostName As String * MAX_HOSTNAME_LEN
DomainName As String * MAX_DOMAIN_NAME_LEN
CurrentDnsServer As Long
DnsServerList As IP_ADDR_STRING
NodeType As Long
ScopeId As String * MAX_SCOPE_ID_LEN
EnableRouting As Long
EnableProxy As Long
EnableDns As Long
End Type

Public Declare Function GetNetworkParams Lib "IPHlpApi" (FixedInfo As
Any, pOutBufLen As Long) As Long
Public Declare Function GetAdaptersInfo Lib "IPHlpApi" (IpAdapterInfo
As Any, pOutBufLen As Long) As Long
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory"
(Destination As Any, Source As Any, ByVal Length As Long)
Sub main()
'This example was created by George Bernier
(ber...@dinomail.qc.ca)
Dim error As Long
Dim FixedInfoSize As Long
Dim AdapterInfoSize As Long
Dim i As Integer
Dim PhysicalAddress As String
Dim NewTime As Date
Dim AdapterInfo As IP_ADAPTER_INFO
Dim Adapt As IP_ADAPTER_INFO
Dim AddrStr As IP_ADDR_STRING
Dim FixedInfo As FIXED_INFO
Dim Buffer As IP_ADDR_STRING
Dim pAddrStr As Long
Dim pAdapt As Long
Dim Buffer2 As IP_ADAPTER_INFO
Dim FixedInfoBuffer() As Byte
Dim AdapterInfoBuffer() As Byte

'Get the main IP configuration information for this machine using
a FIXED_INFO structure
FixedInfoSize = 0
error = GetNetworkParams(ByVal 0&, FixedInfoSize)
If error <> 0 Then
If error <> ERROR_BUFFER_OVERFLOW Then
MsgBox "GetNetworkParams sizing failed with error " & error
Exit Sub
End If
End If
ReDim FixedInfoBuffer(FixedInfoSize - 1)

error = GetNetworkParams(FixedInfoBuffer(0), FixedInfoSize)
If error = 0 Then
CopyMemory FixedInfo, FixedInfoBuffer(0), Len(FixedInfo)
MsgBox "Host Name: " & FixedInfo.HostName 'host name
MsgBox "DNS Servers: " & FixedInfo.DnsServerList.IpAddress
'dns server IP
pAddrStr = FixedInfo.DnsServerList.Next
Do While pAddrStr <> 0
CopyMemory Buffer, ByVal pAddrStr, Len(Buffer)
MsgBox "DNS Servers: " & Buffer.IpAddress 'dns
server IP
pAddrStr = Buffer.Next
Loop

Select Case FixedInfo.NodeType 'node type
Case 1
MsgBox "Node type: Broadcast"
Case 2
MsgBox "Node type: Peer to peer"
Case 4
MsgBox "Node type: Mixed"
Case 8
MsgBox "Node type: Hybrid"
Case Else
MsgBox "Unknown node type"
End Select

MsgBox "NetBIOS Scope ID: " & FixedInfo.ScopeId 'scope ID
'routing
If FixedInfo.EnableRouting Then
MsgBox "IP Routing Enabled "
Else
MsgBox "IP Routing not enabled"
End If
' proxy
If FixedInfo.EnableProxy Then
MsgBox "WINS Proxy Enabled "
Else
MsgBox "WINS Proxy not Enabled "
End If
' netbios
If FixedInfo.EnableDns Then
MsgBox "NetBIOS Resolution Uses DNS "
Else
MsgBox "NetBIOS Resolution Does not use DNS "
End If
Else
MsgBox "GetNetworkParams failed with error " & error
Exit Sub
End If

'Enumerate all of the adapter specific information using the
IP_ADAPTER_INFO structure.
'Note: IP_ADAPTER_INFO contains a linked list of adapter entries.

AdapterInfoSize = 0
error = GetAdaptersInfo(ByVal 0&, AdapterInfoSize)
If error <> 0 Then
If error <> ERROR_BUFFER_OVERFLOW Then
MsgBox "GetAdaptersInfo sizing failed with error " & error
Exit Sub
End If
End If
ReDim AdapterInfoBuffer(AdapterInfoSize - 1)

' Get actual adapter information
error = GetAdaptersInfo(AdapterInfoBuffer(0), AdapterInfoSize)
If error <> 0 Then
MsgBox "GetAdaptersInfo failed with error " & error
Exit Sub
End If
CopyMemory AdapterInfo, AdapterInfoBuffer(0), Len(AdapterInfo)
pAdapt = AdapterInfo.Next

Do While pAdapt <> 0
CopyMemory Buffer2, AdapterInfo, Len(Buffer2)
Select Case Buffer2.Type
Case MIB_IF_TYPE_ETHERNET
MsgBox "Ethernet adapter "
Case MIB_IF_TYPE_TOKENRING
MsgBox "Token Ring adapter "
Case MIB_IF_TYPE_FDDI
MsgBox "FDDI adapter "
Case MIB_IF_TYPE_PPP
MsgBox "PPP adapter"
Case MIB_IF_TYPE_LOOPBACK
MsgBox "Loopback adapter "
Case MIB_IF_TYPE_SLIP
MsgBox "Slip adapter "
Case Else
MsgBox "Other adapter "
End Select
MsgBox " AdapterName: " & Buffer2.AdapterName
MsgBox "AdapterDescription: " & Buffer2.Description 'adatpter name

For i = 0 To Buffer2.AddressLength - 1
PhysicalAddress = PhysicalAddress & Hex(Buffer2.Address(i))
If i < Buffer2.AddressLength - 1 Then
PhysicalAddress = PhysicalAddress & "-"
End If

Next
MsgBox "Physical Address: " & PhysicalAddress 'mac address
If Buffer2.DhcpEnabled Then
MsgBox "DHCP Enabled "
Else
MsgBox "DHCP disabled"
End If

pAddrStr = Buffer2.IpAddressList.Next
Do While pAddrStr <> 0
CopyMemory Buffer, Buffer2.IpAddressList, LenB(Buffer)
MsgBox "IP Address: " & Buffer.IpAddress
MsgBox "Subnet Mask: " & Buffer.IpMask
pAddrStr = Buffer.Next
If pAddrStr <> 0 Then
CopyMemory Buffer2.IpAddressList, ByVal pAddrStr,
Len(Buffer2.IpAddressList)
End If
Loop
MsgBox "Default Gateway: " & Buffer2.GatewayList.IpAddress
pAddrStr = Buffer2.GatewayList.Next
Do While pAddrStr <> 0
CopyMemory Buffer, Buffer2.GatewayList, Len(Buffer)
MsgBox "IP Address: " & Buffer.IpAddress
pAddrStr = Buffer.Next
If pAddrStr <> 0 Then
CopyMemory Buffer2.GatewayList, ByVal pAddrStr,
Len(Buffer2.GatewayList)
End If
Loop

MsgBox "DHCP Server: " & Buffer2.DhcpServer.IpAddress
MsgBox "Primary WINS Server: " &
Buffer2.PrimaryWinsServer.IpAddress
MsgBox "Secondary WINS Server: " &
Buffer2.SecondaryWinsServer.IpAddress

' Display time
NewTime = CDate(Adapt.LeaseObtained)
MsgBox "Lease Obtained: " & CStr(NewTime)

NewTime = CDate(Adapt.LeaseExpires)
MsgBox "Lease Expires : " & CStr(NewTime)
pAdapt = Buffer2.Next
If pAdapt <> 0 Then
CopyMemory AdapterInfo, ByVal pAdapt, Len(AdapterInfo)
End If

Loop

End Sub






Copyright © 1998-2001, The KPD-Team - Privacy statement

ro...@sensor.com (Robb Williams) wrote in message news:<d2288a30.01121...@posting.google.com>...

Robb Williams

unread,
Dec 17, 2001, 3:28:57 PM12/17/01
to
Larry,

I found another method (presumably a non-NetBios method)
at http://tangentsoft.net/wskfaq/examples/getmac-snmp.html.
I haven't had a chance to try it out yet due to other
priorities, but I plan to sometime soon. I also want to
try the other poster's (Julie Random) method - although
I see references to NetBios in the code comments. If you
get the chance to try any of these before I do, please send
me an email or a post here as to the outcome.

Happy MAC hunting...
Robb

larry....@cedara.com (Larry D'Cunha) wrote in message news:<d32300e6.01121...@posting.google.com>...

Larry D'Cunha

unread,
Dec 19, 2001, 4:41:46 PM12/19/01
to
Hi Robb!
I have decided to go the ipconfig route. I came across this suggestion
from someone in these groups. But thanks very much to a certain senior
software guru I work with (I'm sure he wont mind me giving out his
code). In this C program solution, we call the system command
'ipconfig /all' and dump the output to a tempfile. Then read the MAC
address from this file. It works on WinNT4.0,Win2000 all the time even
when cable is disconnected!!
hope this helps..

Larry

(by the way, the snmp method is actually what ipconfig uses, but that
is all hacker reverse engineered code, undocumented and not safe to
use. Best bet is to use this method and not have to worry about bugs
or maintenance.)

here is the code (might be a little messed up i formatting)

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int get_mac_ip( ip, mac )
int *ip;
int *mac;
{
char *tfn, *cmd, *ipc = "ipconfig /all ";
int ret = 0;
FILE *tf;
char buf[128];

if ( (tfn = _tempnam(0, "ipconfig")) == (char *)0 )
ret = -1;

if ( ret == 0 && (cmd = (char *)malloc(strlen(tfn) + strlen(ipc) +
4)) ==
(char *)0 )
ret = -1;

(void)sprintf( cmd, "%s > %s", ipc, tfn );

if ( ret == 0 && (ret = system(cmd)) < 0 )
{
fprintf( stderr, "command \"%s\" failed with error <%s>\n",
cmd, strerror(errno) );
}

if ( ret == 0 && (tf = fopen(tfn, "r")) == (FILE *)0 )
{
fprintf( stderr, "failed with error <%s>\n",
cmd, strerror(errno) );
}

while ( ret == 0 && fgets(buf, sizeof(buf), tf) != (char *)0 )
{
if ( strstr(buf, "Physical Address") )
{
if ( sscanf(strchr(buf,':')+2, "%02x-%02x-%02x-%02x-%02x-%02x",
&mac[0],
&mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) < 6 )
{
fprintf( stderr, "error in Physical Address line <%s>\n", buf );
ret = -1;
}
}
else if ( strstr(buf, "IP Address") )
{
if ( sscanf(strchr(buf,':')+2, "%u.%u.%x.%u", &ip[0], &ip[1],
&ip[2], &ip[3]) < 4 )
{
fprintf( stderr, "error in IP Address line <%s>\n", buf );
ret = -1;
}
}
}

if ( tf ) fclose( tf );
if ( cmd ) free( cmd );
if ( tfn ) free( tfn );

return ret;
}

main()
{
int ip[4], mac[6];

(void)get_mac_ip( ip, mac ); /* MUST USE %02X to keep first 0! */
printf( "MAC address: %02X-%02X-%02X-%02X-%02X-%02X\n", mac[0],
mac[1], mac[2],
mac[3], mac[4], mac[5] );
printf("%d %d %d %d %d %d\n",mac[0], mac[1], mac[2], mac[3],
mac[4], mac[5] );
printf( "IP address: %u.%u.%x.%u\n", ip[0], ip[1], ip[2], ip[3] );
}


ro...@sensor.com (Robb Williams) wrote in message news:<d2288a30.01121...@posting.google.com>...

Robb Williams

unread,
Dec 20, 2001, 9:46:03 AM12/20/01
to
Larry,

Thanks for the code. I will need to make some adjustments to
account for mutiple MAC addresses. Some of our users workstations
use a network configuration that has numerous MACs. I think they
have an ATM config.

-Robb


lpdc...@engmail.uwaterloo.ca (Larry D'Cunha) wrote in message news:<456de2c6.01121...@posting.google.com>...

Julie Random

unread,
Dec 20, 2001, 9:01:24 PM12/20/01
to
the code I posted does not use netbios calls so offline
adapters are reported ok, it even covers when there are two nics.
as stated if you want you can drop the code into any vba
enviroment and step through it and watch it run, the answer is
there you just haven't looked at it.

jran...@yahoo.com.au (Julie Random) wrote in message news:<f8663c6e.01121...@posting.google.com>...

Robb Williams

unread,
Dec 26, 2001, 11:22:54 AM12/26/01
to
I will give this code a try although I was initially hesitant
because the MSDN docs state that these API calls (GetNetworkParams
and GetAdaptersInfo) are only available for Windows CE OS. The
docs also state that some devices do not support these calls
at all. I don't know if they are refering to only network
devices or Windows CE type devices (handhelds, etc..).

Have you tried this code on 98/NT/2000?

thanks for your post,
Robb

jran...@yahoo.com.au (Julie Random) wrote in message news:<f8663c6e.01122...@posting.google.com>...

Julie Random

unread,
Dec 27, 2001, 12:18:04 AM12/27/01
to
your original post states you want win98/nt api calls thats why I posted
that code. yes I have run, it I wouldn't post something I didnt know
worked. as it was vb and not c I suggested you use the vba editor in
excel to step through the code to see what its doing, you just have to
cut and paste it as is

you will need to do the vb to c conversion, MSDN ususally shows the
c++ calls to the api in this case the call is to IPHlpApi the function
is GetNetworkParams and GetAdaptersInfo

ro...@sensor.com (Robb Williams) wrote in message news:<d2288a30.01122...@posting.google.com>...


> I will give this code a try although I was initially hesitant
> because the MSDN docs state that these API calls (GetNetworkParams
> and GetAdaptersInfo) are only available for Windows CE OS. The
> docs also state that some devices do not support these calls
> at all. I don't know if they are refering to only network
> devices or Windows CE type devices (handhelds, etc..).
>
> Have you tried this code on 98/NT/2000?
>
> thanks for your post,
> Robb
>

0 new messages