WMDeviceChange 함수가 다른 함수/프로시저를 호출할 때 델파이 파스칼 문제

StackOverflow https://stackoverflow.com/questions/646023

문제

해결됨

델파이 2009를 사용하고 있습니다.내 프로그램은 USB 드라이브가 연결되어 있는지 수신하고 제거합니다.저는 지난 1년 동안 10개의 앱에서 매우 유사한 코드를 사용했습니다.항상 완벽하게 작동했습니다.마이그레이션할 때 드라이브 모델을 얻기 위해 thddinfo 사용을 포기해야 했습니다.이는 WMI를 사용하여 대체되었습니다.WMI 쿼리에는 실제 디스크 번호가 필요하며 이를 수행하기 위한 기능이 이미 앱에 있습니다.

테스트할 때 이것을 버튼에 넣고 실행하면 psp가 물리적 드라이브 4인지 성공적으로 확인하고 모델을 반환합니다(모두 디버거에서 확인되었으며 다른 예에서는 show 메시지를 사용하여 확인됨).

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;

getphysicaldisknumber 및 wmi 쿼리 문을 호출하기 위해 1년 동안 사용해 온 WMDeviceChange를 허용하기 전까지는 완벽하게 작동합니다.직접 시도해 봤는데 둘 다 문제가 있습니다.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;

Rob은 내가 상속된 메시지 핸들러를 호출하지 않는다고 아래에서 말했습니다. 문서를 읽어보니 내가 반환할 수 있는 몇 가지 항목이 있습니다.하지만 제가 이해했는지는 잘 모르겠지만 조사해 보겠습니다.나는 아주 좋은 파스칼 프로그래머는 아니지만 많은 것을 배웠습니다.2009년으로의 전환에도 약간의 어려움이 있었습니다.

USB 드라이브 감지 및 모든 것이 완벽하게 작동합니다.is psp에서 두 가지를 제거하면 사용자는 즉시 이것이 무엇이든 상관없다고 인사하고 I:\를 목록에 추가합니다.wmdevicechange에 의해 호출될 때 그리고 자체적으로 작동하기 전에 말한 것처럼 앱에서 변경된 두 가지 새로운 사항이 실패합니다.

편집 - 해결됨

좋습니다. 제안된 대로 타이머를 사용하고 있는데 문제가 해결된 것 같습니다.한 가지 참고할 점은 wmdevicechange가 실행된 직후 타이머에 의해 호출될 때 물리적 디스크 번호를 가져오는 것이 여전히 느린 것처럼 보인다는 것입니다.나는 이것이 여전히 시스템에 연결되어 있는 장치 때문이라고 생각합니다.

그 메모에서 저는 정기적으로 P2 450을 사용하고 있습니다.PSP와 앱을 1.8Ghz 듀얼 코어 노트북에 연결했는데 프로그램이 PSP를 감지하고 사용자에게 매우 빠르게 알렸습니다.따라서 매우 느린 컴퓨터가 아닌 한 앱은 정지되지 않으며 이 느린 컴퓨터에서는 몇 초 동안만 작동하고 프로그램 작동에 영향을 주지 않지만 그다지 멋지지는 않습니다.하지만 모든 최신 컴퓨터는 특히 장치를 훨씬 더 빠르게 연결할 수 있기 때문에 감지 속도가 빨라질 것이라고 생각합니다.

도움이 되었습니까?

해결책

쿼리하는 정보 만 사용할 수 있습니다. ~ 후에 wmdevicechange 메시지 핸들러가 실행됩니다. 버튼에서 호출 될 때 동일한 코드가 작동하면 다음을 시도하십시오.

  1. wmdevicechange 핸들러 코드를 하나 이상의 별도의 방법으로 리팩터링하십시오.
  2. WMDEVICECHANGE 핸들러에서 미리 크리팅 된 타이머를 활성화하여 1 초 후에 발사하거나 그와 비슷한 것을 발사하십시오.
  3. 타이머 핸들러 코드에서 이전 WMDEVICECHANGE 처리기 코드를 호출하십시오.

다른 팁

코드에 "문 1"이 무엇인지 표시하지 않았습니다.

귀하가 겪고 있는 문제와 관련이 있을 수도 있고 없을 수도 있는 코드 부분에 대해 몇 가지 의견이 있습니다.

먼저 값을 할당합니다. DriveNum ~에 IsPSP, 하지만 당신은 그것을 사용하지 않습니다.컴파일러는 이에 대한 힌트를 제공했어야 합니다.힌트와 경고를 무시하지 마십시오.또한 매직 넘버 4를 MagWmiGetDiskModel;그럴 예정이었어? DriveNum 대신에?

상속된 메시지 핸들러를 호출하지 않고 메시지 핸들러에 결과를 반환하지 않습니다. 문서 어떤 값을 반환해야 하는지 알려줍니다.Delphi 메시지 핸들러에서 값을 반환하려면 Msg.Result 필드.메시지 핸들러가 처리하지 못하는 경우에는 다음을 호출하세요. inherited 체인의 다음 핸들러가 이를 처리할 수 있도록 합니다.다음 핸들러가 없으면 Delphi는 다음 핸들러를 호출합니다. DefWindowProc 운영 체제의 기본 동작을 가져옵니다.

당신이 설명한 변화는 리팩토링, 코드 실행 방식에는 아무런 영향을 미치지 않습니다.하지만 이렇게 하면 코드를 더 쉽게 읽을 수 있으므로 두 번째 버전을 유지하세요.문제를 찾는 데 있어 가장 좋은 조언은 디버거를 사용하여 코드를 단계별로 진행하여 문제가 발생하는 지점과 원하는 것보다 느리게 실행되는 부분을 식별하는 것입니다.코드의 일부를 제거하여 다른 부분이 독립적으로 올바르게 작동하는지 확인할 수도 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top