USB-Funktionen mit WM_DEVICECHANGE

pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

USB-Funktionen mit WM_DEVICECHANGE

 · 
Posted: 03.09.2014 - 19:52  ·  #1
Hallo Leute,

ich stecke gerade etwas fest.

Ich versuche meine Kommunikation mit dem XMEGA-USBSmart auf Fehler abzufangen und entsprechend zu reagieren.

Ich möchte das mein Board vom Windows-Programm beim einstecken automatisch erkannt wird, den Treiber aktiviert und ein Statustelegramm abfordert..

Das klappt alles auch ganz gut mit:

Code
  public   { Public declarations }
    procedure WMDeviceChange(var Msg:TMessage); message WM_DEVICECHANGE;
....
procedure TForm1.WMDeviceChange(var Msg: TMessage);
var i:integer;
    Dev:TnrUsbDevice;
begin
   nrUSB1.Update;
    Screen.Cursor := crHourGlass;
try
  i := nrUsb1.DeviceIndex;
  nrUsb1.WMDeviceChange(Msg);
  nrUsb1.DeviceIndex := i;
 if (i = -1) AND (nrUsb1.DeviceCount >= 1)  then
  begin
   nrUsb1.DeviceIndex:=   nrUsb1.DeviceCount -1;
  end
 else
  begin
      nrUSB1.Active := False;
       nrUSBPipePair1.Active := False;
  end;
  Screen.Cursor := crDefault;

      UpdateControls; // hier wird der Treiber auf Aktiv gesetzt und das 1. Statuspaket abgeholt

  except
    nrUSB1.Active := False;
     nrUSBPipePair1.Active := False;
      Screen.Cursor := crDefault;
  end;

end;


Egal, ob ich den XMEGA Resete, Abschalte, aus- und wieder einstecke. Das
kann das Windows-Programm ohne Probleme ab....ABER
Gerade eben ist mir aufgefallen, das diese Routine bei JEDEM DeviceChange einen neuen Connect meines XMEGAs ausführt :(

Das will ich aber gar nicht :(

Hat Jemand eine Idee, wie ich das "message WM_DEVICECHANGE" nur auf meine PID/VID beziehen kann?

Gruß
Thorsten
miparo
Administrator
Avatar
Gender:
Location: Germany
Age: 59
Posts: 956
Registered: 09 / 2007
Subject:

Re: USB-Funktionen mit WM_DEVICECHANGE

 · 
Posted: 03.09.2014 - 20:14  ·  #2
Hi pvs,
evtl. mit dem Code getrennt für ein Connect /disconnect:
Code

constructor TComponentUSB.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FWindowHandle := AllocateHWnd(WndProc);
  USBRegister;
end;

destructor TComponentUSB.Destroy;
begin
  DeallocateHWnd(FWindowHandle);
  inherited Destroy;
end;

procedure TComponentUSB.WndProc(var Msg: TMessage);
begin
  if (Msg.Msg = WM_DEVICECHANGE) then begin
    try
      WMDeviceChange(Msg);
    except
      Application.HandleException(Self);
    end;
  end
  else
    Msg.Result := DefWindowProc(FWindowHandle, Msg.Msg, Msg.wParam, Msg.lParam);
end;

procedure TComponentUSB.WMDeviceChange(var Msg: TMessage);
var
  devType: Integer;
  Datos: PDevBroadcastHdr;
begin
  if (Msg.wParam = DBT_DEVICEARRIVAL) or (Msg.wParam = DBT_DEVICEREMOVECOMPLETE) then
  begin
    Datos := PDevBroadcastHdr(Msg.lParam);
    devType := Datos^.dbch_devicetype;
    if devType = DBT_DEVTYP_DEVICEINTERFACE then begin // USB Device
      if Msg.wParam = DBT_DEVICEARRIVAL then begin
        if Assigned(FOnUSBArrival) then
          FOnUSBArrival(Self);
      end
      else begin
        if Assigned(FOnUSBRemove) then
          FOnUSBRemove(Self);
      end;
    end;
  end;
end;

function TComponentUSB.USBRegister: Boolean;
var
  dbi: DEV_BROADCAST_DEVICEINTERFACE;
  Size: Integer;
  r: Pointer;
begin
  Result := False;
  Size := SizeOf(DEV_BROADCAST_DEVICEINTERFACE);
  ZeroMemory(@dbi, Size);
  dbi.dbcc_size := Size;
  dbi.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
  dbi.dbcc_reserved := 0;
  dbi.dbcc_classguid := GUID_DEVINTERFACE_USB_DEVICE;
  dbi.dbcc_name := 0;

  r:= RegisterDeviceNotification(FWindowHandle, @dbi, DEVICE_NOTIFY_WINDOW_HANDLE);
  if Assigned(r) then Result := True;
end;


//------------
Type
  TForm ..
    public
    USBwatch: TComponentUSB;
    procedure DoOnConnect(Sender: TObject);
    procedure DoOnDisconnect(Sender: TObject);


Procedure  .. FormCreate;
   USBwatch := TComponentUSB.Create(MainProg);
  USBwatch.OnUSBArrival := DoOnConnect;
  USBwatch.OnUSBRemove := DoOnDisconnect;


Dafür musst du das mit DEINER Driver GUID registrieren.

miparo
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Re: USB-Funktionen mit WM_DEVICECHANGE

 · 
Posted: 03.09.2014 - 21:39  ·  #3
Quote by miparo

Hi pvs,
evtl. mit dem getrennt für ein Connect /disconnect:
Code

constructor TComponentUSB.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FWindowHandle := AllocateHWnd(WndProc);
  USBRegister;
end;

destructor TComponentUSB.Destroy;
begin
  DeallocateHWnd(FWindowHandle);
  inherited Destroy;
end;

procedure TComponentUSB.WndProc(var Msg: TMessage);
begin
  if (Msg.Msg = WM_DEVICECHANGE) then begin
    try
      WMDeviceChange(Msg);
    except
      Application.HandleException(Self);
    end;
  end
  else
    Msg.Result := DefWindowProc(FWindowHandle, Msg.Msg, Msg.wParam, Msg.lParam);
end;

procedure TComponentUSB.WMDeviceChange(var Msg: TMessage);
var
  devType: Integer;
  Datos: PDevBroadcastHdr;
begin
  if (Msg.wParam = DBT_DEVICEARRIVAL) or (Msg.wParam = DBT_DEVICEREMOVECOMPLETE) then
  begin
    Datos := PDevBroadcastHdr(Msg.lParam);
    devType := Datos^.dbch_devicetype;
    if devType = DBT_DEVTYP_DEVICEINTERFACE then begin // USB Device
      if Msg.wParam = DBT_DEVICEARRIVAL then begin
        if Assigned(FOnUSBArrival) then
          FOnUSBArrival(Self);
      end
      else begin
        if Assigned(FOnUSBRemove) then
          FOnUSBRemove(Self);
      end;
    end;
  end;
end;

function TComponentUSB.USBRegister: Boolean;
var
  dbi: DEV_BROADCAST_DEVICEINTERFACE;
  Size: Integer;
  r: Pointer;
begin
  Result := False;
  Size := SizeOf(DEV_BROADCAST_DEVICEINTERFACE);
  ZeroMemory(@dbi, Size);
  dbi.dbcc_size := Size;
  dbi.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
  dbi.dbcc_reserved := 0;
  dbi.dbcc_classguid := GUID_DEVINTERFACE_USB_DEVICE;
  dbi.dbcc_name := 0;

  r:= RegisterDeviceNotification(FWindowHandle, @dbi, DEVICE_NOTIFY_WINDOW_HANDLE);
  if Assigned(r) then Result := True;
end;


//------------
Type
  TForm ..
    public
    USBwatch: TComponentUSB;
    procedure DoOnConnect(Sender: TObject);
    procedure DoOnDisconnect(Sender: TObject);


Procedure  .. FormCreate;
   USBwatch := TComponentUSB.Create(MainProg);
  USBwatch.OnUSBArrival := DoOnConnect;
  USBwatch.OnUSBRemove := DoOnDisconnect;


Dafür musst du das mit DEINER Driver GUID registrieren.

miparo


Hallo miparo,

:) Super, das ist wohl die Lösung. Schaue ich mir mal genauer an. Danke Dir

Gruß
Thorsten
miparo
Administrator
Avatar
Gender:
Location: Germany
Age: 59
Posts: 956
Registered: 09 / 2007
Subject:

Re: USB-Funktionen mit WM_DEVICECHANGE

 · 
Posted: 04.09.2014 - 02:06  ·  #4
anbei noch der Rest:
Code

Type
 PDevBroadcastHdr = ^DEV_BROADCAST_HDR;
  DEV_BROADCAST_HDR = packed record
    dbch_size: DWORD;
    dbch_devicetype: DWORD;
    dbch_reserved: DWORD;
  end;

  PDevBroadcastDeviceInterface = ^DEV_BROADCAST_DEVICEINTERFACE;
  DEV_BROADCAST_DEVICEINTERFACE = record
    dbcc_size: DWORD;
    dbcc_devicetype: DWORD;
    dbcc_reserved: DWORD;
    dbcc_classguid: TGUID;
    dbcc_name: short;
  end;

const
  GUID_DEVINTERFACE_USB_DEVICE: TGUID = '{ DEINE DeviceGUID }';  
// aus DEINEM libusb Treiber.inf die DeviceGUID  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  DBT_DEVICEARRIVAL = $8000; // system detected a new device
  DBT_DEVICEREMOVECOMPLETE = $8004; // device is gone
  DBT_DEVTYP_DEVICEINTERFACE = $00000005; // device interface class



dann sollte das passen.

miparo
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Re: USB-Funktionen mit WM_DEVICECHANGE

 · 
Posted: 07.09.2014 - 11:05  ·  #5
Hallo miparo,

ich habe das ganze jetzt in eine Komponente gepackt. Aber ist schon ne Ewigkeit her wo ich mit Komponenten rumgemacht habe.

Code
  type
  TComponentUSB = class(TComponent)
  private
    { Private-Deklarationen }
    FWindowHandle: HWND;
    FOnUSBArrival: TNotifyEvent;
    FOnUSBRemove: TNotifyEvent;
    FGUID_DEVINTERFACE_USB_DEVICE : STRING =  '{4266AEE3-A7D8-4DD2-B979-D64FB674F68A}';
    procedure WndProc(var Msg: TMessage);
    function USBRegister: Boolean;
  protected
    { Protected-Deklarationen }
    procedure WMDeviceChange(var Msg: TMessage); dynamic;
  public
    { Public-Deklarationen }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published-Deklarationen }
    property GUID_DEVINTERFACE_USB_DEVICE : STRING read FGUID_DEVINTERFACE_USB_DEVICE;
    property OnUSBArrival: TNotifyEvent read FOnUSBArrival write FOnUSBArrival;
    property OnUSBRemove: TNotifyEvent read FOnUSBRemove write FOnUSBRemove;
  end;


