www.pudn.com > ComputerInfo.rar > DiskSerialNumber.cpp, change:2005-12-28,size:18557b


// DiskSerialNumber.cpp: implementation of the CDiskSerialNumber class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "DiskSerialNumber.h" 
 
#include <winioctl.h> 
 
//(*Output Bbuffer for the VxD (rt_IdeDinfo record)*) 
typedef struct _rt_IdeDInfo_ 
{ 
    BYTE IDEExists[4]; 
    BYTE DiskExists[8]; 
    WORD DisksRawInfo[8*256]; 
} rt_IdeDInfo, *pt_IdeDInfo; 
 
#define  IDENTIFY_BUFFER_SIZE  512 
 
//IOCTL commands 
#define  DFP_GET_VERSION          0x00074080 
#define  DFP_SEND_DRIVE_COMMAND   0x0007c084 
#define  DFP_RECEIVE_DRIVE_DATA   0x0007c088 
 
//Valid values for the bCommandReg member of IDEREGS. 
#define  IDE_ATAPI_IDENTIFY  0xA1  //  Returns ID sector for ATAPI. 
#define  IDE_ATA_IDENTIFY    0xEC  //  Returns ID sector for ATA. 
 
//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; 
 
////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; 
// 
////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; 
// 
////Structure returned by PhysicalDrive IOCTL for several commands 
//typedef struct _SENDCMDOUTPARAMS 
//{ 
//	DWORD         cBufferSize;   //  Size of bBuffer in bytes 
//	DRIVERSTATUS  DriverStatus;  //  Driver status structure. 
//	BYTE          bBuffer[1];    //  Buffer of arbitrary length in which to store the data read from the drive. 
//} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS; 
 
#define SENDIDLENGTH	sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE 
 
#define  FILE_DEVICE_SCSI              0x0000001b 
#define  IOCTL_SCSI_MINIPORT_IDENTIFY  ((FILE_DEVICE_SCSI << 16) + 0x0501) 
#define  IOCTL_SCSI_MINIPORT 0x0004D008  //  see NTDDSCSI.H for definition 
 
typedef struct _SRB_IO_CONTROL 
{ 
	ULONG HeaderLength; 
	UCHAR Signature[8]; 
	ULONG Timeout; 
	ULONG ControlCode; 
	ULONG ReturnCode; 
	ULONG Length; 
} SRB_IO_CONTROL, *PSRB_IO_CONTROL; 
 
//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    sSerialNumber[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; 
 
#define IOCTL_STORAGE_QUERY_PROPERTY   CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) 
#define IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0304, METHOD_BUFFERED, FILE_ANY_ACCESS) 
 
// Types of queries 
typedef enum _STORAGE_QUERY_TYPE { 
    PropertyStandardQuery = 0,				// Retrieves the descriptor 
		PropertyExistsQuery,                // Used to test whether the descriptor is supported 
		PropertyMaskQuery,                  // Used to retrieve a mask of writeable fields in the descriptor 
		PropertyQueryMaxDefined				// use to validate the value 
} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE; 
 
// define some initial property id's 
typedef enum _STORAGE_PROPERTY_ID { 
    StorageDeviceProperty = 0, 
		StorageAdapterProperty 
} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID; 
 
// Query structure - additional parameters for specific queries can follow the header 
typedef struct _STORAGE_PROPERTY_QUERY { 
    STORAGE_PROPERTY_ID PropertyId;		// ID of the property being retrieved 
    STORAGE_QUERY_TYPE QueryType;		// Flags indicating the type of query being performed 
    UCHAR AdditionalParameters[1];		// Space for additional parameters if necessary 
} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY; 
 
//typedef enum _STORAGE_BUS_TYPE { 
//    BusTypeUnknown = 0x00, 
//    BusTypeScsi, 
//    BusTypeAtapi, 
//    BusTypeAta, 
//    BusType1394, 
//    BusTypeSsa, 
//    BusTypeFibre, 
//    BusTypeUsb, 
//    BusTypeRAID, 
//    BusTypeMaxReserved = 0x7F 
//} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE; 
 
