Click here to Skip to main content
14,325,352 members

Get Physical HDD Serial Number without WMI

Rate this:
4.79 (62 votes)
Please Sign up or sign in to vote.
4.79 (62 votes)
6 May 2008CPOL
Retrieve the physical Hard drive ID and other info using low level APIs like DeviceIOControl

Sample Image - DriveInfo.png

Introduction

Many people looking for a schema to protect their work need to get some information that is hardware specific like the Mac Address or some hard drive serial number.

Background

If you tried other solutions like like this one, it probably did not work for you because it's using the WMI services. I was able to find a solution that worked reasonably well here. It made low level calls to the disk using commands sent by the DeviceIoControl API. The code was not very reusable unless you used native C++. Therefore I brushed it a bit and made it look more Object Oriented. Most importantly, I exposed the drive information through a .NET collection.

Using the Code

Since the collection is written in MC++, I've included some Microsoft DLLs from the redistributable pack in the demo zip. Also it's mandatory to use .NET 2.0 since the collection is generic.

The code is very easy to use from any .NET language, like C# for instance:

m_list = new DriveListEx();
m_list.Load();
//bind to a a grid view
m_dataGridView.DataSource = m_list;

Points of Interest

The information about the internal drives is gathered in DiskInfo::LoadDiskInfo();

DiskInfo is a native singleton class that wraps the calls to ReadPhysicalDriveInNTWithAdminRights() and ReadIdeDriveAsScsiDriveInNT(). I ignored the ReadPhysicalDriveInNTWithZeroRights() that did not seem to work anyways.

Both functions will call AddIfNew() if they can retrieve the information.

Internally there is a list that holds the raw information about the drives and that is updated when a new drive information was found.

BOOL DiskInfo::AddIfNew(USHORT *pIdSector)
{
  BOOL bAdd = TRUE;
  for(UINT i =0; i< m_list.size();i++)
  {
    if(memcmp(pIdSector,m_list[i],256 * sizeof(WORD)) == 0)
    {
       bAdd = false;
       break;
    }
  }
   if(bAdd)
   {
      WORD* diskdata = new WORD[256];
      ::memcpy(diskdata,pIdSector,256*sizeof(WORD));
      m_list.push_back(diskdata);
   }
  return bAdd;
}

If you are stuck with a non .NET compiler, you could still use the source code from UnmanagedCode.cpp, just uncomment the #define NATIVE_CODE line.
This build is for Windows XP 32 bit systems. If you need it for Vista or 64 bit systems, you should select the right include and lib folders when building and should not use the additional DLLs from the release.zip archive, since they are 32 bit for Windows XP.

History

  • Version 1.1: Added ReadPhysicalDriveInNTUsingSmart for reading the HDD info.
    P.S. I did not get a chance to test it for Windows 95 and alike.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

dmihailescu
Software Developer (Senior)
United States United States
Decebal Mihailescu is a software engineer with interest in .Net, C# and C++.

