在Delphi 7中,我正在开发一个实现一个对象的库,该对象封装了有关连接到系统的电池的信息.除了检索电池的序列号外,它运行良好.
- function TBattery.GetSerialNumber(hbat: THandle): boolean;
- var
- bqi: TBatteryQueryInformation;
- Serial: PWideChar;
- SerialSize,dwOut: DWORD;
- begin
- Result := False;
- if hbat <> INVALID_HANDLE_VALUE then
- begin
- ZeroMemory(@bqi,SizeOf(bqi));
- dwOut := 0;
- bqi.BatteryTag := FBatteryTag;
- bqi.InformationLevel := BatterySerialNumber;
- SerialSize := 2048;
- GetMem(Serial,SerialSize);
- try
- ZeroMemory(Serial,SerialSize);
- Result := DeviceIoControl(hbat,IOCTL_BATTERY_QUERY_INFORMATION,@bqi,SizeOf(bqi),Serial,SerialSize,@dwOut,nil);
- if Result then
- FSerialNumber := Serial;
- finally
- FreeMem(Serial,SerialSize);
- end;
- end;
- end;
不幸的是,DeviceIoControl()总是返回False,如果我之后检查GetLastError(),那么它返回错误87,“参数不正确”.
这没有多大意义,因为如果我只是简单地将InformationLevel从BatterySerialNumber更改为BatteryUniqueID,那么代码的效果非常好.另外,我在GetSerialNumber之前的代码中的其他调用中使用了电池的句柄(hbat)并且它们都工作正常,并且在此之后我也可以调用其他调用,所以这不是问题.
有任何想法吗?我真的很茫然.
解决方法
这个问题似乎与dwOut变量有关,它以@dwOut的形式传递,这个变量代表
DeviceIoControl
的var lpBytesReturned参数,定义为
- function DeviceIoControl(hDevice: THandle; dwIoControlCode: DWORD; lpInBuffer: Pointer;
- nInBufferSize: DWORD; lpOutBuffer: Pointer; nOutBufferSize: DWORD;
- var lpBytesReturned: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
所以替换你的代码
- Result := DeviceIoControl(hbat,dwOut,nil);
必须解决问题.
WinAPI的
另请查看此msdn条目Enumerating Battery Devices
中转换为delphi的代码,它可以帮助您检测代码的任何其他问题.
- uses
- SetupApi,Windows,SysUtils;
- type
- BATTERY_QUERY_INFORMATION_LEVEL = (
- BatteryInformation,BatteryGranularityInformation,BatteryTemperature,BatteryEstimatedTime,BatteryDeviceName,BatteryManufactureDate,BatteryManufactureName,BatteryUniqueID,BatterySerialNumber);
- TBatteryQueryInformationLevel = BATTERY_QUERY_INFORMATION_LEVEL;
- _BATTERY_QUERY_INFORMATION = record
- BatteryTag: ULONG;
- InformationLevel: BATTERY_QUERY_INFORMATION_LEVEL;
- AtRate: Longint;
- end;
- BATTERY_QUERY_INFORMATION = _BATTERY_QUERY_INFORMATION;
- PBATTERY_QUERY_INFORMATION = ^BATTERY_QUERY_INFORMATION;
- TBatteryQueryInformation = BATTERY_QUERY_INFORMATION;
- const
- GUID_DEVCLASS_BATTERY:TGUID='{72631E54-78A4-11D0-BCF7-00AA00B7B32A}';
- //DEFINE_GUID( GUID_DEVCLASS_BATTERY,0x72631E54,0x78A4,0x11D0,0xBC,0xF7,0x00,0xAA,0xB7,0xB3,0x2A );
- METHOD_BUFFERED = 0;
- FILE_DEVICE_BATTERY = $00000029;
- FILE_READ_ACCESS = $0001; // for files and pipes
- IOCTL_BATTERY_QUERY_TAG =
- (FILE_DEVICE_BATTERY shl 16) or (FILE_READ_ACCESS shl 14) or ($10 shl 2) or (METHOD_BUFFERED);
- IOCTL_BATTERY_QUERY_INFORMATION =
- (FILE_DEVICE_BATTERY shl 16) or (FILE_READ_ACCESS shl 14) or ($11 shl 2) or (METHOD_BUFFERED);
- function GetBatteryInfo(InformationLevel : BATTERY_QUERY_INFORMATION_LEVEL) : string;
- var
- cbrequired : DWORD;
- hdev : HDEVINFO;
- idev : Integer;
- did : TSPDeviceInterfaceData;
- pdidd : PSPDeviceInterfaceDetailData;
- hBattery : THandle;
- bqi : TBatteryQueryInformation;
- dwWait,dwOut : DWORD;
- lpOutBuffer: PWideChar;
- begin
- // enumerate the batteries
- hdev := SetupDiGetClassDevs(@GUID_DEVCLASS_BATTERY,nil,DIGCF_PRESENT OR DIGCF_DEVICEINTERFACE);
- if ( INVALID_HANDLE_VALUE <> THandle(hdev) ) then
- begin
- idev:=0;//first battery
- ZeroMemory(@did,SizeOf(did));
- did.cbSize := SizeOf(did);
- if (SetupDiEnumDeviceInterfaces(hdev,GUID_DEVCLASS_BATTERY,idev,did)) then
- begin
- try
- cbrequired := 0;
- SetupDiGetDeviceInterfaceDetail(hdev,@did,cbrequired,nil);
- if (ERROR_INSUFFICIENT_BUFFER= GetLastError()) then
- begin
- pdidd:=AllocMem(cbrequired);
- try
- pdidd.cbSize := SizeOf(TSPDeviceInterfaceDetailData);
- if (SetupDiGetDeviceInterfaceDetail(hdev,pdidd,nil)) then
- begin
- hBattery :=CreateFile(pdidd.DevicePath,GENERIC_READ OR GENERIC_WRITE,FILE_SHARE_READ OR FILE_SHARE_WRITE,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
- if (INVALID_HANDLE_VALUE <> hBattery) then
- begin
- try
- ZeroMemory(@bqi,SizeOf(bqi));
- // With the tag,you can query the battery info.
- dwWait := 0;
- if (DeviceIoControl(hBattery,IOCTL_BATTERY_QUERY_TAG,@dwWait,sizeof(dwWait),@bqi.BatteryTag,sizeof(bqi.BatteryTag),nil)) then
- begin
- lpOutBuffer:=AllocMem(MAX_PATH);
- try
- ZeroMemory(lpOutBuffer,MAX_PATH);
- bqi.InformationLevel:=InformationLevel;
- if DeviceIoControl(hBattery,SizeOf(BATTERY_QUERY_INFORMATION),lpOutBuffer,255,nil) then
- Result:= WideCharToString(lpOutBuffer);
- finally
- FreeMem(lpOutBuffer);
- end;
- end;
- finally
- CloseHandle(hBattery)
- end;
- end;
- end;
- finally
- FreeMem(pdidd);
- end;
- end;
- finally
- SetupDiDestroyDeviceInfoList(hdev);
- end;
- end;
- end;
- end;
- begin
- try
- if not LoadsetupAPI then exit;
- Writeln(GetBatteryInfo(BatterySerialNumber));
- except
- on E: Exception do
- Writeln(E.ClassName,': ',E.Message);
- end;
- readln;
- end.
WMI
最后请注意,您可以使用WMI检索相同的信息,在本例中使用BatteryStaticData WMI类
- {$APPTYPE CONSOLE}
- uses
- SysUtils,ActiveX,ComObj,Variants;
- // Battery Static Data
- procedure GetBatteryStaticDataInfo;
- const
- WbemUser ='';
- WbemPassword ='';
- WbemComputer ='localhost';
- wbemFlagForwardOnly = $00000020;
- var
- FSWbemLocator : OLEVariant;
- FWMIService : OLEVariant;
- FWbemObjectSet: OLEVariant;
- FWbemObject : OLEVariant;
- oEnum : IEnumvariant;
- iValue : LongWord;
- begin;
- FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
- FWMIService := FSWbemLocator.ConnectServer(WbemComputer,'root\WMI',WbemUser,WbemPassword);
- FWbemObjectSet:= FWMIService.ExecQuery('SELECT SerialNumber FROM BatteryStaticData','WQL',wbemFlagForwardOnly);
- oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
- while oEnum.Next(1,FWbemObject,iValue) = 0 do
- begin
- Writeln(Format('SerialNumber %s',[String(FWbemObject.SerialNumber)]));// String
- Writeln('');
- FWbemObject:=Unassigned;
- end;
- end;
- begin
- try
- CoInitialize(nil);
- try
- GetBatteryStaticDataInfo;
- finally
- CoUninitialize;
- end;
- except
- on E:EOleException do
- Writeln(Format('EOleException %s %x',[E.Message,E.ErrorCode]));
- on E:Exception do
- Writeln(E.Classname,':',E.Message);
- end;
- Writeln('Press Enter to exit');
- Readln;
- end.