AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*)

Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*)

Offene Frage von "CodeX"
Ein Thema von CodeX · begonnen am 17. Aug 2015 · letzter Beitrag vom 31. Aug 2015
Antwort Antwort
Seite 3 von 4     123 4   
CodeX

Registriert seit: 30. Okt 2004
458 Beiträge
 
Delphi 10.3 Rio
 
#21

AW: Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*

  Alt 18. Aug 2015, 19:48
Der Grund, warum sich ein manuell entferntes Laufwerk in allen Explorer-Fenstern gleichzeitig aktualisiert, dürfte alleine diese Message hier sein:
Code:
<000001> 0001015E S WM_DEVICECHANGE Event:DBT_DEVICEREMOVECOMPLETE dwData:00D6F95C
<000002> 0001015E R WM_DEVICECHANGE fComplete:True
Ich glaube, dass das dem hier entsprechen müsste: SendMessage(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVICEREMOVECOMPLETE, 0); Allerdings führt das nicht zum Löschen des Laufwerks, sondern führt letztlich zu einer Art "F5" in Explorer.
Der API-Monitor ist deshalb wohl meine letzte Chance. Allerdings tue ich es mir damit sehr schwer, etwas brauchbares zu finden. Sollte jemand mit dem Tool oder mit einem anderen Debugging/Monitoring Tool vertraut sein, wäre ich für Hilfe bei der Analyse wirklich sehr dankbar.

Fällt alternativ jemandem ein API-Befehl ein, mit dem man den Explorer quasi komplett reinitialisieren kann oder zumindest die Laufwerke komplett neu aufbauen?
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.
  Mit Zitat antworten Zitat
CodeX

Registriert seit: 30. Okt 2004
458 Beiträge
 
Delphi 10.3 Rio
 
#22

AW: Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*

  Alt 19. Aug 2015, 10:28
Ich habe bemerkt, dass die Versendung der DBT_DEVICEREMOVECOMPLETE Nachricht zumindest unvollständig sein dürfte. Keine Ahnung, ob das wirklich das Problem ist, aber ich würde das zumindest doch gerne in korrekter Form ausprobieren.

Ich habe das jetzt so versucht:
Delphi-Quellcode:
const
  DBT_DEVICEREMOVECOMPLETE = 32772;
var
  phdr: PDevBroadcastHdr; //Aus JvComputerInfoEx
begin
  phdr.dbch_size := SizeOf(DEV_BROADCAST_HDR);
  phdr.dbch_devicetype := DBT_DEVTYP_VOLUME;
  SendMessage(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVICEREMOVECOMPLETE, INTEGER(@phdr));

//Auszug aus JvComputerInfoEx:
  {$EXTERNALSYM PDevBroadcastHdr}
  PDevBroadcastHdr = ^TDevBroadcastHdr;
  {$EXTERNALSYM DEV_BROADCAST_HDR}
  DEV_BROADCAST_HDR = packed record
    dbch_size: DWORD;
    dbch_devicetype: DWORD;
    dbch_reserved: DWORD;
  end;
  TDevBroadcastHdr = DEV_BROADCAST_HDR;
Aber das kann so nicht stimmen.

MSDN:
WM_DEVICECHANGE message
DBT_DEVICEREMOVECOMPLETE event
Hier steht:
Code:
lParam: A pointer to a structure identifying the device removed. The structure consists of an event-independent header, followed by event-dependent members that describe the device. To use this structure, treat the structure as a DEV_BROADCAST_HDR structure, then check its dbch_devicetype member to determine the device type.
Allerdings sehe ich in DEV_BROADCAST_HDR keine Möglichkeit, ein Laufwerk anzugeben.
Was übersehe ich?
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
946 Beiträge
 
Delphi 6 Professional
 
#23

AW: Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*

  Alt 19. Aug 2015, 12:52
Hallo..

Du übersiehst da was..

Wenn deine Application ein WM_DEVICECHANGE Event erhält, dann kann in lParm ein Record sein, welches verschiedenen Inhalt haben kann.

Um zu ermitteln, welches 'richtige' Record darin ist, sollst Du den Pointer mit DEV_BROADCAST_HDR casten und dann dbch_devicetype auslesen.