Comments and Discussions

 
GeneralMy vote of 4 Pin
Member 1272333412-Apr-17 8:56
memberMember 1272333412-Apr-17 8:56 
QuestionDoes not work with VS2013 Pin
Matias Castro7-Feb-17 16:00
memberMatias Castro7-Feb-17 16:00 
QuestionYour solution is sh*t... Pin
JoeDude12328-Mar-16 17:45
memberJoeDude12328-Mar-16 17:45 
QuestionDownload Link Pin
LoganMB20-Jul-15 10:05
memberLoganMB20-Jul-15 10:05 
QuestionThe downloads doesn't work well! Pin
jjjjj1023102324-Jun-15 20:06
memberjjjjj1023102324-Jun-15 20:06 
AnswerRe: The downloads doesn't work well! Pin
Member 1184242720-Jul-15 9:55
memberMember 1184242720-Jul-15 9:55 
QuestionGetting Error: Could not load file or assembly 'DriveInfoEx, Version=1.1.3054.15437, Culture=neutral Pin
Mohiyuddin Khan28-May-14 19:19
memberMohiyuddin Khan28-May-14 19:19 
AnswerRe: Getting Error: Could not load file or assembly 'DriveInfoEx, Version=1.1.3054.15437, Culture=neutral Pin
dmihailescu1-Jul-14 3:44
memberdmihailescu1-Jul-14 3:44 
QuestionCan not run This Code In VS2010 Pin
Yonos allahyari19-Dec-13 8:31
memberYonos allahyari19-Dec-13 8:31 
AnswerRe: Can not run This Code In VS2010 Pin
Albert Holguin19-Dec-13 9:16
professionalAlbert Holguin19-Dec-13 9:16 
GeneralMessage Closed Pin
19-Dec-13 9:21
memberYonos allahyari19-Dec-13 9:21 
AnswerRe: Can not run This Code In VS2010 Pin
Albert Holguin19-Dec-13 9:32
professionalAlbert Holguin19-Dec-13 9:32 
QuestionCan i get usb drive serial no from this code Pin
sandeepraj331-Dec-13 21:51
membersandeepraj331-Dec-13 21:51 
QuestionDriveInfoEx.dll not working for x64 bit computer Pin
kalaivanan from Bangalore, India22-Oct-13 3:57
memberkalaivanan from Bangalore, India22-Oct-13 3:57 
AnswerRe: DriveInfoEx.dll not working for x64 bit computer Pin
dmihailescu23-Oct-13 15:30
memberdmihailescu23-Oct-13 15:30 
GeneralRe: DriveInfoEx.dll not working for x64 bit computer Pin
Hossam™ Ahmed11-Feb-15 1:27
memberHossam™ Ahmed11-Feb-15 1:27 
Suggestioni tried ur demo project Pin
abhinav_8930-Aug-13 7:22
memberabhinav_8930-Aug-13 7:22 
GeneralRe: i tried ur demo project Pin
dmihailescu1-Jul-14 3:46
memberdmihailescu1-Jul-14 3:46 
QuestionHow to execute this code Pin
Member 101775611-Aug-13 10:40
memberMember 101775611-Aug-13 10:40 
BugNot runing in VS2008 Pin
Menon Santosh13-Mar-13 2:28
professionalMenon Santosh13-Mar-13 2:28 
GeneralRe: Not runing in VS2008 Pin
dmihailescu23-Oct-13 15:39
memberdmihailescu23-Oct-13 15:39 
Questioni want to get hd Info of other computer through network Pin
ehtshamkh15-Jan-13 1:20
memberehtshamkh15-Jan-13 1:20 
QuestionIf there are more than 1 HDD? Pin
leomifare21-Oct-12 21:20
memberleomifare21-Oct-12 21:20 
Questionmac add, ip add, motherboard serial no, processor s.no, local drive s.no.... Pin
Praveen S22-Jul-12 20:38
memberPraveen S22-Jul-12 20:38 


// Mac Address.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "stdafx.h"
#include <windows.h>
#include <conio.h>
#include <string>
#include<iostream>
#include <fstream>
#include <lm.h>
#include <assert.h>
#include <winsock.h>
#define _WIN32_DCOM
#include <iostream>
#include <comdef.h>
#include <wbemidl.h>
#include <comutil.h>


#pragma comment(lib, "Netapi32.lib")
#pragma comment(lib, "wsock32.lib")
# pragma comment(lib, "wbemuuid.lib")



using namespace std;


void filewrite(string a,int e)
{
ofstream fout;
if(e==1)
fout.open("System Configuration.txt");
else
{
fout.open("System Configuration.txt", ios::app);
fout<<a;
fout<<endl;
="" }
=""
="" fout.close();
=""
}=""


void="" getmac()
{
="" unsigned="" char="" macdata[8];
="" wksta_transport_info_0="" *pwkti;
="" dword="" dwentriesread;
="" dwtotalentries;
="" byte="" *pbbuffer;

="" net_api_status="" dwstatus="NetWkstaTransportEnum(
" null,="" [in]="" server="" name
="" 0,="" data="" structure="" to="" return
="" &pbbuffer,="" [out]="" pointer="" buffer
="" max_preferred_length,="" maximum="" length
="" &dwentriesread,="" counter="" of="" elements="" actually="" enumerated
="" &dwtotalentries,="" total="" number="" that="" could="" be="" null);="" [in="" out]="" resume="" handle

="" assert(dwstatus="=" nerr_success);

="" pwkti="(WKSTA_TRANSPORT_INFO_0" *)pbbuffer;="" type="" cast="" the="" buffer

