Step to UEFI (100)InstallProtocolInterface

前面介绍了很多“消费”Protocol的代码,这次试试自己生产一个 Protocol 试试。根据我的理解,产生的 protocol 可以挂接在任何的 Handle 上(DH 命令看到的都可以),提供服务的代码需要常驻内存,一般的 Application 是不会常驻内存的,驱动直接可以常驻内存。于是,我们实验编写一个驱动程序,使用 Load 来加载驱动产生自定义的 Protocol ,挂接在自身Image 的Handle上。
需要使用的主要服务是 InstallProtocolInterface,我们先看看它的定义和输入参数:

typedef
EFI_STATUS
(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE)(
  IN OUT EFI_HANDLE               *Handle,          //安装到哪个Handle上
  IN     EFI_GUID                 *Protocol,               //安装的Protocol 的名字
  IN     EFI_INTERFACE_TYPE       InterfaceType,  ,  //目前只有一种类型:EFI_NATIVE_INTERFACE
  IN     VOID                     *Interface                  //Protocol的实例
  );

 

实际上,代码中更加常见的是InstallMultipleProtocolInterfaces, 这是因为 “ Installs a protocol interface on a device handle. If the handle does not exist, it is created and added to the list of handles in the system. InstallMultipleProtocolInterfaces() performs more error checking than InstallProtocolInterface(), so it is recommended that InstallMultipleProtocolInterfaces() be used in place of InstallProtocolInterface()” 因此,我们代码中会使用 InstallMultipleProtocolInterfaces 而不是前面提到的 InstallProtocolInterface。

/**
  Installs one or more protocol interfaces into the boot services environment.

  @param[in, out]  Handle       The pointer to a handle to install the new protocol interfaces on,
                                or a pointer to NULL if a new handle is to be allocated.
  @param  ...                   A variable argument list containing pairs of protocol GUIDs and protocol
                                interfaces.

  @retval EFI_SUCCESS           All the protocol interface was installed.
  @retval EFI_OUT_OF_RESOURCES  There was not enough memory in pool to install all the protocols.
  @retval EFI_ALREADY_STARTED   A Device Path Protocol instance was passed in that is already present in
                                the handle database.
  @retval EFI_INVALID_PARAMETER Handle is NULL.
  @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle.

**/
typedef
EFI_STATUS
(EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES)(
  IN OUT EFI_HANDLE           *Handle,
  ...
  );

 

InstallMultipleProtocolInterfaces 服务支持一次性安装多个Protocol,所以接收的变量是可变数量的,看起来让人有眼晕的感觉。最简单的方法是照葫芦画瓢,我们在UDK2014的代码中找一下我们的“葫芦”。在MdeModulePkg中,有一个 PrintDxe,它会向系统中注册名称为Print2Protocol 的 Protocol。

先分析一下他的代码结构。主要文件有3个:

1. \MdeModulePkg\Universal\PrintDxe\PrintDxe.inf 可以看做是工程文件,特别注意,其中有用到gEfiPrint2ProtocolGuid 在 MdeModulePkg.dec 中有定义:

  ## Print protocol defines basic print functions to print the format unicode and ascii string.
  # Include/Protocol/Print2.h
  gEfiPrint2ProtocolGuid          = { 0xf05976ef, 0x83f1, 0x4f3d, { 0x86, 0x19, 0xf7, 0x59, 0x5d, 0x41, 0xe5, 0x38 } }

 

2 \MdeModulePkg\Universal\PrintDxe\Print.c 其中有这个 Protocol的实例,还有入口函数PrintEntryPoint。其中使用了InstallMultipleProtocolInterfaces 将mPrint2Protocol 安装到了mPrintThunkHandle(==0) 上面。

3. \MdeModulePkg\Include\Protocol\Print2.h 定义了提供的 Protocol 的结构。

