解决了

我使用的是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;

罗布在下面说了一些关于我不调用继承的消息处理程序的事情,我读了文档,我看到了一些我可以返回的东西......但我不太确定我是否理解,但我会调查一下。我不是一个很好的 Pascal 程序员,但我学到了很多东西。到 2009 年的过渡也遇到了一些困难。

USB 驱动器检测以及所有这些都运行良好。如果我从 psp 中删除这两个东西,用户会立即收到“这是你的任何东西”的问候,并将 I:\ 添加到列表中。只是应用程序中发生更改的两个新内容在被 wmdevicechange 调用时失败,并且正如它们自己工作之前所说的那样。

编辑 - 已解决

好吧,我按照建议使用计时器,问题似乎已经解决。需要注意的是,在 wmdevicechange 之后不久被计时器调用时,获取物理磁盘编号似乎仍然很慢。我将此归因于设备仍连接到系统。

关于这一点,我经常使用 P2 450。我将 PSP 和应用程序连接到 1.8Ghz 双核笔记本电脑,程序检测到 PSP 并很快通知用户。因此,除非在非常非常慢的计算机上,否则应用程序不会冻结,并且在这种慢速计算机上,它只会持续几秒钟,并且不会影响程序的运行,尽管不是很酷。但我觉得所有现代计算机都会快速运行检测,特别是因为它们可以更快地连接设备。

有帮助吗?

解决方案

您查询的信息可能仅可用 WMDeviceChange 消息处理程序运行。如果从按钮调用时相同的代码可以工作,请尝试以下操作:

  1. 将 WMDeviceChange 处理程序代码重构为一个或多个单独的方法。
  2. 在 WMDeviceChange 处理程序中,激活预先创建的计时器并让它在一秒后触发,或者类似的事情。
  3. 从计时器处理程序代码中调用以前的 WMDeviceChange 处理程序代码。

其他提示

您尚未指出代码中的“语句 1”是什么。

我对部分代码有一些评论,这些评论可能与您遇到的问题相关,也可能无关。

首先,您分配一个值 DriveNumIsPSP, ,但你不使用它。编译器应该对此发出提示;不要忽视提示和警告。您还将神奇的数字 4 传递给 MagWmiGetDiskModel;本来应该是这样吗 DriveNum 反而?

您没有调用继承的消息处理程序,也没有在消息处理程序中返回结果。 文档 告诉你应该返回什么值。要从 Delphi 消息处理程序返回值,请将值分配给 Msg.Result 场地。对于消息处理程序无法处理的情况,请确保调用 inherited 以便链上的下一个处理程序可以处理它们。如果没有下一个处理程序,那么 Delphi 将调用 DefWindowProc 获取操作系统的默认行为。

您所说明的更改称为 重构, ,并且它不会影响代码的运行方式。不过,它使代码更易于阅读,因此请保留第二个版本。至于发现问题,我最好的建议是使用调试器单步调试代码,以确定出现问题的点以及运行速度比您希望的慢的部分。您还可以尝试删除部分代码,以确认其他部分单独正常工作。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top