typedef struct _STORAGE_DEVICE_DESCRIPTOR { 
    // Sizeof(STORAGE_DEVICE_DESCRIPTOR) 
    ULONG Version; 
    // Total size of the descriptor, including the space for additional 
    // data and id strings 
    ULONG Size; 
    // The SCSI-2 device type 
    UCHAR DeviceType; 
    // The SCSI-2 device type modifier (if any) - this may be zero 
    UCHAR DeviceTypeModifier; 
    // Flag indicating whether the device's media (if any) is removable.  This 
    // field should be ignored for media-less devices 
    BOOLEAN RemovableMedia; 
    // Flag indicating whether the device can support mulitple outstanding 
    // commands.  The actual synchronization in this case is the responsibility 
    // of the port driver. 
    BOOLEAN CommandQueueing; 
    // Byte offset to the zero-terminated ascii string containing the device's 
    // vendor id string.  For devices with no such ID this will be zero 
    ULONG VendorIdOffset; 
    // Byte offset to the zero-terminated ascii string containing the device's 
    // product id string.  For devices with no such ID this will be zero 
    ULONG ProductIdOffset; 
    // Byte offset to the zero-terminated ascii string containing the device's 
    // product revision string.  For devices with no such string this will be 
    // zero 
    ULONG ProductRevisionOffset; 
    // Byte offset to the zero-terminated ascii string containing the device's 
    // serial number.  For devices with no serial number this will be zero 
    ULONG SerialNumberOffset; 
    // Contains the bus type (as defined above) of the device.  It should be 
    // used to interpret the raw device properties at the end of this structure 
    // (if any) 
    STORAGE_BUS_TYPE BusType; 
    // The number of bytes of bus-specific data which have been appended to 
    // this descriptor 
    ULONG RawPropertiesLength; 
    // Place holder for the first byte of the bus specific property data 
    UCHAR RawDeviceProperties[1]; 
} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR; 
 
typedef struct _MEDIA_SERAL_NUMBER_DATA { 
	ULONG  SerialNumberLength;  
	ULONG  Result; 
	ULONG  Reserved[2]; 
	UCHAR  SerialNumberData[1]; 
} MEDIA_SERIAL_NUMBER_DATA, *PMEDIA_SERIAL_NUMBER_DATA; 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CDiskSerialNumber::CDiskSerialNumber() 
{ 
	m_nSerialCount=0; 
} 
 
CDiskSerialNumber::~CDiskSerialNumber() 
{ 
 
} 
 
BOOL CDiskSerialNumber::GetFirstDiskSerial(LPSTR szDiskSerial) 
{ 
	m_nReadCount=0; 
		 
	OSVERSIONINFO version; 
	memset(&version,0,sizeof(version)); 
	version.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); 
	GetVersionEx(&version); 
	DWORD dwPlatform=version.dwPlatformId; 
	 
	BOOL done=FALSE; 
	if(VER_PLATFORM_WIN32_NT==dwPlatform) 
	{ 
		done=ReadPhysicalDriveInNTWithAdminRights(); 
 
		if(FALSE==done) 
			done=ReadIdeDriveAsScsiDriveInNT(); 
 
		if(FALSE==done) 
			done=ReadPhysicalDriveInNTWithZeroRights(); 
	} 
	else 
	{ 
		for(int i=0;i<10 && !done;i++) 
			done=ReadDrivePortsInWin9X(); 
	} 
 
	return GetNextDiskSerial(szDiskSerial); 
} 
 
BOOL CDiskSerialNumber::GetNextDiskSerial(LPSTR szDiskSerial) 
{ 
	if(m_nReadCount>=m_nSerialCount) 
		return FALSE; 
	else 
	{ 
		strcpy(szDiskSerial,m_szSerials[m_nReadCount++]); 
		return TRUE; 
	} 
} 
 
void CDiskSerialNumber::ConvertToString(LPSTR szDiskSerial, DWORD dwDiskData[], int nSize) 
{ 
	int position=0; 
	for(int i=0;i<nSize;i++) 
	{ 
		szDiskSerial[position]=(char)(dwDiskData[i]/256); 
		if(' '!=szDiskSerial[position])//不接受空格 
			position++; 
		szDiskSerial[position]=(char)(dwDiskData[i]%256); 
		if(' '!=szDiskSerial[position])//不接受空格 
			position++; 
	} 
	szDiskSerial[position]='\0'; 
} 
 
