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

WMDeviceChange函数调用其他函数/过程时出现Delphi Pascal问题,delphi,function,pascal,procedure,Delphi,Function,Pascal,Procedure,解决 我使用的是Delphi2009。我的程序监听usb驱动器的连接和删除。在过去的一年里,我在10个应用程序中使用了非常类似的代码。它一直工作得很好。当我迁移时,我不得不放弃使用thddinfo来获取驱动器模型。这已被使用WMI取代。WMI查询需要物理磁盘号,而我碰巧在应用程序中已经有了这样做的功能 当我测试时,我把它放在一个按钮中并运行它,它成功地确定psp是物理驱动器4并返回模型(所有都在调试器中检查,在另一个示例中使用show message): 直到我允许我使用了一年的WMDevice

解决

我使用的是Delphi2009。我的程序监听usb驱动器的连接和删除。在过去的一年里,我在10个应用程序中使用了非常类似的代码。它一直工作得很好。当我迁移时,我不得不放弃使用thddinfo来获取驱动器模型。这已被使用WMI取代。WMI查询需要物理磁盘号,而我碰巧在应用程序中已经有了这样做的功能

当我测试时,我把它放在一个按钮中并运行它,它成功地确定psp是物理驱动器4并返回模型(所有都在调试器中检查,在另一个示例中使用show message):

直到我允许我使用了一年的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这是您的任何东西,并将i:\添加到列表中。这只是应用程序中发生变化的两个新事物,它们在被wmdevicechange调用时失败,正如它们自己工作之前所说的那样

编辑-解决

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


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

您没有指出代码中的“语句1”是什么

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

首先,在
IsPSP
中为
DriveNum
指定一个值,但不使用它。编译器应该对此发出提示;不要忽略提示和警告。您还可以将幻数4传递到
MagWmiGetDiskModel
;那应该是
DriveNum

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


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

您没有指出代码中的“语句1”是什么

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

首先,在
IsPSP
中为
DriveNum
指定一个值,但不使用它。编译器应该对此发出提示;不要忽略提示和警告。您还可以将幻数4传递到
MagWmiGetDiskModel
;那应该是
DriveNum

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

您所演示的更改称为重构,它不会影响代码的运行方式。但是,它使代码更易于阅读,因此请保留第二个版本。至于查找问题,我最好的建议是使用调试器逐步检查代码,以确定出错点以及运行速度比您希望的慢的部分。您还可以尝试删除部分代码,以确认其他部分在隔离状态下正常工作。

可能
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;