Da ich diese Componente gerne für mehrere Projekte nutzen möchte, wollte ich die GUID_DEVINTERFACE_USB_DEVICE gerne als Attribute Visuell übergeben.
Nur wenn ich den STRING leer lasse erhalte ich beim einfügen der Komponente in der Form einen Fehler "...GUID_DEVINTERFACE_USB_DEVICE hat ungültigen wert...."

Code
function TComponentUSB.USBRegister: Boolean;
var
   dbi: DEV_BROADCAST_DEVICEINTERFACE;
   Size: Integer;
   r: Pointer;
begin
   Result := False;
   Size := SizeOf(DEV_BROADCAST_DEVICEINTERFACE);
   ZeroMemory(@dbi, Size);
   dbi.dbcc_size := Size;
   dbi.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
   dbi.dbcc_reserved := 0;
   dbi.dbcc_classguid  := StringToGUID( FGUID_DEVINTERFACE_USB_DEVICE );
   dbi.dbcc_name := 0;

   r := RegisterDeviceNotification(FWindowHandle, @dbi,
     DEVICE_NOTIFY_WINDOW_HANDLE
     );
   if Assigned(r) then Result := True;
end;

Die Routine habe ich mit dem StringToGUID angepasst, damit ich den STRING aus dem Attributen verwenden kann.

