解決した
私はdelphi 2009を使用しています。私のプログラムは、接続されているUSBドライブをリッスンして取り外します。過去 1 年間で 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;
1 年間使用してきた WMDeviceChange が getphysicaldisknumber と wmi クエリ ステートメントを呼び出すことを許可するまでは、完全に機能します。私はそれらを単独で試しましたが、どちらも問題です。GetPhysicalDiskNumber は、論理ディスクで CloseHandle を実行しているときに非常にフリーズしますが、最終的には数値を返します。WMI クエリはエラーなしで失敗し、接続が発生しなかった wbemscripting_tlb に '' デバッガー ポイントが返されます。1 年で変更された唯一のことは、私が 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;
ロブは、継承されたメッセージハンドラーを呼び出さないことについて以下のことを言っています。ドキュメントを読んで、返すことができるものがいくつかあります...しかし、理解できるかどうかはよくわかりませんが、調べてみます。私はあまり優れたパスカル プログラマーではありませんが、多くのことを学んでいます。2009 年への移行には、大まかなパッチもいくつかありました。
USBドライブの検出とすべてが完全に機能します。is psp から 2 つのものを削除すると、ユーザーはすぐに wis this your anything で迎えられ、I:\ がリストに追加されます。アプリで変更された 2 つの新しい変更は、wmdevicechange によって呼び出されたときに失敗し、前に述べたように、単独で機能します。
編集 - 解決済み
提案どおりにタイマーを使用すると、問題は解決したようです。1 つの注意点は、wmdevicechange の直後にタイマーによって呼び出された場合、物理ディスク番号の取得がまだ遅いように見えることです。これは、デバイスがまだシステムに接続されているためだと考えています。
そのメモでは、通常の P2 450 を使用しています。PSP とアプリを 1.8Ghz デュアル コア ラップトップに接続すると、プログラムが PSP を検出し、ユーザーに非常に迅速に通知しました。そのため、非常に遅いコンピューター上にない限り、アプリはフリーズしません。この遅いコンピューターでは、ほんの数秒であり、プログラムの動作には影響しませんが、非常にクールではありません。しかし、最近のすべてのコンピューターは、特にデバイスをはるかに高速に接続できるため、検出が高速に実行されると思います。