Главная > Программирование, системное > WinAPI: Определение типа носителя и его серийного номера.

WinAPI: Определение типа носителя и его серийного номера.

Иногда в программах необходимо использовать возможность проверки типа носителя или его серийный номер. Причины могут быть разными от банального контроля устройств в системе до средств защит использующих привязку к железу. Сейчас я вам покажу как с помощью API реализовать эту простую задачу.

Нам понадобится всего 2 API - функции:

  • GetDriveType - определяет и возвращает тип носителя;
  • GetVolumeInformation - определяет информацию о носителе,  среди которой содержится серийный номер.

Рассмотрим описание этих функций для С++ и Delphi. Первой будет функция GetDriveType, она очень простая и использует всего один параметр - указатель на том. Например "c:\","a:\" и т.д. Функция возвращает одно из следующих значений:

DRIVE_UNKNOWN - 0 : диск неопределен/не существует

DRIVE_NO_ROOT_DIR - 1 : неверный путь/ путь не указывает на том

DRIVE_REMOVABLE - 2 : тип устройства определяется как съемный (дискета, флешка и т.д.)

DRIVE_FIXED - 3 : тип устройства - фиксированный диск (жесткий диск)

DRIVE_REMOTE - 4 : тип устройства - удаленный(сетевой) диск

DRIVE_CDROM - 5 : это устройство CD-ROM

DRIVE_RAMDISK - 6 : виртуальный диск, созданный в оперативной памяти

C/C++


UINT WINAPI GetDriveType(
LPCTSTR lpRootPathName //путь к диску
);


function GetDriveType(
lpRootPathName: PChar //путь к диску
): UINT; stdcall;

Замечание: Если в качестве параметра указать для С/С++ NULL, а для Delphi - nil то тип устройства будет определяться для текущего диска (с которого была запущена программа).

А теперь взглянем на функцию GetVolumeInformation. Тоже достаточно простая функция, однако использует параметров значительно больше.
C/C++


BOOL WINAPI GetVolumeInformation(
LPCTSTR lpRootPathName, //путь к сетевому или локальному
// тому (пример: "\\MyServer\MyShare\" или "C:\".
 LPTSTR lpVolumeNameBuffer, //буфер - в котором будет храниться
// имя тома
DWORD nVolumeNameSize, //размер буфера
LPDWORD lpVolumeSerialNumber, //серийный номер тома
LPDWORD lpMaximumComponentLength, //размер тома
LPDWORD lpFileSystemFlags, //тип файловой системы
LPTSTR lpFileSystemNameBuffer, //название файловой системы
DWORD nFileSystemNameSize //размер буфера под название ФС
);

Delphi


function GetVolumeInformation(
lpRootPathName: PChar; //путь к сетевому или локальному
 //тому (пример: "\\MyServer\MyShare\" или "C:\".
 lpVolumeNameBuffer: PChar; //буфер - в котором будет храниться
// имя тома
nVolumeNameSize: DWORD; //размер буфера
lpVolumeSerialNumber: PDWORD; //серийный номер тома
var lpMaximumComponentLength, lpFileSystemFlags: DWORD; //размер
// тома и тип файловой системы
lpFileSystemNameBuffer: PChar; //название файловой системы
nFileSystemNameSize: DWORD //размер буфера под название ФС
): BOOL; stdcall;

Замечание: Если в качестве первого параметра указать для С/С++  NULL, а для Delphi - nil то функция будет выполняется для текущего диска (с которого была запущена программа).
Ну а теперь собственно для пущего интересу приведу пример, как привязать программу к устройству. В данном примере будем привязывать программу к флешке. Смотрим пример:
C/C++


#include
#include
#include
#include
using namespace std;

int main() {
// Получаем тип носителя с которого запущена программа
unsigned int drive_type = GetDriveType( NULL );

char VolumeNameBuffer[100];
char FileSystemNameBuffer[100];
DWORD sz,fs;
unsigned long drive_sn;
GetVolumeInformationA(
NULL,
VolumeNameBuffer,
100,
&drive_sn,
sz,
fs,
FileSystemNameBuffer,
100
);
cout << "Volume serial number:\t";
if(drive_sn == 1018821877) //сравниваем серийный номер
cout << "correct" << endl;
else
cout << "invalid" << endl;
cout << "Drive type:\t";
if(drive_type == DRIVE_REMOVABLE)
cout << "correct" << endl;
else
cout << "invalid" << endl;
getch();
}

Delphi

program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils,windows;

var
SerialNum,dtyp:DWORD;
a,b:DWORD;
Buffer,disk :Array[0..255]of char;
begin
dtyp:=GetDriveType(nil);
if dtyp = DRIVE_REMOVABLE then
writeln('Disk(type): Yes')
else
writeln('Disk(type): No');
GetVolumeInformation(
nil,
Buffer,
sizeof(Buffer),
@SerialNum,
a,
b,
nil,
0);
if SerialNum = 1018821877 then //сравниваем серийный номер
writeln('S\N: Yes')
else
writeln('S\N: No');
readln;
end.

Замечание: Может возникнуть вопрос, а как узнать серийник диска, чтобы знать с чем сравнивать? Очень просто, для этого пишем тестовую прогу, в которой пишем следующий код:
C/C++


...
GetVolumeInformationA(NULL, VolumeNameBuffer,100,
&drive_sn,sz,fs,FileSystemNameBuffer,100);
...

Delphi


...
GetVolumeInformation(nil,Buffer,sizeof(Buffer),
@SerialNum, a,b, nil, 0);
writeln('S/N drive: ',SerialNum);
readln;
...

Рекомендуемые статьи для прочтения:
WinAPI: Смена серийного номера тома.

Пожалуйста, оцените полезность и качество данной статьи. Одна звезда - плохо, 5 - хорошо.
1/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.2/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.3/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.4/5.5/5. (6 голосов, средний: 5,00 из 5)
Загрузка...
  1. Zero
    29 января 2009 в 23:52 | #1

    Очень нужная вещь эта привязка. Спасибо коффи

  2. ex3me
    15 февраля 2009 в 15:47 | #2

    Автор, за статью респект. В частности за реализацию на Делфи ;)

  3. Alexey
    23 апреля 2009 в 13:43 | #3

    Не слишком поднодит для привязки. Поскольку этот серийник меняется при форматировании.
    Из описания GetVolumeInformation Function в MSDN :

    This function returns the volume serial number that the operating system assigns when a hard disk is formatted. To programmatically obtain the hard disk's serial number that the manufacturer assigns, use the Windows Management Instrumentation (WMI) Win32_PhysicalMedia property SerialNumber.

  4. C0ffe1n
    24 апреля 2009 в 23:27 | #4

    Не понимаю Alexey, как вы так пришли к этому выводу... Может вы не понимаете определения привязки? ... привязка представляет собой некоторую зависимость, при которой в данном случае будет запускаться/не запускаться программа. А от того что при форматировании сменился номер, фигово то тому кто отформатировал, потому что прога уже работать не будет(пока номер не сменить обратно) ;) ... но соглашусь в одном что данный пример привязки очень прост, и достаточно быстро обходиться =)

  5. lizz
    25 апреля 2009 в 17:04 | #5

    @C0ffe1n
    А что тут непонятного? "Поскольку этот серийник меняется при форматировании." - по моему, всё очевидно.

  1. Пока что нет уведомлений.