BOOL CDiskSerialNumber::ReadDrivePortsInWin9X() 
{ 
	BOOL done=FALSE; 
	//set the thread priority high so that we get exclusive access to the disk 
	SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS); 
 
	//1.Try to load the VxD 
	HANDLE hVxDHandle=CreateFile("\\\\.\\IDE21201.VXD",0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0); 
	if(hVxDHandle!=INVALID_HANDLE_VALUE) 
	{ 
		//2.Make an output buffer for the VxD 
		DWORD dwBytesReturned=0; 
		rt_IdeDInfo info; 
		pt_IdeDInfo pOutBufVxD=&info; 
		//WARNING!!! 
		//HAVE to zero out the buffer space for the IDE information! 
		//If this is NOT done then garbage could be in the memory 
		//locations indicating if a disk exists or not. 
		ZeroMemory(&info,sizeof(info)); 
 
		//3.Run VxD function 
		DeviceIoControl(hVxDHandle,1,0,0,pOutBufVxD,sizeof(pt_IdeDInfo),&dwBytesReturned,0); 
 
		//4.Unload VxD 
		CloseHandle(hVxDHandle); 
 
		//5.Translate and store data 
		for(int i=0;i<8;i++) 
		{ 
			if((pOutBufVxD->DiskExists[i]) && (pOutBufVxD->IDEExists[i/2])) 
			{ 
				//process the information for this buffer 
				DWORD dwDiskInfo[10]; 
				for(int j=10;j<20;j++)  
					dwDiskInfo[j-10]=pOutBufVxD->DisksRawInfo[i*256+j]; 
				 
				ConvertToString(m_szSerials[m_nSerialCount++],dwDiskInfo,10); 
			} 
		} 
 
		done=TRUE; 
	} 
 
	//reset the thread priority back to normal 
	SetPriorityClass(GetCurrentProcess(),NORMAL_PRIORITY_CLASS); 
 
	return done; 
} 
 
BOOL CDiskSerialNumber::ReadPhysicalDriveInNTWithAdminRights() 
{ 
	BOOL done=FALSE; 
 
	for(int i=0;i<16;i++) 
	{ 
		char driveName[256]; 
		sprintf(driveName,"\\\\.\\PhysicalDrive%d",i); 
 
		HANDLE hPhysicalDriveIOCTL=CreateFile(driveName, 
			GENERIC_READ|GENERIC_WRITE, 
			FILE_SHARE_READ|FILE_SHARE_WRITE,NULL, 
			OPEN_EXISTING,0,NULL); 
 
		if(hPhysicalDriveIOCTL!=INVALID_HANDLE_VALUE) 
		{ 
			GETVERSIONOUTPARAMS VersionParams; 
			DWORD cbBytesReturned=0; 
			memset((void*)&VersionParams,0,sizeof(VersionParams)); 
 
			if(DeviceIoControl(hPhysicalDriveIOCTL,DFP_GET_VERSION, 
				NULL,0,&VersionParams,sizeof(VersionParams), 
				&cbBytesReturned,NULL) && VersionParams.bIDEDeviceMap>0) 
			{ 
				// Now, get the ID sector for all IDE devices in the system. 
				// If the device is ATAPI use the IDE_ATAPI_IDENTIFY command, 
				// otherwise use the IDE_ATA_IDENTIFY command 
				BYTE IdOutCmd[sizeof(SENDCMDOUTPARAMS)+IDENTIFY_BUFFER_SIZE-1]; 
				BYTE bIDCmd=(VersionParams.bIDEDeviceMap>>i&0x10)?IDE_ATAPI_IDENTIFY:IDE_ATA_IDENTIFY; 
				SENDCMDINPARAMS scip; 
				memset(&scip,0,sizeof(scip)); 
				memset(IdOutCmd,0,sizeof(IdOutCmd)); 
 
				scip.cBufferSize=IDENTIFY_BUFFER_SIZE; 
				scip.irDriveRegs.bFeaturesReg=0; 
				scip.irDriveRegs.bSectorCountReg=1; 
				scip.irDriveRegs.bCylLowReg=0; 
				scip.irDriveRegs.bCylHighReg=0; 
				scip.irDriveRegs.bDriveHeadReg=0xA0|((i&1)<<4); 
				scip.irDriveRegs.bCommandReg=bIDCmd; 
				scip.bDriveNumber=i; 
				scip.cBufferSize=IDENTIFY_BUFFER_SIZE; 
 
				if(DeviceIoControl(hPhysicalDriveIOCTL,DFP_RECEIVE_DRIVE_DATA, 
								(LPVOID)&scip,sizeof(SENDCMDINPARAMS)-1, 
								(LPVOID)(PSENDCMDOUTPARAMS)&IdOutCmd, 
								sizeof(SENDCMDOUTPARAMS)+IDENTIFY_BUFFER_SIZE-1, 
								&cbBytesReturned,NULL)) 
				{ 
					//process the information for this buffer 
					DWORD dwDiskInfo[10]; 
					USHORT *pIdSector=(USHORT*)((PSENDCMDOUTPARAMS)IdOutCmd)->bBuffer; 
					 
					for(int j=10;j<20;j++)  
						dwDiskInfo[j-10]=pIdSector[j]; 
 
					ConvertToString(m_szSerials[m_nSerialCount++],dwDiskInfo,10); 
 
					done = TRUE; 
				} 
			} 
 
			CloseHandle(hPhysicalDriveIOCTL); 
		} 
	} 
 
	return done; 
} 
 
BOOL CDiskSerialNumber::ReadIdeDriveAsScsiDriveInNT() 
{ 
	int done=FALSE; 
	 
	for(int i=0;i<16;i++) 
	{ 
		char driveName[256]; 
		sprintf(driveName,"\\\\.\\Scsi%d:",i); 
 
		HANDLE hScsiDriveIOCTL=CreateFile(driveName, 
			GENERIC_READ|GENERIC_WRITE, 
			FILE_SHARE_READ|FILE_SHARE_WRITE,NULL, 
			OPEN_EXISTING,0,NULL); 
 
		if(hScsiDriveIOCTL!=INVALID_HANDLE_VALUE) 
		{ 
			for(int j=0;j<2;j++) 
			{ 
				char buffer[sizeof(SRB_IO_CONTROL)+SENDIDLENGTH]; 
				SRB_IO_CONTROL *p=(SRB_IO_CONTROL*)buffer; 
				SENDCMDINPARAMS *pin=(SENDCMDINPARAMS*)(buffer+sizeof(SRB_IO_CONTROL)); 
				DWORD dummy; 
 
				memset(buffer,0,sizeof(buffer)); 
				p->HeaderLength=sizeof(SRB_IO_CONTROL); 
				p->Timeout=10000; 
				p->Length=SENDIDLENGTH; 
				p->ControlCode=IOCTL_SCSI_MINIPORT_IDENTIFY; 
				strncpy((char*)p->Signature,"SCSIDISK",8); 
 
				pin->irDriveRegs.bCommandReg=IDE_ATA_IDENTIFY; 
				pin->bDriveNumber=j; 
 
				if(DeviceIoControl(hScsiDriveIOCTL,IOCTL_SCSI_MINIPORT, 
					buffer,sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1, 
					buffer,sizeof(SRB_IO_CONTROL)+SENDIDLENGTH,&dummy,NULL)) 
				{ 
					SENDCMDOUTPARAMS *pOut=(SENDCMDOUTPARAMS*)(buffer+sizeof(SRB_IO_CONTROL)); 
					IDSECTOR *pId=(IDSECTOR*)(pOut->bBuffer); 
					if(pId->sModelNumber[0]) 
					{												 
						//process the information for this buffer 
						DWORD dwDiskInfo[10]; 
						USHORT *pIdSector=(USHORT*)pId; 
						 
						for(int k=10;k<20;k++)  
							dwDiskInfo[k-10]=pIdSector[k]; 
 
						ConvertToString(m_szSerials[m_nSerialCount++],dwDiskInfo,10); 
 
						done=TRUE; 
					} 
				} 
			} 
 
			CloseHandle(hScsiDriveIOCTL); 
		} 
	} 
 
	return done; 
} 
 
BOOL CDiskSerialNumber::ReadPhysicalDriveInNTWithZeroRights() 
{ 
	BOOL done=FALSE; 
 
	for(int i=0;i<16;i++) 
	{ 
		char driveName[256]; 
		sprintf(driveName,"\\\\.\\PhysicalDrive%d",i); 
 
		HANDLE hPhysicalDriveIOCTL=CreateFile(driveName,0, 
			FILE_SHARE_READ|FILE_SHARE_WRITE,NULL, 
			OPEN_EXISTING,0,NULL); 
 
		if(hPhysicalDriveIOCTL!=INVALID_HANDLE_VALUE) 
		{ 
			int nCurrentCount=m_nSerialCount; 
 
			STORAGE_PROPERTY_QUERY query; 
			DWORD cbBytesReturned=0; 
			char buffer[8192]; 
 
			memset((void *)&query,0,sizeof(query)); 
			query.PropertyId=StorageDeviceProperty; 
			query.QueryType=PropertyStandardQuery; 
			 
			memset(buffer,0,sizeof(buffer)); 
			if(DeviceIoControl(hPhysicalDriveIOCTL,IOCTL_STORAGE_QUERY_PROPERTY, 
				&query,sizeof(query),&buffer,sizeof(buffer),&cbBytesReturned,NULL)) 
			{ 
				STORAGE_DEVICE_DESCRIPTOR *descrip=(STORAGE_DEVICE_DESCRIPTOR*)&buffer; 
				 
				flipAndCodeBytes(m_szSerials[m_nSerialCount],&buffer[descrip->SerialNumberOffset]); 
				//serial number must be alphanumeric 
				if((isalnum(m_szSerials[m_nSerialCount][0])))//? || isalnum(m_szSerials[m_nSerialCount][19]) 
				{ 
					m_nSerialCount++; 
					done=TRUE; 
				} 
			} 
 
			if(nCurrentCount==m_nSerialCount) 
			{ 
				memset(buffer,0,sizeof(buffer)); 
				if(DeviceIoControl(hPhysicalDriveIOCTL,IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER, 
					NULL,0,&buffer,sizeof(buffer),&cbBytesReturned,NULL)) 
				{ 
					MEDIA_SERIAL_NUMBER_DATA *mediaSerialNumber=(MEDIA_SERIAL_NUMBER_DATA*)&buffer; 
					 
					fileBlankSpace(m_szSerials[m_nSerialCount],(char*)mediaSerialNumber->SerialNumberData); 
					//serial number must be alphanumeric 
					if((isalnum(m_szSerials[m_nSerialCount][0])))//? || isalnum(m_szSerials[m_nSerialCount][19]) 
					{ 
						m_nSerialCount++; 
						done=TRUE; 
					} 
				} 
			} 
 
			CloseHandle (hPhysicalDriveIOCTL); 
		} 
	} 
 
	return done; 
} 
 
void CDiskSerialNumber::flipAndCodeBytes(LPSTR result, LPCSTR str) 
{ 
	int num=strlen(str); 
	int position=0; 
	for(int i=0;i<num;i+=4) 
	{ 
		for(int j=1;j>=0;j--) 
		{ 
			int sum=0; 
			for(int k=0;k<2;k++) 
			{ 
				sum*=16; 
				switch(str[i+j*2+k]) 
				{ 
				case '0': sum += 0; break; 
				case '1': sum += 1; break; 
				case '2': sum += 2; break; 
				case '3': sum += 3; break; 
				case '4': sum += 4; break; 
				case '5': sum += 5; break; 
				case '6': sum += 6; break; 
				case '7': sum += 7; break; 
				case '8': sum += 8; break; 
				case '9': sum += 9; break; 
				case 'a': sum += 10; break; 
				case 'b': sum += 11; break; 
				case 'c': sum += 12; break; 
				case 'd': sum += 13; break; 
				case 'e': sum += 14; break; 
				case 'f': sum += 15; break; 
				case 'A': sum += 10; break; 
				case 'B': sum += 11; break; 
				case 'C': sum += 12; break; 
				case 'D': sum += 13; break; 
				case 'E': sum += 14; break; 
				case 'F': sum += 15; break; 
				} 
			} 
			if(sum>0 && ' '!=(char)sum) 
				result[position++]=(char)sum; 
		} 
	} 
 
	result[position]='\0'; 
} 
 
void CDiskSerialNumber::fileBlankSpace(LPSTR result, LPCSTR str) 
{ 
	int num=strlen(str); 
	int position=0; 
	for(int i=0;i<num;i+=4) 
	{ 
		if(' '!=str[i]) 
			result[position++]=str[i]; 
	} 
 
	result[position]='\0'; 
}