Anhand dessen Wert wird der Pointer dann mit dem richtigen Record gecastet.



DBT_DEVTYP_DEVICEINTERFACE 0x00000005
Class of devices. This structure is a DEV_BROADCAST_DEVICEINTERFACE structure.

DBT_DEVTYP_HANDLE 0x00000006
File system handle. This structure is a DEV_BROADCAST_HANDLE structure.

DBT_DEVTYP_OEM 0x00000000
OEM- or IHV-defined device type. This structure is a DEV_BROADCAST_OEM structure.

DBT_DEVTYP_PORT 0x00000003
Port device (serial or parallel). This structure is a DEV_BROADCAST_PORT structure.

DBT_DEVTYP_VOLUME 0x00000002
Logical volume. This structure is a DEV_BROADCAST_VOLUME structure.



Somit musst Du in der von Dir generierten Message ein DEV_BROADCAST_VOLUME (https://msdn.microsoft.com/de-de/library/aa363249) angeben mit

dbch_devicetype = DBT_DEVTYP_VOLUME
dbcv_unitmask = 4 // entspricht z.B. D:
dbcv_flags = DBTF_NET // 0x0002
  Mit Zitat antworten Zitat
CodeX

Registriert seit: 30. Okt 2004
458 Beiträge
 
Delphi 10.3 Rio
 
#24

AW: Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*

  Alt 19. Aug 2015, 13:02
Danke, aber wo kommt das DEV_BROADCAST_VOLUME denn hin?
Delphi-Quellcode:
const
  DBT_DEVICEREMOVECOMPLETE = 32772;
  DBTF_NET = 2;
var
  phdr: PDevBroadcastHdr;
  pvol: PDevBroadcastVolume;
begin
  pvol.dbcv_size := SizeOf(DEV_BROADCAST_VOLUME);
  pvol.dbcv_devicetype := DBT_DEVTYP_VOLUME;
  pvol.dbcv_unitmask := 26; //Z:
  pvol.dbcv_flags := DBTF_NET;

  phdr.dbch_size := SizeOf(DEV_BROADCAST_HDR);
  phdr.dbch_devicetype := DBT_DEVTYP_VOLUME;

  SendMessage(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVICEREMOVECOMPLETE, INTEGER(@phdr));
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
946 Beiträge
 
Delphi 6 Professional
 
#25

AW: Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*

  Alt 19. Aug 2015, 14:56
Delphi-Quellcode:
const
  DBT_DEVICEREMOVECOMPLETE = 32772;
  DBTF_NET = 2;
var
  pvol: PDevBroadcastVolume;
begin
  pvol.dbcv_size := SizeOf(DEV_BROADCAST_VOLUME);
  pvol.dbcv_devicetype := DBT_DEVTYP_VOLUME;
  pvol.dbcv_unitmask := 26; //Z:
  pvol.dbcv_flags := DBTF_NET;

  SendMessage(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVICEREMOVECOMPLETE, INTEGER(@pvol));
DEV_BROADCAST_HDR wird nicht bei SendMessage verwendet!

Nur, wenn Du die Message selber erhälst und wissen willst, auf was für ein Record lParam zeigt.

Da alle DevBroadcast Records mit den gleichen Feldern anfangen wie DEV_BROADCAST_HDR, kannst Du dann den Typ auslesen um dann mit dem richtigen Typ (z.B. DEV_BROADCAST_VOLUME) zu casten und weiter zu arbeiten.

Wenn es nicht Records währen, sondern Objecte, dann währe DEV_BROADCAST_VOLUME von DEV_BROADCAST_HDR abgeleitet.

Ach ja
pvol.dbcv_unitmask := 26; //Z:
ist falsch, Z: hat die ID 25, da A = ID 0 ist..

OK auch falsch...
Hier wird eine Bitmaske gebraucht.. $02000000 = Z

Geändert von HolgerX (19. Aug 2015 um 15:08 Uhr)
  Mit Zitat antworten Zitat
CodeX

Registriert seit: 30. Okt 2004
458 Beiträge
 
Delphi 10.3 Rio
 
#26

AW: Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*

  Alt 19. Aug 2015, 15:47
DEV_BROADCAST_HDR wird nicht bei SendMessage verwendet!
Oh, OK ... das hatte ich irgendwie falsch verstanden.

Z: hat die ID 25, da A = ID 0 ist..
Dann ist 4 = D: in deinem Beispiel vorhin aber auch falsch.


Scheinbar knallts aber bei jeder Zuweisung der Werte von pvol:
Code:
Access violation at address 0053CFAD in module 'disconnect.exe'. Write of address 00000000.
Muss das irgendwie noch initialisiert werden? pvol ist erstmal nur nil.

Edit:
Also so bekomme ich die Funktion zum Laufen:
Delphi-Quellcode:
var
  pvol: PDevBroadcastVolume;
  sDrive: String;
const
  DBT_DEVICEREMOVECOMPLETE = 32772;
  DBTF_NET = 2;
  EmptyDevBroadcastVolume: TDevBroadcastVolume = (
    dbcv_size: 0;
    dbcv_devicetype: 0;
    dbcv_reserved: 0;
    dbcv_unitmask: 0;
    dbcv_flags: 0);
begin
  sDrive := 'Z:';
  pvol := @EmptyDevBroadcastVolume;
  pvol.dbcv_size := SizeOf(DEV_BROADCAST_VOLUME);
  pvol.dbcv_devicetype := DBT_DEVTYP_VOLUME;
  pvol.dbcv_unitmask := PathGetDriveNumber(PChar(sDrive))
  pvol.dbcv_flags := DBTF_NET;

  SendMessage(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVICEREMOVECOMPLETE, INTEGER(@pvol));
Einen Unterschied scheint es aber dennoch nicht zu machen. Das Laufwerk ist immer noch da.
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.

Geändert von CodeX (19. Aug 2015 um 16:52 Uhr)
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
946 Beiträge
 
Delphi 6 Professional
 
#27

AW: Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*

  Alt 19. Aug 2015, 18:15
Hmm..

Mit meiner Test-Version kann ich dem Explorer mitteilen, das er ein angegebenes Laufwerk aus der Ansicht entfernt.
Das klappt sogar mit meinem Festplatten-Laufwerk D:.

Wieso Du Pointer auf eine Const machst und diese dann verändern willst ist mir schleierhaft ?!?!

Der folgende Code ist mit D6 erstellt und läuft unter Win 8.1.
Wenn der Explorer offen ist, kannste ihn dazu bringen, sogar das LW C: auszublenden. Mit einem F5 im Explorer ist es dann wieder da....

Edit:
Korrektur, das Ausblenden von C: mag der Explorer nicht und führt anschließend direkt ein F5 aus

Meine Funktionen GetDrive und GetDriveMask berücksichtigen hier nur jeweils ein Laufwerk.
In der Message kannst Du aber direkt auch alle Laufwerke ausblenden lassen, da die dbcv_unitmask alle von Laufwerke von A-Z auf einmal enthalten kann.

Delphi-Quellcode:
const
  DBT_DEVICEREMOVECOMPLETE = $8004;

  DBT_DEVTYP_VOLUME = $00000002;

  DBTF_MEDIA = $0001;
  DBTF_NET = $0002;

type
  PDEV_BROADCAST_HDR = ^DEV_BROADCAST_HDR;
  DEV_BROADCAST_HDR = packed record
    dbch_size : DWORD;
    dbch_devicetype : DWORD;
    dbch_reserved : DWORD;
  end;

  PDEV_BROADCAST_VOLUME = ^DEV_BROADCAST_VOLUME;
  DEV_BROADCAST_VOLUME = packed record
    dbcv_size: DWORD;
    dbcv_devicetype: DWORD;
    dbcv_reserved: DWORD;
    dbcv_unitmask: DWORD;
    dbcv_flags: WORD;
  end;

function GetDrive(unitmask: DWORD): Char;
var
  i: Byte;
begin
  result := ' ';
  for i := 0 to 25 do begin
    if (unitmask and 1) = 1 then begin
      Result := Char(i + Ord('A'));
      break;
    end;
    unitmask := unitmask shr 1;
  end;
end;

function GetDriveMask(Drive: Char): DWORD;
begin
  result := 1 shl (ord(Drive) - ord('A'));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  DevVol: DEV_BROADCAST_VOLUME;
  sDrive: Char;
begin
  sDrive := Edit1.text[1];
  FillChar(DevVol,SizeOf(DEV_BROADCAST_VOLUME),0);
  DevVol.dbcv_size := SizeOf(DEV_BROADCAST_VOLUME);
  DevVol.dbcv_devicetype := DBT_DEVTYP_VOLUME;
  DevVol.dbcv_unitmask := GetDriveMask(sDrive);
  DevVol.dbcv_flags := DBTF_NET;
  SendMessage(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVICEREMOVECOMPLETE, INTEGER(@DevVol));
end;

procedure TForm1.WMDeviceChange(var Msg: TMessage);
begin
  if Msg.WParam = DBT_DEVICEREMOVECOMPLETE then begin
    if PDEV_BROADCAST_HDR(Msg.LParam)^.dbch_devicetype = DBT_DEVTYP_VOLUME then
      ShowMessage(GetDrive(PDEV_BROADCAST_VOLUME(msg.LParam)^.dbcv_unitmask));
  end;
end;

Geändert von HolgerX (19. Aug 2015 um 18:19 Uhr)
  Mit Zitat antworten Zitat
CodeX

Registriert seit: 30. Okt 2004
458 Beiträge
 
Delphi 10.3 Rio
 
#28

AW: Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*

  Alt 19. Aug 2015, 18:38
Ich hatte mich wohl irgendwie in eine Richtung verrannt.
Bei der unitmask lag ich auch noch komplett falsch...
Vielen Dank für deine Unterstützung!

Mit Deiner Version kann ich tatsächlich Laufwerke ausblenden. Bei mir bleiben diese auch bei einem F5 weg. Wenn ich den Explorer abschieße und wieder starte, sind die lokalen Laufwerke (korrekterweise) wieder da. Habe es soeben auf 2 Systemen getestet.

Leider funktioniert es nur mit echten Laufwerken, aber mit keinen Netzlaufwerken. Egal ob mit dem "Problem-Szenario" oder ganz normal frisch verbunden. Dabei steht DBTF_NET ja gerade für "Indicated logical volume is a network volume". Oder funktioniert das bei dir (falls kein anderer Rechner/VM vorhanden ist, kann man ja auch ein freigegebenes Verzeichnis auf dem gleichen Rechner mounten)?
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.

Geändert von CodeX (19. Aug 2015 um 18:42 Uhr)
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
946 Beiträge
 
Delphi 6 Professional
 
#29

AW: Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*

  Alt 21. Aug 2015, 07:23
So...

Hab mich mal ein bischen intensiver mit den 'nicht verbundenen' Netzwerklaufwerken im Explorer beschäftigt.

Anscheinend listet der Explorer auch alle nicht verbundenen (persistenten) Laufwerke auf.

Bei Verwendung von WNetEnumResource werden als RESOURCE_CONNECTED nur die tatsächlich vorhandenen und verfügbaren Connections aufgelistet, erst mit RESOURCE_REMEMBERED auch die getrennten.

Versucht man dann mit WNetCancelConnection2 dieses 'nicht verbundenen' Laufwerk zu löschen kommt der Fehlercode 2250 (ERROR_NOT_CONNECTED) = 'Diese Netzwerkverbindung ist nicht vorhanden.'. Die Anzeige im Explorer bleibt bestehen.

Was ja auch richtig ist, da keine 'aktive' Connection besteht.

Benutzt mann dann 'Trennen' im Explorer wird eventuell das Laufwerk entfernt, manchmal aber auch nicht.

Dies kann ein BUG im Explorer sein oder ein Feature...
Schließlich ist dies eine Info, das etwas mit der Verbindung nicht funktioniert hat!

WM_DEVICECHANGE / DBT_DEVICEREMOVECOMPLETE funktioniert anscheinend tatsächlich nur mit echten DRIVES, also HDs, Wechselplatten, CD-LW.... nicht mit NetzwerkCONNECTIONs..

Somit musste mit dem Explorer so leben, wie es ist, oder einfach keine persistenten Netzwerkverbindungen verwenden.
  Mit Zitat antworten Zitat
CodeX

Registriert seit: 30. Okt 2004
458 Beiträge
 
Delphi 10.3 Rio
 
#30

AW: Windows-Bug mit bestimmter Netzlaufwerkskonstellation (*Herausforderung gesucht?*

  Alt 21. Aug 2015, 11:59
Vielen herzlichen Dank für deine Analyse, HolgerX!

Feature oder Bug:
Wenn man ein Netzlaufwerk dieser Konstellation trennt (mit dem Wizzard von Windows per Explorer-Hauptmenü > Extras > Trennen, oder alternativ per net use oder API), dann verbleibt die Verbindung wie schon bekannt sichtbar. Verbindet man jetzt ein neues Netzlaufwerk auf diesen Laufwerksbuchstaben (was ja problemlos geht, auch wenn der Buchstabe laut Explorer schon/noch vergeben ist), wird weiterhin der Name/Pfad der alten Verbindung angezeigt. Klickt man allerdings drauf kommt man ins neu verbundene Verzeichnis. [Edit: Ich habe gerade mal versucht, ein lokales Laufwerk auf den Laufwerksbuchstaben vom halb-getrennten Netzlaufwerk zu legen. Das geht problemlos, nur dass im Explorer das Laufwerk unverändert als getrenntes Netzlaufwerk mit Netzwerknamen angezeigt wird; per Doppelklick kommt man dann allerdings auf den Inhalt des lokalen Laufwerks. Verrückt.]
Zudem: Der Explorer zeigt nach dem "fehlerhaften Trennen" ein Laufwerk an, das nirgends sonst anzeigbar ist. Weder in anderen Tools, noch in anderen Windows-Darstellungen (Netzlaufwerk verbinden, etc.)
Ich glaube, man kann das durchaus als Bug bezeichnen.

Benutzt mann dann 'Trennen' im Explorer wird eventuell das Laufwerk entfernt, manchmal aber auch nicht.
Das Laufwerk wird meinen Tests nach manuell immer korrekt getrennt und entfernt, sofern man die Trennung zuvor nicht schon auf anderem Wege durchgeführt hat (dann sagt er, die Netzwerkverbindung würde nicht existieren).

Genau das ist auch der Grund, warum es eine Lösung geben muss. Irgendetwas tut der Explorer zusätzlich. Und falls er eine Funktion auslöst, die per API nicht verfügbar ist, dann war mein gedanklicher Ansatz, dass man eben zumindest das "Rechtsklick+Trennen"-Verhalten irgendwie reproduzieren kann. Aus diesem Grund habe ich es zunächst mit diesem Thread hier versucht:
http://www.delphipraxis.net/186217-e...usfuehren.html

Wenn man exakt den gleichen Kontextmenüpunkt ausführen könnte, müsste ja auch das gleiche Ergebnis kommen, oder?

Absurderweise scheint das Netzlaufwerk-Kontextmenü, das man per API aufruft zwar exakt so auszusehen und augenscheinlich auch die richtigen Funktionen auszuführen. Aber das betätigen von "Trennen" führt zum gleichen fehlerhaften Ergebnis. Wie kann das sein?
Und: Das Kontextmenü zu einem "halb getrennten" Netzlaufwerk lässt sich im Explorer problemlos öffnen und bedienen, aber per API kann man auf dieses Kontextmenü nicht mehr zugreifen, weil das Laufwerk darüber nicht mehr zugreifbar ist. Ich glaube mittlerweile aber, dass sobald dieser Fehlerfall eingetreten ist, man nichts mehr tun kann (eben ein Explorer-Bug). Aber bevor der Fehler eintritt muss man doch den "Trennen"-Punkt irgendwie exakt so ausführen können wie per Maus, oder??
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.

Geändert von CodeX (21. Aug 2015 um 16:21 Uhr)
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:07 Uhr.
Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf