Delphi Pascal WMDeviceChange函数调用其他函数/过程时出现的问题

时间:2009-03-14 14:53:43

标签: delphi function pascal procedure

解决

我正在使用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调用时失败,并且在它们自己工作之前就已经说过了。

编辑 - 已解决

好吧我正在使用建议的计时器,问题似乎得到解决。需要注意的是,在wmd​​evicechange获取物理磁盘号后,很快就会被计时器调用。我将此归因于仍然连接到系统的设备。

关于那个注意我正常使用P2 450。我将PSP和应用程序连接到1.8Ghz双核笔记本电脑上,程序检测到了psp并且非常快地通知了用户。因此应用程序不会冻结,除非在一台非常非常慢的计算机上,并且这个慢速只能在几秒钟内完成,并且不会影响程序的运行,虽然不是很酷。但我觉得所有现代计算机都会快速运行检测,特别是因为它们可以更快地连接设备。

2 个答案:

答案 0 :(得分:2)

您尚未在代码中说明“声明1”。

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

首先,您在DriveNum中为IsPSP分配值,但不使用它。编译器应该发布一个提示;不要忽略提示和警告。你还将幻数4传递给MagWmiGetDiskModel;应该是DriveNum呢?

您没有调用继承的消息处理程序,并且您没有在消息处理程序中返回结果。 The documentation告诉你应该返回什么值。要从Delphi消息处理程序返回值,请为Msg.Result字段指定值。对于消息处理程序无法处理的情况,请确保调用inherited,以便链中的下一个处理程序可以处理它们。如果没有下一个处理程序,那么Delphi将调用DefWindowProc来获取操作系统的默认行为。

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

答案 1 :(得分:2)

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

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