struct _EFI_PRINT2_PROTOCOL {
  UNICODE_BS_PRINT                     UnicodeBSPrint;
  UNICODE_S_PRINT                      UnicodeSPrint;
  UNICODE_BS_PRINT_ASCII_FORMAT        UnicodeBSPrintAsciiFormat;
  UNICODE_S_PRINT_ASCII_FORMAT         UnicodeSPrintAsciiFormat;
  UNICODE_VALUE_TO_STRING              UnicodeValueToString;
  ASCII_BS_PRINT                       AsciiBSPrint;
  ASCII_S_PRINT                        AsciiSPrint;
  ASCII_BS_PRINT_UNICODE_FORMAT        AsciiBSPrintUnicodeFormat;
  ASCII_S_PRINT_UNICODE_FORMAT         AsciiSPrintUnicodeFormat;
  ASCII_VALUE_TO_STRING                AsciiValueToString;
};

 

更多的介绍可以在【参考1】中看到。
之后就可以尝试进行编译,需要在 MdeModulePkg.dec 中声明一次 gEfiPrint9ProtocolGuid ,注意我修改了GUID保证不会和原来的发生冲突。再在MdeModulePkg.dsc 中加入 PrintDxe.inf 加入的位置和我们之前编译过的GOP旋转驱动还有截图的驱动位置一样。

编译之后的结果可以直接在 NT32 模拟器下试验:
st1001
加载之后可以发现用 DH 命令列出当前的 Handle会多了一个image(如果我们再Load一次,那么还会多出来一个Image,我们的代码不完善,没有自动查找确认当前是否已经执行过一次的功能)
stu1002

我们编写一个简单的Application来调用这个 Protocol 测试:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include "Print9.h"

EFI_GUID gEfiPrint9ProtocolGuid =
		{ 0xf05976ef, 0x83f1, 0x4f3d, 
			{ 0x86, 0x19, 0xf7, 0x59, 
				0x5d, 0x41, 0xe5, 0x61 } };

							
extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
	EFI_PRINT9_PROTOCOL		*Print9Protocol;
	EFI_STATUS				Status;	
	CHAR16					*Buffer=L"12345678";
	// Search for the Print9 Protocol
    //
    Status = gBS->LocateProtocol(
      &gEfiPrint9ProtocolGuid,
      NULL,
      (VOID **)&Print9Protocol
     );
    if (EFI_ERROR(Status)) {
      Print9Protocol = NULL;
	  Print(L"Can't find Print9Protocol.\n");
	  return EFI_SUCCESS;
     }
	Print(L"Find Print9Protocol.\n"); 
	Print9Protocol->UnicodeSPrint(Buffer,8,L"%d",200);
	Print(L"%s\n",Buffer); 
	
	return EFI_SUCCESS;
}

 

运行结果:
stu1003
首先运行的时候找不到对应的 Protocol,需要Load一次,再次运行就可以正常运行了。
本文提到的完整代码下载:

pdt

printdriver

参考:
1. http://feishare.com/attachments/065_EFI%20Howto,%20%20%20%E6%B3%A8%E5%86%8C%EF%BC%8C%E5%8F%91%E5%B8%83%EF%BC%8C%E4%BD%BF%E7%94%A8%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84protocol.pdf EFI Howto ,注册,发布,使用自定义的protocol

USB 控制七段数码管(II)

换个免驱的方式。前面之所以能免驱动,是因为我走的是USB HID协议。除了这个,更常见的是USB Mass Storage协议,就是我们常见的U盘走的协议。对于这个协议在《圈圈教你玩USB》中有详细介绍。下面就讲一下如何把我这个设备移植到MSD协议上。

首先说一下Firmware设计上的改变。

驱动数码管同样使用之前HID中的那种,用一个Timer不断循环点亮每一个数码管。因此,在Main.c中加入Timer0的初始化和中断服务程序。它会按照zBuf中给出来的依次点亮四个数码管。

volatile uint8 zBuf[]={1,2,3,4}; //用来保存8字节的输出报告。

/********************************************************************
函数功能:定时器0初始化,用来做键盘扫描。
入口参数:无。
返    回:无。
备    注:无。
********************************************************************/
void InitTimer0(void)
{
 TMOD&=0xF0;
 TMOD|=0x01;
 ET0=1;
 TR0=1;
}

/********************************************************************
函数功能:定时器0中断处理。
入口参数:无。
返    回:无。
备    注:22.1184M晶体约5ms中断一次。
********************************************************************/
void Timer0Isr(void) interrupt 1
{ 
   static i=0; 

//定时器0重装,定时间隔为5ms,加15是为了修正重装所花费时间
//这个值可以通过软件仿真来确定,在这里设置断点,调整使两次运行
//时间差刚好为5ms即可。
 TH0=(65536-Fclk/1000/12*5+15)/256;	 
 TL0=(65536-Fclk/1000/12*5+15)%256;   // 

	P2=1 << i;
	P1=zBuf[i];
	i++;
	if (i==4) {i=0;}
}
/*******************************************************************/

 

PC对USB Mass Storage 设备传数据,使用的是 WRITE(10) 命令,具体的数据会在批量传输协议中的批量数据阶段传输给设备。具体对应在代码中 SCSI.C 中的 procScsiOutData 中,我们在这里将收到的输局赋值给 zBuf.

/********************************************************************
函数功能:处理输出数据。
入口参数:无。
返    回:无。
备    注:无。
********************************************************************/
void ProcScsiOutData(void)
{
 uint8 Len;
 int i;

 //读端点2数据
 Len=D12ReadEndpointBuffer(4,EP2_SIZE,Ep2Buffer);

 //LabzDebug_Start 
 zBuf[0]=Ep2Buffer[0]; zBuf[1]=Ep2Buffer[1]; zBuf[2]=Ep2Buffer[2]; zBuf[3]=Ep2Buffer[3];

  PrintHex(zBuf[0]);
  PrintHex(zBuf[1]);
  PrintHex(zBuf[2]);
  PrintHex(zBuf[3]);
  Prints("\r\n");

 #ifdef DEBUG1
 Prints("收到 \r\n");
 for ( i=0; i <4;i++)
 {
  PrintHex(*(Ep2Buffer+i));  //如果需要显示调试信息,则显示发送的数据
  if(((i+1)%16)==0)Prints("\r\n"); //每16字节换行一次
  PrintHex(zBuf[0]);
  PrintHex(zBuf[1]);
  PrintHex(zBuf[2]);
  PrintHex(zBuf[3]);
  if((Len%16)!=0)Prints("\r\n"); //换行
 }
 #endif
 //LabZDebug_End
 Ep2DataLength-=Len;
 //清除端点缓冲区
 D12ClearBuffer();
 //由于没有存储器,这里将缓冲区清0模拟数据处理
 while(Len)
 {
  Ep2Buffer[Len]=0; //缓冲区清0
  Len--;
 }
 
 //数据传输完毕,进入到状态阶段
 if(Ep2DataLength==0)
 {
  //此时Ep2DataLength为0,并且处于数据阶段,调用发送数据函数将返回CSW
  Ep2SendData();
 }
}

 

只要做这一点Change,Firmware即可支持。

其次说一下上位机程序的设计。

因为模拟成一个U盘,因此,按照访问硬盘的方式即可传输数据。先是使用CreateFile打开PhysicalDriverX (特别注意:从PhysicalDriver0开始),之后就用 WriteFile 进行写入,特别注意,写入的最小单位是512字节,不能小于这个值。最后CloseHandle关闭即可。

最初,程序设计出来是这样的

CreateFile(PhysicalDrive3)

while Keypressed=false
{
WriteFile (512 Byte)
}

CloseHandle

结果发现非常奇怪,只有第一次能够顺利写入512Bytes,之后会不断出现 Error 5 ERROR_ACCESS_DENIED 5 (0x5) Access is denied. 的问题。为了防止是我设备不稳定造成的,我还用一个U盘进行试验(特别注意,操作会导致U盘内容不可读!!!)在Windows 7 x64和WindowsXP 32 都有同样的现象。请教天杀,他回复“想起来了,Win7的确有这个问题,可以写分区表,但是不能写后续的分区位置,是会被拒绝的。要写数据必须通过分区去写,或者将分区删除。你可以把设备识别成USB HDD,然后没有分区,这样应该可以全盘去写。如果是没有分区的那种U盘形式,是可能会被禁止写入的。”

这样的话,第一个方案就出来了,每次都要用CreateFile打开硬盘,写入之后再Close。

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>

