解决
我正在使用delphi 2009.我的程序侦听连接和删除的USB驱动器。在过去的一年里,我在10个应用程序中使用了非常相似的代码。它一直很完美。当我迁移时,我不得不放弃使用thddinfo来获得驱动器模型。这已被使用WMI取代。 WMI查询需要物理磁盘编号,我恰好在应用程序中已经有了一个功能。
当我测试时,我将它放在一个按钮中并运行它并成功确定psp是物理驱动器4并返回模型(所有在调试器中检查,在另一个示例中使用show message检查):
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已经在下面说了一些关于我没有调用继承的消息处理程序的东西,我已经阅读了文档,我看到了一些我可以返回的东西...但我不确定我理解但我会调查它。我不是一个非常好的帕斯卡程序员,但我一直在学习很多。向2009年的过渡也有一些粗糙的补丁。
USB驱动器检测功能完美无缺。如果我从psp中删除了两个东西,那么用户就会立刻受到欢迎,这就是你的任何东西,并将I:\添加到列表中。它只是在应用程序中发生变化的两个新事物,当它们被wmdevicechange调用时失败,并且在它们自己工作之前就已经说过了。
编辑 - 已解决
好吧我正在使用建议的计时器,问题似乎得到解决。需要注意的是,在wmdevicechange获取物理磁盘号后,很快就会被计时器调用。我将此归因于仍然连接到系统的设备。
关于那个注意我正常使用P2 450。我将PSP和应用程序连接到1.8Ghz双核笔记本电脑上,程序检测到了psp并且非常快地通知了用户。因此应用程序不会冻结,除非在一台非常非常慢的计算机上,并且这个慢速只能在几秒钟内完成,并且不会影响程序的运行,虽然不是很酷。但我觉得所有现代计算机都会快速运行检测,特别是因为它们可以更快地连接设备。
答案 0 :(得分:2)
您尚未在代码中说明“声明1”。
我对代码的某些部分有一些评论,这些评论可能与你遇到的问题有关,也可能没有。
首先,您在DriveNum
中为IsPSP
分配值,但不使用它。编译器应该发布一个提示;不要忽略提示和警告。你还将幻数4传递给MagWmiGetDiskModel
;应该是DriveNum
呢?
您没有调用继承的消息处理程序,并且您没有在消息处理程序中返回结果。 The documentation告诉你应该返回什么值。要从Delphi消息处理程序返回值,请为Msg.Result
字段指定值。对于消息处理程序无法处理的情况,请确保调用inherited
,以便链中的下一个处理程序可以处理它们。如果没有下一个处理程序,那么Delphi将调用DefWindowProc
来获取操作系统的默认行为。
您所说明的更改称为重构,它不会影响代码的运行方式。它使代码更容易阅读,所以请保留第二个版本。至于发现问题,我最好的建议是使用调试器逐步执行代码,以确定出现错误的部分以及运行速度比您想要的慢的部分。您也可以尝试删除部分代码,以确认其他部分可以单独正常工作。
答案 1 :(得分:2)
在 WMDeviceChange消息处理程序运行后,您查询的信息可能只在中可用。如果从按钮调用时代码相同,请尝试以下操作: