Autor Beitrag
Mashalla
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Windows 7 Professional
Delphi 7 Enterprise, Turbo Delphi Explorer 2006
BeitragVerfasst: Fr 12.06.09 18:47 
Ich versuche gerade eine Anwendung zu programmieren, bei der ich angesteckte USB-Wechseldatenträger erkennen können muss. Dazu hab ich folgende Unit von Swissdelphicenter benutzt, die auch tadellos funktioniert. Einziges Problem ist, dass mein Programm sich leider einklinkt, bevor das Laufwerk einen Buchstaben zugewiesen bekommt. Mit folgender Funktion überprüfe ich auf Wechseldatenträger:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
////////////////////////////////////////////////////////////////////////////////
// @Function: GetRemovableDrives
////////////////////////////////////////////////////////////////////////////////
function TMainForm.GetRemovableDrives: TStringList;
const
  DRIVE_UNKNOWN = 0;
  DRIVE_NO_ROOT_DIR = 1;
  DRIVE_REMOVABLE = 2;
  DRIVE_FIXED = 3;
  DRIVE_REMOTE = 4;
  DRIVE_CDROM = 5;
  DRIVE_RAMDISK = 6;
var
  r: LongWord;
  Drives: array[0..128of char;
  pDrive: PChar;
begin
  Result := TStringList.Create;
  try
    r := GetLogicalDriveStrings(SizeOf(Drives), Drives);
    if r = 0 then Exit;
    if r > SizeOf(Drives) then
      raise Exception.Create(SysErrorMessage(ERROR_OUTOFMEMORY));
    pDrive := Drives;
    // Zeiger durch das Array laufen lassen und alle Laufwerke betrachten
    while pDrive^ <> #0 do
    begin
      if GetDriveType(pDrive) = DRIVE_REMOVABLE then
        Result.Add(pDrive);
      Inc(pDrive, 4);
    end;
  except
    FreeAndNil(Result);
  end;
end;


Diese Funktion funktioniert wunderbar und liefert mir, was ich brauche. Die nächste Funktion wird aufgerufen, wenn ein USB Gerät angesteckt wird. Leider bekomme ich immer eine leere Rückgabe, egal wie lange die Schleife läuft.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
////////////////////////////////////////////////////////////////////////////////
// @Function: GetNewDrive
////////////////////////////////////////////////////////////////////////////////
function TMainForm.GetNewDrive: String;
var
  NewList: TStringList;
  I, P, Counter: Integer;
begin
  Counter := 0;
  NewList := GetRemovableDrives;
  // Warten, bis das Laufwerk gefunden wurde
  while (NewList.Count = IndexedDriveList.Count) and (Counter < 25do begin
    Sleep(500);
    NewList := GetRemovableDrives;
    Inc(Counter);
    result := '';
  end;
...


Lässt es sich irgendwie einrichten, dass mein Programm erst darauf zugreift, wenn das Laufwerk einen Laufwerksbuchstaben hat? Weil ohne diesen komme ich leider nicht weit.

Gruß Mashalla
MaPsTaR
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 90
Erhaltene Danke: 4

Win XP
Delphi 7 Enterprise
BeitragVerfasst: So 14.06.09 19:24 
Hallo

Leider konnte ich mit dem kurzen Ausschnit deiner Function GetNewDrive nicht viel anfangen, geschweige denn einen Fehler suchen.
Dieser scheint aber definitiv dort zu liegen. Da ich außerdem nicht erfahren konnte wo und wie du IndexedDriveList mit Werten füllst.....

Auf das neue Laufwerk brauchst du übrigens nicht zu warten, da in deiner Klasse & meiner Prozedur "GetNewDrive" erst aufgerufen werden, wenn das Laufwerk bereits einen Buchstaben erhalten hat.

Ich würde es so machen, ist aber nur eine Idee:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
    procedure OnDeviceChange(var Msg: TMsg); message WM_DEVICECHANGE;
    function GetRemovableDrives: TStringList;
    function GetAllLogicalDrives: TStringList;
    function GetNewDrive: String;

var
  IndexedDriveList: TStringList;

const
  DBT_DEVICEARRIVAL          = $8000;          // Neues Gerät gefunden
  DBT_DEVICEREMOVECOMPLETE   = $8004;          // Gerät wurde entfernt


function TForm1.GetNewDrive: String;
var
  NewList: TStringList;
  I, P: Integer;
begin
  NewList := GetRemovableDrives;
  // Neues Laufwerk suchen
  for p := NewList.Count - 1 downto 0 do
  begin
    result := NewList[p];
    for i := IndexedDriveList.Count - 1 downto 0 do
    begin
      if NewList[p] = IndexedDriveList[i]
      then
      begin
        result := '';
        break;
      end;
    end;
    if result <> ''
    then
      break;
  end;
end;

function TForm1.GetAllLogicalDrives: TStringList;
const
  DRIVE_UNKNOWN = 0;
  DRIVE_NO_ROOT_DIR = 1;
  DRIVE_REMOVABLE = 2;
  DRIVE_FIXED = 3;
  DRIVE_REMOTE = 4;
  DRIVE_CDROM = 5;
  DRIVE_RAMDISK = 6;
var
  r: LongWord;
  Drives: array[0..128of char;
  pDrive: PChar;
begin
  Result := TStringList.Create;
  try
    r := GetLogicalDriveStrings(SizeOf(Drives), Drives);
    if r = 0 then Exit;
    if r > SizeOf(Drives) then
      raise Exception.Create(SysErrorMessage(ERROR_OUTOFMEMORY));
    pDrive := Drives;
    // Zeiger durch das Array laufen lassen und alle Laufwerke betrachten
    while pDrive^ <> #0 do
    begin
      Result.Add(pDrive);
      Inc(pDrive, 4);
    end;
  except
    FreeAndNil(Result);
  end;
end;

function TForm1.GetRemovableDrives: TStringList;
const
  DRIVE_UNKNOWN = 0;
  DRIVE_NO_ROOT_DIR = 1;
  DRIVE_REMOVABLE = 2;
  DRIVE_FIXED = 3;
  DRIVE_REMOTE = 4;
  DRIVE_CDROM = 5;
  DRIVE_RAMDISK = 6;
var
  r: LongWord;
  Drives: array[0..128of char;
  pDrive: PChar;
begin
  Result := TStringList.Create;
  try
    r := GetLogicalDriveStrings(SizeOf(Drives), Drives);
    if r = 0 then Exit;
    if r > SizeOf(Drives) then
      raise Exception.Create(SysErrorMessage(ERROR_OUTOFMEMORY));
    pDrive := Drives;
    // Zeiger durch das Array laufen lassen und alle Laufwerke betrachten
    while pDrive^ <> #0 do
    begin
      if GetDriveType(pDrive) = DRIVE_REMOVABLE then
        Result.Add(pDrive);
      Inc(pDrive, 4);
    end;
  except
    FreeAndNil(Result);
  end;
end;

procedure TForm1.OnDeviceChange(var Msg: TMsg);
var i: integer;
begin
  if (Msg.message = DBT_DEVICEARRIVAL)
  then
  begin
    ShowMessage(GetNewDrive);
    IndexedDriveList := GetAllLogicalDrives;
  end;
  if (Msg.message = DBT_DEVICEREMOVECOMPLETE)
  then
  begin
    IndexedDriveList := GetAllLogicalDrives;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i: integer;
begin
  IndexedDriveList := GetAllLogicalDrives;
end;

end.


Zumindest läuft es so bei mir.

PS: Beim nächsten Mal hätte ich gern mehr Code zum Fehler suchen. ;-)

Gruß MaPsTaR

Moderiert von user profile iconNarses: Code- durch Delphi-Tags ersetzt
Mashalla Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Windows 7 Professional
Delphi 7 Enterprise, Turbo Delphi Explorer 2006
BeitragVerfasst: Mo 15.06.09 00:00 
Jo...der Codefehler wird mir hoffentlich nicht mehr unterlaufen. Im Nachhinein wunder ich mich selbst, wie man darauf ne Problemlösung ableiten soll, was ich gepostet hab *gg*

Ok, also mit deiner Änderung funktioniert das leider immer noch nicht so ganz zuverlässig. Wenn ich 2 Stick angeschlossen hab und das Programm starte, findet er beide, aber wenn ich während dem Betrieb einen ansteck, schnallt er es wieder nicht. Ich hab sicher irgendwas mit dem OnDeviceChange verrafft :)

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
////////////////////////////////////////////////////////////////////////////////
// @Procedure: FormCreate
////////////////////////////////////////////////////////////////////////////////
procedure TMainForm.FormCreate(Sender: TObject);
var
  USBCheck: TComponentUSB;
begin
  Application.ShowMainForm := false;
  CreatePopupMenu;
  ScanForDriveFiles(MainForm.TrayIcon);
  USBCheck := TComponentUSB.Create(MainForm);
  // Handler zum Erkennen neuer Laufwerke
  USBCheck.OnUSBArrival := NewUSBDrive;
  USBCheck.OnUSBRemove := RemoveUSBDrive;
end;


////////////////////////////////////////////////////////////////////////////////
// @Procedure: ScanForDriveFiles
////////////////////////////////////////////////////////////////////////////////
procedure TMainForm.ScanForDriveFiles(Sender: TObject);
var
  DriveList, FileList: TStringList;
  DriveCount, FileCount, I, P: Integer;
  FileName, FilePath, Dir, Mask: String;
begin
  DriveList := TStringList.Create;
  FileCount := 0;
  Mask := '*.exe';
  // Alte Daten im Menu löschen
  ResetPopupMenu;
  try
    // Wechseldatenträger holen
    DriveList := GetRemovableDrives;
    DriveCount := DriveList.Count;
    if DriveCount > 0 then begin
      // Durch alle Wechseldatenträger laufen
      for I := 0 to DriveCount - 1 do begin
        Dir := DriveList[I];
        ShowMessage(Dir);
        // Daten holen
        FileList := GetAllFiles(Dir, Mask);
        FileCount := FileList.Count;
        if FileCount > 0 then begin
          // Durch alle Dateien des Datenträgers laufen
          for P := 0 to FileCount - 1 do begin
            FileName := ExtractFileName(FileList[P]);
            FilePath := ExtractFilePath(FileList[P]);
            Pop.Items.Insert(2,CreatePopupItem(FileName, FilePath));
          end;
        end;
        InsertDividerAtIndex(Pop, Pop.Items.Count - 1);
      end;
    end;
  finally
    DriveList.Free;
  end;
end;

////////////////////////////////////////////////////////////////////////////////
// @Procedure: NewUSBDrive
////////////////////////////////////////////////////////////////////////////////
procedure TMainForm.NewUSBDrive(Sender: TObject);
var
  Msg: TMsg;
begin
  Msg.message := DBT_DEVICEARRIVAL;
  OnDeviceChange(Msg);
end;

////////////////////////////////////////////////////////////////////////////////
// @Procedure: RemoveUSBDrive
////////////////////////////////////////////////////////////////////////////////
procedure TMainForm.RemoveUSBDrive(Sender: TObject);
var
  Msg: TMsg;
begin
  Msg.message := DBT_DEVICEREMOVECOMPLETE;
  OnDeviceChange(Msg);
end;

////////////////////////////////////////////////////////////////////////////////
// @Procedure: OnDeviceChange
////////////////////////////////////////////////////////////////////////////////
procedure TMainForm.OnDeviceChange(var Msg: TMsg);
begin
  if (Msg.message = DBT_DEVICEARRIVAL) or
     (Msg.message = DBT_DEVICEREMOVECOMPLETE) then
    ScanForDriveFiles(MainForm);
end;


Das sollten alle relevanten Prozeduren sein...wie gesagt, beim Anstecken ist die StringList "DriveList" leer, das neue Laufwerk wird (noch) nicht erkannt. Beim Abziehen eines Wechseldatenträgers funktioniert nun alles, wie es sollte. Was mache ich falsch bzw was läuft hier falsch?
bis11
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1247
Erhaltene Danke: 2

Apple Mac OSX 10.11

BeitragVerfasst: Mo 15.06.09 06:14 
Guten Morgen,

in meinem Programm SystemInfo benutze ich den folgenden Code um zu merken ob ein USB-Stick angeschlossen ist oder nicht, vielleicht hilft er Dir ja weiter.
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
procedure TMainForm.WMDeviceChange(var Msg: TMessage);
type
  PDevBroadcastHdr = ^TDevBroadcastHdr;
  TDevBroadcastHdr = packed record
    dbcd_size, dbcd_devicetype, dbcd_reserved: DWORD;
  end;
  PDevBroadcastVolume = ^TDevBroadcastVolume;
  TDevBroadcastVolume = packed record
    dbcv_size, dbcv_devicetype, dbcv_reserved, dbcv_unitmask: DWORD;
    dbcv_flags: Word;
  end;

  function GetDrive(pDBVol: PDevBroadcastVolume): string;
  var
    i: Byte; Maske: DWORD;
  begin
    if (pDBVol^.dbcv_flags and $0001) = $0001 then
    begin
      Maske := pDBVol^.dbcv_unitmask;
      for i := 0 to 25 do
      begin
        if (Maske and 1) = 1 then
        Result := Char(i + Ord('A')) + ': ';
        Maske := Maske shr 1;
      end;
    end;
  end;

begin
  case Msg.wParam of
  $8000:
    if PDevBroadcastHdr(Msg.lParam)^.dbcd_devicetype = $0002 then
    begin
//      M_phys_Drives.Lines.Text := GetLocalDrives;
//      GetLocalDrives2;
    end;
  $8004:
    if PDevBroadcastHdr(Msg.lParam)^.dbcd_devicetype = $0002 then
    begin
//      M_phys_Drives.Lines.Text := GetLocalDrives;
//      GetLocalDrives2;
    end;
  end;
end;

Die auskommentierten Zeilen ersetze durch Deine Aktionen, die ausgeführt werden sollen.
MaPsTaR
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 90
Erhaltene Danke: 4

Win XP
Delphi 7 Enterprise
BeitragVerfasst: Mo 15.06.09 14:53 
Du rufst OnDeviceChange ja auch über eine andere Procedure auf.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
interface

type TForm1 = class(TForm)
  private
    { Private-Deklarationen }
    procedure OnDeviceChange(var Msg: TMsg); message WM_DEVICECHANGE;  // Wird aufgerufen, wenn ein Gerät geändert wird
    function GetRemovableDrives: TStringList;
    function GetAllLogicalDrives: TStringList;
    function GetNewDrive: String;
end;

Hast du an das  message WM_DEVICECHANGE; im interface-Teil gedacht?
Dann wird die Funktion automatisch aufgerufen, wenn das Prorgamm die Message empfängt.

Und dann sollte es auch funktionieren, dass er im Betrieb deine Sticks erkennt.
Bei mir hat es mit 3 Sticks auf jeden Fall geklappt.

Viel Erfolg MaPsTaR

Moderiert von user profile iconNarses: Code- durch Delphi-Tags ersetzt
Mashalla Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Windows 7 Professional
Delphi 7 Enterprise, Turbo Delphi Explorer 2006
BeitragVerfasst: Mo 15.06.09 16:45 
@ Mapster:

Jo danke, der letzte Tipp half mir. Jetzt läuft es alles nach Plan. Großes Danke :)

@ Rolf:

Ich hab deinen Code jetzt nicht ausprobiert, aber danke fürs Posten. Möglicherweise greift jemand anders darauf zurück ;)
Mashalla Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Windows 7 Professional
Delphi 7 Enterprise, Turbo Delphi Explorer 2006
BeitragVerfasst: So 12.07.09 23:50 
Ok, neues "Problem":

Das Erkennen funktioniert aktuell wunderbar. Wenn ich jetzt im Windows Explorer dem Stick eine neue Bezeichnung gebe, erkennt er beim erneuten Einstecken den Stick nicht mehr, also die Message von WM_DEVICECHANGE ist weder DBT_DEVICEARRIVAL noch DBT_DEVICEREMOVALCOMPLETE beim Abziehen des Sticks. Kann mir das jemand erklären?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
////////////////////////////////////////////////////////////////////////////////
// @Procedure: OnDeviceChange
////////////////////////////////////////////////////////////////////////////////
procedure TMainForm.OnDeviceChange(var Msg: TMsg);
begin
  if (Msg.message = DBT_DEVICEARRIVAL) then begin
    NewDriveArrived := true;
    ScanForDriveFiles(MainForm);
    end;
  if (Msg.message = DBT_DEVICEREMOVECOMPLETE) then begin
    NewDriveArrived := false;
    ScanForDriveFiles(MainForm);
    end;
end;


Er springt weder beim Anstecken noch beim Abziehen in einen if-Teil, sondern läuft einfach durch.

NACHTRAG:
Ähem...ich kanns aktuell leider nicht mehr reproduzieren, er erkennt jetzt auch den umbenannten Stick ... ich schiebs einfach mal auf die RC von Windows 7 :D
josejp1
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Di 04.08.09 13:17 
Werfen sie einen blick auf den folgenden Link:


Original:
delphimagic.blogspot...-de-un-pendrive.html


Übersetzung:
translate.google.com...20discusi%25C3%25B3n