Domanda

RISOLTO

Sto usando Delphi 2009. Il mio programma è in ascolto delle unità USB che vengono collegate e rimosse. L'anno scorso ho usato un codice molto simile in 10 app. Ha sempre funzionato perfettamente. Quando sono migrato ho dovuto rinunciare a utilizzare thddinfo per ottenere il modello di unità. Questo è stato sostituito usando WMI. La query WMI richiede il numero di disco fisico e mi capita di avere già una funzione nell'app per farlo.

Mentre collaudo lo inserisco in un pulsante e lo eseguo e determina con successo che psp è l'unità fisica 4 e restituisce il modello (tutto verificato nel debugger e in un altro esempio usando 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;

Funziona perfettamente fino a quando non autorizzo WMDeviceChange che uso da un anno per richiamare il numero getphysicaldisk e l'istruzione query wmi. Ive li hanno provati da soli sono entrambi un problema. GetPhysicalDiskNumber si blocca molto quando esegue CloseHandle sul disco logico ma alla fine restituisce il numero. La query WMI ha esito negativo senza alcun errore e restituisce '' punti debugger in wbemscripting_tlb dove la connessione non è mai avvenuta. Ricorda che l'unica cosa che è cambiata in un anno è ciò che sto chiamando per ottenere il modello che stavo usando una chiamata API e ora sto usando qualcos'altro.

Di seguito è riportato il resto del codice coinvolto in questo momento senza l'ispsp che viene visualizzato sopra:

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 ha detto qualcosa di seguito sul fatto che non sto chiamando il gestore di messaggi ereditato, quindi leggo il documento, vedo un paio di cose che posso restituire ... ma non sono proprio sicuro di aver capito, ma lo esaminerò. Non sono un ottimo programmatore pasquale ma sto imparando molto. La transizione al 2009 ha avuto anche alcune patch approssimative.

Il rilevamento di unità USB e tutto ciò che funziona perfettamente. Se rimuovo le due cose da psp, l'utente viene subito accolto con questo è il tuo qualunque e aggiunge I: \ all'elenco. Sono solo le due nuove cose che sono cambiate nell'app che falliscono quando vengono chiamate da wmdevicechange e come detto prima che funzionino da sole.

MODIFICA - RISOLTO

Bene, sto usando un timer come suggerito e il problema sembra essere risolto. Una nota è che quando viene chiamato dal timer molto poco dopo lo scambio di dati, il numero del disco fisico sembra essere ancora lento. Attribuisco questo al dispositivo ancora collegato al sistema.

In quella nota sto usando un P2 450 sul normale. Ho collegato la PSP e l'app a un laptop Dual Core da 1,8 Ghz e il programma ha rilevato la psp e avvisato l'utente molto velocemente. Quindi l'app non si bloccherà a meno che non ci sia su un computer molto lento e su questo lento onw sia solo per pochi secondi e non influisca sul funzionamento del programma sebbene non sia molto bello. Ma ritengo che tutti i computer moderni eseguiranno il rilevamento rapidamente soprattutto perché possono collegare il dispositivo molto più velocemente.

È stato utile?

Soluzione

È possibile che le informazioni che stai interrogando siano disponibili solo dopo il gestore di messaggi WMDeviceChange viene eseguito. Se lo stesso codice funziona quando viene chiamato da un pulsante, prova questo:

  1. Rifattorizza il codice del gestore WMDeviceChange in uno o più metodi separati.
  2. Nel gestore WMDeviceChange, attiva un timer precreato e fallo funzionare un secondo dopo, o qualcosa del genere.
  3. Chiama il precedente codice del gestore WMDeviceChange dal codice del gestore timer.

Altri suggerimenti

Non hai indicato cosa " istruzione 1 " è nel tuo codice.

Ho alcuni commenti su parti del codice, che possono o meno essere correlate al problema che stai riscontrando.

Innanzitutto, assegni un valore a DriveNum in IsPSP , ma non lo usi. Il compilatore avrebbe dovuto fornire un suggerimento al riguardo; non ignorare suggerimenti e avvertenze. Passa anche il numero magico 4 in MagWmiGetDiskModel ; avrebbe dovuto essere invece DriveNum ?

Non stai chiamando il gestore messaggi ereditato e non stai restituendo un risultato nel gestore messaggi. La documentazione indica quali valori dovresti restituire. Per restituire un valore da un gestore di messaggi Delphi, assegnare un valore al campo Msg.Result . Per i casi che il gestore dei messaggi non gestisce, assicurati di chiamare ereditato in modo che il gestore successivo nella catena possa occuparsene. Se non è presente alcun gestore successivo, Delphi chiamerà DefWindowProc per ottenere il comportamento predefinito del sistema operativo.

La modifica che hai illustrato si chiama refactoring e non farà nulla per influire sull'esecuzione del codice. Rende il codice più facile da leggere, tuttavia, quindi ti preghiamo di conservare la seconda versione. Per quanto riguarda la ricerca del problema, il mio miglior consiglio è quello di utilizzare il debugger per scorrere il codice per identificare il punto in cui le cose vanno male e le parti che funzionano più lentamente di quanto desideri. Puoi anche provare a rimuovere parti del codice per confermare che le altre parti funzionano correttamente in modo isolato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top