="" for(dword="" i="1;" i<="" dwentriesread;="" i++)="" first="" address="" is="" 00000000,="" skip="" it
="" {="" dd[33];="" enumerate="" macs="" and="" print
="" swscanf((wchar_t="" *)pwkti[i].wkti0_transport_address,="" l"%2hx%2hx%2hx%2hx%2hx%2hx",="" &macdata[0],="" &macdata[1],="" &macdata[2],="" &macdata[3],="" &macdata[4],="" &macdata[5]);
="" printmacaddress(macdata);
="" sprintf(dd,"="" %02x-%02x-%02x-%02x-%02x-%02x\n",macdata[0],="" macdata[1],="" macdata[2],="" macdata[3],="" macdata[4],="" macdata[5]);
="" string="" u="MAC Address :" ;
="" u+="dd;
" filewrite(u,0);
="" release="" pbbuffer="" allocated="" by="" above="" function
="" nerr_success);
}

void="" getip()
{
="" word="" wversionrequested;
="" wsadata="" wsadata;
="" name[255];
="" phostent="" hostinfo;
="" wversionrequested="MAKEWORD(" 1,="" 1="" );
="" *ip;

="" if="" (="" wsastartup(="" wversionrequested,="" &wsadata="" )="=" 0="" )
="" if(="" gethostname="" name,="" sizeof(name))="=" 0)
="" {
="" printf("host="" name:="" %s\n",="" name);
="" name1="Computer Name: " name1+="name;
" filewrite(name1,0);

="" if((hostinfo="gethostbyname(name))" !="NULL)
" int="" ncount="0;
" while(hostinfo-="">h_addr_list[nCount])
{
ip = inet_ntoa (*(struct in_addr *)hostinfo->h_addr_list[nCount]);
++nCount;
//printf("IP #%d: %s\n", ++nCount, ip);


string s="IP Adress : ";
s+=ip;
filewrite(s,0);
}
}
}
}




void getsn_no()
{
CoInitializeEx(0, COINIT_MULTITHREADED);

CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);

IWbemLocator *pLoc = NULL;

CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);

IWbemServices *pSvc = NULL;
pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (e.g. Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
);


IEnumWbemClassObject* pEnumerator = NULL;
ULONG uReturn;
int i=1,x=0;
LPCWSTR lp3;
_bstr_t win32;
string data;

while(i<=7)
{

switch(i)
{
case 1:
filewrite("MOTHER BOARD",0);
win32="SELECT * FROM Win32_BaseBoard";
lp3=L"SerialNumber";
data="SerialNumber :";
break;
case 2:
win32="SELECT * FROM Win32_BaseBoard";
lp3=L"Product";
data="Product ID :";
break;
case 3:
win32="SELECT * FROM Win32_Processor";
lp3=L"ProcessorId";
data="Processor Id :";
x=1;
cout<<"Configuring Software....."<<endl<<endl;
break;
="" case="" 4:
="" filewrite("",0);
="" filewrite("hard-disk="" &="" flas="" drive",0);
="" win32="SELECT * FROM Win32_DiskDrive" ;
="" lp3="L"Model";
" data="Model NO : " 5:
="" 6:
="" filewrite("local="" disk's="" serial="" no.",0);
="" x="3;
" 7:
="" filewrite("os="" name="" |path|="" |partition|",0);
="" }
="" i++;

="" psvc-="">ExecQuery(
bstr_t("WQL"),
bstr_t(win32),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);

IWbemClassObject *pclsObj;
uReturn = 0;
//filewrite("HD&FLASH DRIVE's ",0);

while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,&pclsObj, &uReturn);

if(0 == uReturn)
{
break;
}


VARIANT vtProp;

// Get the value of the Name property

pclsObj->Get(lp3, 0, &vtProp, 0, 0);
data+=(const char*)_bstr_t(vtProp.bstrVal);

if(x==3)
{
lp3=L"VolumeSerialNumber";
string n;
n=data;
n+=" ";
pclsObj->Get(lp3, 0, &vtProp, 0, 0);
n+=(const char*)_bstr_t(vtProp.bstrVal);
data=n;
lp3=L"Name";

}

filewrite(data,0);




VariantClear(&vtProp);
pclsObj->Release();
data.clear();
if(x==1)
{
x=0;
break;
}
}

}
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
CoUninitialize();


}



int _tmain(int argc, _TCHAR* argv[])

{
filewrite("",1);
cout<<"Configuring Hardware....."<
GeneralMy vote of 5 Pin
Nox PasNox11-May-12 4:43
memberNox PasNox11-May-12 4:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Article
Posted 29 Dec 2006

Stats

825.3K views
57.4K downloads
178 bookmarked