Ich stehe gerade auf dem Schlauch, ich weiss aber es geht (hatte ich damals zu Delphi 1 Zeiten auch mal gemacht. Wie kann ich der Componente/Attribute einen Standardwert übergeben, damit er nicht mehr mault :)

So geht's nicht ;)
Code

    FGUID_DEVINTERFACE_USB_DEVICE : STRING =  '{4266AEE3-A7D8-4DD2-B979-D64FB674F68A}';


Ich bin mir aber sicher das es geht.....nur fällt es mir nicht mehr ein... :(

Wenn Jemand daran bedarf hat, kann ich die Componente dann gerne hier posten..
Wenn sie läuft ;)

Gruß
Thorsten
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Re: USB-Funktionen mit WM_DEVICECHANGE

 · 
Posted: 07.09.2014 - 11:48  ·  #6
Hallo....

ich wusste es geht ;)
.. mit dem "property ...Default" geht es bei einem String nicht.

Man muss den Write in den Property aktivieren und in dem ...Create den Standard zuweisen...

Hier der Code und das Package:
Code
unit PVS_ComponentUSB;

interface

uses
  Windows, Messages, SysUtils, Classes, Forms;

type

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

   PDevBroadcastDeviceInterface  = ^DEV_BROADCAST_DEVICEINTERFACE;
   DEV_BROADCAST_DEVICEINTERFACE = record
     dbcc_size: DWORD;
     dbcc_devicetype: DWORD;
     dbcc_reserved: DWORD;
     dbcc_classguid: TGUID;
     dbcc_name: short;
   end;

const
 //  coGUID_DEVINTERFACE_USB_DEVICE: TGUID = '{4266AEE3-A7D8-4DD2-B979-D64FB674F68A}';
   DBT_DEVICEARRIVAL          = $8000;          // system detected a new device
   DBT_DEVICEREMOVECOMPLETE   = $8004;          // device is gone
   DBT_DEVTYP_DEVICEINTERFACE = $00000005;      // device interface class


  type
  TComponentUSB = class(TComponent)
  private
    { Private-Deklarationen }
    FWindowHandle: HWND;
    FOnUSBArrival: TNotifyEvent;
    FOnUSBRemove: TNotifyEvent;
    FGUID_DEVINTERFACE_USB_DEVICE : STRING;
    procedure WndProc(var Msg: TMessage);
    function USBRegister: Boolean;
//    procedure SetGUID_DEVINTERFACE_USB_DEVICE(Value: TGUID);
  protected
    { Protected-Deklarationen }
    procedure WMDeviceChange(var Msg: TMessage); dynamic;
  public
    { Public-Deklarationen }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published-Deklarationen }
    property GUID_DEVINTERFACE_USB_DEVICE : STRING read FGUID_DEVINTERFACE_USB_DEVICE write FGUID_DEVINTERFACE_USB_DEVICE;
    property OnUSBArrival: TNotifyEvent read FOnUSBArrival write FOnUSBArrival;
    property OnUSBRemove: TNotifyEvent read FOnUSBRemove write FOnUSBRemove;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('PVS', [TComponentUSB]);
end;


constructor TComponentUSB.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);
   FGUID_DEVINTERFACE_USB_DEVICE:=  '{4266AEE3-A7D8-4DD2-B979-D64FB674F68A}'; // Standardsetzen
   FWindowHandle := AllocateHWnd(WndProc);
   USBRegister;
end;

destructor TComponentUSB.Destroy;
begin
   DeallocateHWnd(FWindowHandle);
   inherited Destroy;
end;

procedure TComponentUSB.WndProc(var Msg: TMessage);
begin
   if (Msg.Msg = WM_DEVICECHANGE) then
   begin
     try
       WMDeviceChange(Msg);
     except
       Application.HandleException(Self);
     end;
   end
   else
     Msg.Result := DefWindowProc(FWindowHandle, Msg.Msg, Msg.wParam, Msg.lParam);
end;