int main(int argc, char *argv[])
{
   HANDLE hFile;
   BOOL fSuccess;
   char txchar[512];
   DWORD iBytesWritten;
   byte Seven_Dig[10]={   0x40,  // = 0
						  0x79,  // = 1	
						  0x24,  // = 2
						  0x30,  // = 3
                          0x19,  // = 4	
						  0x12,  // = 5
						  0x02,  // = 6
                          0x78,  // = 7	
						  0x00,  // = 8
						  0x10,  // = 9
                             }; 



 int n=1234;	
 while (kbhit()==0)
  {
	  hFile = CreateFile(L"\\\\.\\PhysicalDrive2",
                    GENERIC_WRITE,
                    FILE_SHARE_WRITE,    // must be opened with exclusive-access
                    NULL, // no security attributes
                    OPEN_EXISTING, // must use OPEN_EXISTING
                    0,    // not overlapped I/O
                    NULL  // hTemplate must be NULL for comm devices
                    );

   if (hFile == INVALID_HANDLE_VALUE) 
   {
       // Handle the error.
        printf ("CreateFile failed with error %d.\n", GetLastError());
		system("PAUSE");
        return (1);
   }

   txchar[0]=Seven_Dig[n / 1000 % 10];
   txchar[1]=Seven_Dig[n / 100 % 10];
   txchar[2]=Seven_Dig[n / 10 % 10];
   txchar[3]=Seven_Dig[n %10];
								
  for (int i=1;i<512 /4;i++) 
   {
 txchar[i*4]=txchar[0];
 txchar[i*4+1]=txchar[1];
  txchar[i*4+2]=txchar[2];
  txchar[i*4+3]=txchar[3];
   }

fSuccess=WriteFile(hFile, &txchar, 512, &iBytesWritten,NULL);
printf ("done send %d bytes.Status [%d] \n", iBytesWritten,fSuccess);
printf ("Get lasterror %d\n", GetLastError());
printf("%d \n",n);

n=(n++)%10000;
FlushFileBuffers(hFile);
Sleep(1000);
 CloseHandle(hFile);
}//while (kbhit()==0)

   system("PAUSE");


   return (0);
}

 

第二个方案就是每次用WriteFile写入之后,我们再重置指针,再从最开始写入。类似下面的方案。

CreateFile(PhysicalDrive3)

while Keypressed=false
{
SetFilePointer(hFile,0,0,FILE_BEGIN);
WriteFile (512 Byte)
}

CloseHandle

实际的效果和之前的HID的方式相同。

Firmware下载 USB7SegFW

第一种上位机程序下载
exp1

第二种上位机程序下载
exp2

通过WriteFile对硬盘发送数据

下面这个程序首先用 CreateFile 打开 PhysicalDiskX 然后使用 CreateFile 向里面写入数据。

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <conio.h>

int main(int argc, char *argv[])
{
   HANDLE hFile;
   BOOL fSuccess;
   char txchar[512];
   DWORD iBytesWritten;

   hFile = CreateFile(L"\\\\.\\PhysicalDrive1",
                    GENERIC_WRITE,
                    FILE_SHARE_WRITE,    // must be opened with exclusive-access
                    NULL, // no security attributes
                    OPEN_EXISTING, // must use OPEN_EXISTING
                    0,    // not overlapped I/O
                    NULL  // hTemplate must be NULL for comm devices
                    );

   if (hFile == INVALID_HANDLE_VALUE) 
   {
       // Handle the error.
        printf ("CreateFile failed with error %d.\n", GetLastError());
		system("PAUSE");
        return (1);
   }

   txchar[0]='l'; txchar[1]='a';txchar[2]='b';txchar[3]='z';

   //有资料说用这个函数对磁盘写的最小值是 512 bytes 我实验了一下如果小于此会出现error
   fSuccess=WriteFile(hFile, &txchar, 512, &iBytesWritten,NULL);
   printf ("done send %d bytes.Status [%d] \n", iBytesWritten,fSuccess,iBytesWritten);
   printf ("Get lasterror %d\n", GetLastError());

   system("PAUSE");
   CloseHandle(hFile);

   return (0);
}

 

我的实验是在虚拟机中进行的。特别提醒:本次实验可能会损害你的数据,请务必小心。如果系统有安装杀毒软件,有可能被判定为病毒行为。实验的目标盘是一个U盘,盘符为 G:

a

之后,先用 Winhex 打开,我们可以看到开始的几个字符是 abcd

b

运行我们的程序(可以看到发送 512 Bytes Status=1 表示 Success GetLastError=0 表示无错误)
c

我们需要重新打开一次硬盘(WinHex有磁盘修改感知功能,但是在这里不好用)
e

我们可以看到最开始的几个字符被修改了,这说明我们的程序是由效果的的。
d

完整的程序下载:

sendbywritefile

参考:

1.http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx MSDN WriteFile function

2.http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx MSDN System Error 对于确定 GetLastError 返回值很有用

3.http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx MSDN CreateFile function

给USB HID设备发送数据

image

《圈圈教你玩USB》 第五章 提到可以自己设计一个HID设备,于是,进行实验,刷新他的 Firmware 运行他的测试程序,在 Win7 3和64 下都不需要安装驱动程序,直接使用应用程序即可。

usb0device

《圈圈教你玩USB》 第五章 带的 Firmware 程序和Windows下的应用程序:

用户自定义HID设备上位机应用程序及源代码包

用户自定义HID设备下位机固件源代码包

自己动手直接编写一个 VS2008 程序来对这个设备发送数据(主要是我一直没法再 VS2008下成功编译他的Application)

