解决了
我正在使用 delphi 2009。我的程序会监听 USB 驱动器的连接和移除。在过去的一年里,我在 10 个应用程序中使用了非常相似的代码。它一直很完美。当我迁移时,我不得不放弃使用 thddinfo 来获取驱动器型号。这已被 WMI 取代。WMI 查询需要物理磁盘号,而我恰好在应用程序中已经有一个功能可以做到这一点。
当我测试时,我将它放在一个按钮中并运行它,它成功确定 psp 是物理驱动器 4 并返回模型(全部在调试器中检查,在另一个示例中使用显示消息):
function IsPSP(Drive: String):Boolean;
var
Model: String;
DriveNum: Byte;
begin
Result := False;
Delete(Drive, 2, MaxInt);
DriveNum := GetPhysicalDiskNumber(Drive[1]);
Model := (MagWmiGetDiskModel(DriveNum));
if Pos('PSP',Model) > 0 then Result := True;
end;
procedure TfrmMain.Button1Click(Sender: TObject);
var DriveNum: Byte;
begin
IsPSP('I');
end;
它工作得很好,直到我允许我使用了一年的 WMDeviceChange 调用 getphysicaldisknumber 和 wmi 查询语句。我自己试过了,它们都是一个问题。GetPhysicalDiskNumber 在逻辑磁盘上执行 CloseHandle 时冻结非常糟糕,但最终确实返回了数字。WMI 查询失败且没有错误,只是将“调试器点”返回到从未发生连接的 wbemscripting_tlb 中。请记住,一年中唯一改变的是我调用什么来获取我正在使用 api 调用的模型,而现在我正在使用其他东西。
以下是此时涉及的其余代码,没有上面显示的 ispsp:
procedure TfrmMain.WMDeviceChange(var Msg: TMessage);
var Drive: String;
begin
case Msg.wParam of
DBT_DeviceArrival: if PDevBroadcastHdr(Msg.lParam)^.dbcd_devicetype = DBT_DevTyp_Volume then
begin
Drive := GetDrive(PDevBroadcastVolume(Msg.lParam)) + '\';
OnDeviceInsert(Drive);
end;
DBT_DeviceRemoveComplete: if PDevBroadcastHdr(Msg.lParam)^.dbcd_devicetype = DBT_DevTyp_Volume then
begin
Drive := GetDrive(PDevBroadcastVolume(Msg.lParam)) + '\';
OnDeviceRemove(Drive);
end;
end;
end;
Procedure TfrmMain.OnDeviceInsert(Drive: String);
var PreviousIndex: Integer;
begin
if (getdrivetype(Pchar(Drive))=DRIVE_REMOVABLE) then
begin
PreviousIndex := cbxDriveList.Items.IndexOf(cbxDriveList.Text);
cbxDriveList.Items.Append(Drive);
if PreviousIndex = -1 then //If there was no drive to begin with then set index to 0
begin
PreviousIndex := 0;
cbxDriveList.ItemIndex := 0;
end;
if isPSP(Drive) then
begin
if MessageDlg('A PSP was detect @ ' + Drive + #10#13 + 'Would you like to select this drive?',mtWarning,[mbYes,mbNo], 0) = mrYes then
cbxDriveList.ItemIndex := cbxDriveList.Items.IndexOf(Drive)
else cbxDriveList.ItemIndex := PreviousIndex;
end
else if MessageDlg('USB Drive ' + Drive + ' Detected' + #10#13 + 'Is this your target drive?',mtWarning,[mbYes,mbNo], 0) = mrYes then
cbxDriveList.ItemIndex := cbxDriveList.Items.IndexOf(Drive)
else cbxDriveList.ItemIndex := PreviousIndex;
end;
end;
Procedure TfrmMain.OnDeviceRemove(Drive: String);
begin
if not (getdrivetype(Pchar(Drive)) = DRIVE_CDROM) then
begin
if cbxDriveList.Text = (Drive) then ShowMessage('The selected drive (' + Drive + ') has been removed');
cbxDriveList.Items.Delete(cbxDriveList.Items.IndexOf(Drive));
if cbxDriveList.Text = '' then cbxDriveList.ItemIndex := 0;
if Drive = PSPDrive then //Check Detect PSP and remove reference if its been removed
begin
PSPDrive := '';
end;
end;
end;
Rob 在下面说了一些关于我没有调用继承的消息处理程序的内容,我阅读了文档,我看到了一些我可以返回的东西......但我不确定我是否理解,但我会调查它。我不是一个非常好的 Pascal 程序员,但我学到了很多东西。到 2009 年的过渡也有一些困难。
USB 驱动器检测和所有这些都可以完美运行。如果我从 is psp 中删除这两个东西,那么用户会立即用 wis this yourwhat 向用户致意,并将 I:\ 添加到列表中。它只是在应用程序中发生变化的两个新事物在被 wmdevicechange 调用时失败,并且正如在它们自己工作之前所说的那样。
编辑 - 已解决
好吧,我按照建议使用计时器,问题似乎已经解决。需要注意的是,在 wmdevicechange 获取物理磁盘号后不久被计时器调用时,它似乎仍然很慢。我将此归因于仍连接到系统的设备。
在那张纸条上,我经常使用 P2 450。我将 PSP 和应用程序连接到一台 1.8Ghz 双核笔记本电脑,程序检测到 psp 并很快通知用户。因此,除非在非常慢的计算机上,否则该应用程序不会冻结,并且在这种缓慢的 onw 上它只会持续几秒钟,并且不会影响程序的运行,尽管不是很酷。但我觉得所有现代计算机都会快速运行检测,特别是因为它们可以更快地连接设备。