procedure TComponentUSB.WMDeviceChange(var Msg: TMessage);
var
   devType: Integer;
   Datos: PDevBroadcastHdr;
begin
   if (Msg.wParam = DBT_DEVICEARRIVAL) or (Msg.wParam = DBT_DEVICEREMOVECOMPLETE) then
   begin
     Datos := PDevBroadcastHdr(Msg.lParam);
     devType := Datos^.dbch_devicetype;
     if devType = DBT_DEVTYP_DEVICEINTERFACE then
     begin // USB Device
       if Msg.wParam = DBT_DEVICEARRIVAL then
       begin
         if Assigned(FOnUSBArrival) then
           FOnUSBArrival(Self);
       end
       else
       begin
         if Assigned(FOnUSBRemove) then
           FOnUSBRemove(Self);
       end;
     end;
   end;
end;

function TComponentUSB.USBRegister: Boolean;
var
   dbi: DEV_BROADCAST_DEVICEINTERFACE;
   Size: Integer;
   r: Pointer;
begin
   Result := False;
   Size := SizeOf(DEV_BROADCAST_DEVICEINTERFACE);
   ZeroMemory(@dbi, Size);
   dbi.dbcc_size := Size;
   dbi.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
   dbi.dbcc_reserved := 0;
   dbi.dbcc_classguid  := StringToGUID( FGUID_DEVINTERFACE_USB_DEVICE );
   dbi.dbcc_name := 0;

   r := RegisterDeviceNotification(FWindowHandle, @dbi,
     DEVICE_NOTIFY_WINDOW_HANDLE
     );
   if Assigned(r) then Result := True;
end;


//procedure TComponentUSB.SetGUID_DEVINTERFACE_USB_DEVICE(Value: TGUID);
//begin
//  if Value <> FZahl1 then
//    FZahl1 := Value;
//end;

end.


Allerdings läuft es nicht so wie es soll, evtl. habe ich bei der GUID einen Fehler gemacht.
Die GUID ist komischerweise nicht die, die ich bei meiner Treiberinstallation angegeben habe???

Bei der Treiberinstallation habe ich den Wert: {4266AEE3-A7D8-4DD2-B979-D64FB674F68A} übergeben, aber bei dem Gerätemanager / Geräteklasse-GUID steht: {36fc9e60-c465-11cf-8056-444553540000} Oder sind das zwei verschiedene Sachen?

Ich habe es jetzt mit beiden probiert, die Funktionen beim einstecken und entfernen werden nicht aufgerufen :(

Gruß
Thorsten
You must be logged in or your permissions are to low to see this Attachment(s).
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Re: USB-Funktionen mit WM_DEVICECHANGE

 · 
Posted: 27.09.2014 - 17:48  ·  #7
Hallo miparo,

ich bekomme es nicht zum laufen. Auf meine DeviceGUID = "{716A4FE4-4927-46C6-993B-06EB45DFD9A1}" reagiert er nicht, wo finde ich denn diese? Beim Gerätemanager steht eine andere Nummer, aber auf die reagiert das Tool auch nicht.

Komisch ist auch, das in dem Tool die DeviceClass 5 eingetragen ist aber im Gerätemanager DeviceClass 0 steht ???

Gibt es ein Tool, mit dem alle Messages sichtbar machen kann? Früher hatte ich mal ein Tool vom Microsoft VisualStudio, ich glaube WinSight oder WinSpy (so in der Richtung)?

Gruß
Thorsten
miparo
Administrator
Avatar
Gender:
Location: Germany
Age: 59
Posts: 956
Registered: 09 / 2007
Subject:

Re: USB-Funktionen mit WM_DEVICECHANGE

 · 
Posted: 30.09.2014 - 16:31  ·  #8
Ich werde dir die Tage was getestetes posten.

miparo
Selected quotes for multi-quoting:   0

Registered users in this topic

Currently no registered users in this section

The statistic shows who was online during the last 5 minutes. Updated every 90 seconds.
MySQL Queries: 15 · Cache Hits: 14   138   152 · Page-Gen-Time: 0.033774s · Memory Usage: 2 MB · GZIP: on · Viewport: SMXL-HiDPI