//http://blog.csdn.net/xuxinhua/article/details/6329182
#include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <setupapi.h>
extern "C" {
void __stdcall
HidD_GetHidGuid (
   OUT   LPGUID   HidGuid
   );
typedef struct _HIDD_ATTRIBUTES {
    ULONG   Size; // = sizeof (struct _HIDD_ATTRIBUTES)

    //
    // Vendor ids of this hid device
    //
    USHORT  VendorID;
    USHORT  ProductID;
    USHORT  VersionNumber;

    //
    // Additional fields will be added to the end of this structure.
    //
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;

BOOLEAN __stdcall
HidD_GetAttributes (
    IN  HANDLE              HidDeviceObject,
    OUT PHIDD_ATTRIBUTES    Attributes
    );
}

#pragma comment( lib, "hid.lib" )
#pragma comment( lib, "setupapi.lib" )

int main(array<System::String ^> ^args)
{
	 GUID HidGuid;
	 BOOL Result;

	//获取HID设备的接口类GUDI
		HidD_GetHidGuid(&HidGuid);
	//输出一下看看GUID
		printf("HID GUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n"
		   , HidGuid.Data1, HidGuid.Data2, HidGuid.Data3
		   , HidGuid.Data4[0], HidGuid.Data4[1], HidGuid.Data4[2], HidGuid.Data4[3], HidGuid.Data4[4]
		   , HidGuid.Data4[5], HidGuid.Data4[6], HidGuid.Data4[7] );
	
	//根据获得的GUID枚举HID设备
	HDEVINFO hDevInfo = SetupDiGetClassDevs( &HidGuid, NULL, 0, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE );
    if( INVALID_HANDLE_VALUE != hDevInfo )
    {
        SP_DEVICE_INTERFACE_DATA strtInterfaceData = { sizeof(SP_DEVICE_INTERFACE_DATA) };
        for( DWORD index=0; SetupDiEnumDeviceInterfaces(hDevInfo,NULL,&HidGuid,index,&strtInterfaceData); ++index )
        {
            char buf[1000];
            SP_DEVICE_INTERFACE_DETAIL_DATA& strtDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA&)buf[0];
            strtDetailData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
            if( SetupDiGetDeviceInterfaceDetail(hDevInfo,&strtInterfaceData,&strtDetailData,_countof(buf),NULL,NULL) )
            {
                printf("[%d] path: %ls\n", index, strtDetailData.DevicePath);
				
				//这里打开的有可能是USB键盘鼠标这样比较特别的设备(只能查询)
                HANDLE hUsb = CreateFile( strtDetailData.DevicePath, 
							NULL, FILE_SHARE_WRITE, 
							NULL, OPEN_EXISTING, 
							FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 
							NULL );
	
                // 查询设备标识
                HIDD_ATTRIBUTES strtAttrib = { sizeof(HIDD_ATTRIBUTES) };
				Result=HidD_GetAttributes(hUsb,&strtAttrib);
                
				//所以这里要关闭一下,后面找到我们自己的设备确定可以写入再打开一次
			    CloseHandle( hUsb );
                
				if(TRUE==Result)
                    {
						if ((0x8888==strtAttrib.VendorID) && 
						   (0x6==strtAttrib.ProductID))	//找到我们自己的设备
						     {
								printf("VendorID : %hX\n", strtAttrib.VendorID );
								printf("ProductID: %hX\n", strtAttrib.ProductID );
								printf("VerNumber: %hX\n", strtAttrib.VersionNumber );
	
								//确定是我们自己的设备,再打开一次,注意我们这里使用的是同步发送
								hUsb = CreateFile( strtDetailData.DevicePath, 
												   GENERIC_WRITE, FILE_SHARE_WRITE, 
												   NULL, OPEN_EXISTING, 
												   FILE_ATTRIBUTE_NORMAL, NULL );
		
								//发送报告的缓冲区,1字节报告ID+8字节报告数据。
								UCHAR WriteReportBuffer[9];
								DWORD lpNumberOfBytesWritten;
								UINT LastError;
									
								WriteReportBuffer[0]=0x00;
								WriteReportBuffer[1]=0x75;
									
								//调用WriteFile函数发送数据
								Result=WriteFile(hUsb,
												WriteReportBuffer,
											    9,
											    &lpNumberOfBytesWritten,
										       	NULL);
								//如果函数返回失败,则可能是真的失败,也可能是IO挂起
								if(Result==FALSE)
										{
											//获取最后错误代码
												LastError=GetLastError();
											//看是否是真的IO挂		
												if((LastError==ERROR_IO_PENDING)||(LastError==ERROR_SUCCESS))
													{ return TRUE;	}
												//否则,是函数调用时发生错误,显示错误代码
												else	
													{
														printf("Sending error:%d \n",LastError);
														//如果最后错误为1,说明该设备不支持该函数。
														if(LastError==1)
														{printf("This device doesn't support WriteFile function \n");}
													}


										}

                				CloseHandle( hUsb );
								}//if ((0x8888==strtAttrib.VendorID) && 
					}		//if(TRUE==Result)
            }	// if( SetupDiGetDeviceInterfaceDetail(hDevInfo,&strtInterfaceData,&strtDetailData,_countof(buf),NULL,NULL) )

        }	//for( DWORD index=0;
        
		if( GetLastError() != ERROR_NO_MORE_ITEMS )
			{printf("No more items!\n"); }

        SetupDiDestroyDeviceInfoList( hDevInfo );
    }	//if( INVALID_HANDLE_VALUE != hDevInfo )

	system("PAUSE");
    return 0;
}

 

运行结果:

usb0

程序下载

HidSend

枚举当前系统中硬盘的方法(1)

枚举的结果是 "\\.\PhysicalDriveX"这样的形式。

需要注意的是:程序必须在 Administrator 权限下运行。即运行时,要求 "Run as Administrator"。同样在VS2008中编译时,由于权限不够,可能无法看到运行结果。本程序使用的是最传统的方法,使用CreateFile尝试不同的 PhysicalDirve+Number如果能够打开就是存在的。

#include "stdafx.h"
#include   <windows.h>   
#include   <stdio.h>   
#include   <conio.h> 

int _tmain(int argc, _TCHAR* argv[])
{
	int    i;
	TCHAR  Device[0x20];
	HANDLE hDevice;

	for (i=0;i<10;i++)

	{
		wsprintf(Device,TEXT("\\\\.\\PhysicalDrive%d"), i);
		
		hDevice = CreateFile(Device, 
						GENERIC_READ,
						FILE_SHARE_READ, 
						NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);

		if (hDevice!=INVALID_HANDLE_VALUE) {printf("%ws \n",Device); }
		CloseHandle( hDevice );   
	}



	_getch(); 
	return 0;
}

 

phylist1