Problem mit Rescan von SCSi Bus

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
Benutzeravatar
Lupo
Beiträge: 147
Registriert: 16.02.2005 15:15

Problem mit Rescan von SCSi Bus

Beitrag von Lupo »

Ich hab ein Problem:

Ich habe zwei SCSI Scanner an einem SCSI Controller angeschlossen
und es funktioniert alles ok.

Nun ist es aber so, daß das Windoof die Geräte nur dann kennt,
wenn man sie schon beim PC-Booten eingeschalten hat. Nun läuft der
PC aber den ganzen Tag und die Scanner werden ja nicht immer
gebraucht und so schaltet sie niemand in der Früh ein.

Wenn man aber den Scanner braucht und schaltet ihn ein
dann läuft nix weil Windos kennt ihn nicht und die Scansoftware hängt
sich auf und dann muß man sie im Taskmanager killen :evil:

Jetzt hab ich von Bingo einenCode gefunden für einen SCSI Bus
rescan. Er funktionirt auch aber meistens vergisst man ihn zu
starten und dann hängt das Scanprogramm wieder :|

Jetzt hab ich das ganze in eine Repeatschleife gestellt und auf
20 sekunden delay gestellt (hier zum Testen nur 5 Sekunden) und
lade das Programm in den Autostart

Code: Alles auswählen

Repeat
  OpenLibrary(1,"cfgmgr32.dll") 
  CallFunction(1, "CM_Locate_DevNodeA",@calli,0,0)
  CallFunction(1, "CM_Reenumerate_DevNode_Ex",calli,0,0)  
  CloseLibrary(1)   
  Delay(5000)
ForEver 
Es läuft auch aber es hat eine Nebenwirkung die das
ganze unbrauchbar macht:

Für 1/2 Sekunde wird der ganze Bildschirm schwarz als ob er
ganz kurz in den Vollbild-Konsolenmodus schalten würde und
das wiederholt sich alle 20 ( jetzt 5) Sekunden :(

Wers ausprobieren möchte sollte aber eine SCSi Karte im PC
haben sonst geschieht nix weil der Handle von der Karte fehlt.
Es ist die zweite CallFunktion die den Mist macht.....

Hat jemand eine Idee wie man das Bildschirmumschalten
wegbekommt oder hat jemand einen andern Code für das
SCSI Bus rescannen ? Ich hab XP Home.

Google gibt leider nicht viel für WIndows her, nur MS C-Code und den
kann ich nicht umsetzen und viele Linux Seiten mit dem Thema.

Danke

Lupo
Benutzeravatar
bingo
Beiträge: 118
Registriert: 16.09.2004 18:33
Wohnort: thüringen
Kontaktdaten:

Beitrag von bingo »

hier der "aktuelle" code ...

Code: Alles auswählen

;rescan
#CM_LOCATE_DEVNODE_NORMAL = 0
#CM_REENUMERATE_NORMAL = 0 
OpenLibrary(1,"setupapi.dll") 
*F1 = IsFunction(1, "CM_Locate_DevNodeA") 
*F2 = IsFunction(1, "CM_Reenumerate_DevNode") 
CallFunctionFast(*F1,@devhandle,0,#CM_LOCATE_DEVNODE_NORMAL) 
CallFunctionFast(*F2,devhandle,#CM_REENUMERATE_NORMAL) 
CloseLibrary(1)
... wirkt wie button "nach geänderter hardware suchen" im gerätemanager .

in deinem fall ... wird der button alle paar sekunden geklickt .
besser:

mach ein kleines programm und leg das auf den dektop :

* msgbox "bitte scanner einschalten !"
* rescan
* paar sekunden warten
* scanner-anwendung per runprogram laden ...
1:0>1
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Problem mit Rescan von SCSi Bus

Beitrag von Danilo »

Lupo hat geschrieben:

Code: Alles auswählen

Repeat
  OpenLibrary(1,"cfgmgr32.dll") 
  CallFunction(1, "CM_Locate_DevNodeA",@calli,0,0)
  CallFunction(1, "CM_Reenumerate_DevNode_Ex",calli,0,0)  
  CloseLibrary(1)   
  Delay(5000)
ForEver 
Es läuft auch aber es hat eine Nebenwirkung die das
ganze unbrauchbar macht:

Für 1/2 Sekunde wird der ganze Bildschirm schwarz als ob er
ganz kurz in den Vollbild-Konsolenmodus schalten würde und
das wiederholt sich alle 20 ( jetzt 5) Sekunden :(
Bei mir flackert der Bildschirm nicht.

Davon mal abgesehen ist das flackern aber erklärbar:
Du ReEnumerierst hier alle Devices, angefangen mit Root, und
da sind eben auch "DISPLAY", "Root\LEGACY_VGA" und noch
viel mehr dabei.

Versuche mal nur die SCSI\* Nodes zu re-enumerieren, dann
sollte das flackern des Bildschirms weg sein.
Außerdem geht es auch schneller nur die SCSI-Geräte zu
re-enumerieren. Mit Deinem Code dauert es bei mir beim
ersten mal ~15 Sekunden, dann noch 5 - 6 Sekunden pro
Durchlauf.

Nur die SCSI-Geräte zu enumerieren geht dagegen ohne
Verzögerung:

Code: Alles auswählen

Structure _SCSI_NODES
  name.s
  devnode.l
EndStructure

NewList DevNode_SCSI._SCSI_NODES()

If OpenLibrary(1,"cfgmgr32.dll")

  If CallFunction(1,"CM_Get_Device_ID_List_SizeA",@size,0,0)=0
    If size
      buffer=AllocateMemory(size)
      If buffer
        If CallFunction(1,"CM_Get_Device_ID_ListA",0,buffer,size,0)=0
          Repeat
            Dev$ = PeekS(buffer,64000)
            If Dev$
              Debug Dev$
              If Left(Dev$,4)="SCSI"
                AddElement(DevNode_SCSI())
                DevNode_SCSI()\name=Dev$
              EndIf
              buffer+Len(Dev$)+1
            EndIf
          Until Dev$ = ""
          Debug "----------"
        EndIf
        FreeMemory(buffer)
      EndIf
    EndIf
  EndIf

  If CountList(DevNode_SCSI())
    ForEach DevNode_SCSI()
      If CallFunction(1,"CM_Locate_DevNodeA",@calli,DevNode_SCSI()\name,0)=0
        DevNode_SCSI()\devnode = calli
        Debug "DevNode for "+DevNode_SCSI()\name+":"
        Debug "   - "+StrU(calli,#LONG)
      EndIf
    Next
    
    Repeat
      Debug "------------------------------------"
      Debug "ReEnumerating:"
      ForEach DevNode_SCSI()
        If DevNode_SCSI()\devnode
          Debug DevNode_SCSI()\name
          If CallFunction(1,"CM_Reenumerate_DevNode_Ex",DevNode_SCSI()\devnode,0,0)=0
            Debug "   - ReEnumeration OK"
          Else
            Debug "   - ReEnumeration failed!"
          EndIf
        EndIf
      Next
      Delay(5000)
      
      x+1
    Until x = 5 ; Forever
  Else
    Debug "Nothing to re-enumerate"
  EndIf
  
  Debug "<<< END >>>"
  
  CloseLibrary(1)

EndIf
Schau Dir mal den Debug-Output genau an, dort siehst Du
die DevNodes für Deine SCSI-Geräte.

Wenn das Programm immer auf dem gleichen Rechner läuft,
könntest Du die DevNodes direkt im Code für ReEnumerate
verwenden, solange an der Hardware nichts geändert wird.

Ich würde aber von der Art her die obige Methode verwenden.
So werden beim Start des Programmes alle SCSI\*-Member
gesucht und dann ReEnumeriert.

Falls das bei Dir nicht geht, mußt Du Dir aus der Liste der
Devices versuchen das richtige rauszusuchen. Vielleicht
siehst Du dort direkt Deine SCSI-Karte. Unter "PCI" sollte
die ja bestimmt mit dabei sein.
Dann scannst Du immer nur diese Karte nach neu eingeschalteten
Geräten...
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
Lupo
Beiträge: 147
Registriert: 16.02.2005 15:15

Beitrag von Lupo »

zuerst danke für die Antworten :)

@bingo

ja sicher kann man so ne Abfrage machen, aber ich hab den
ehrgeiz das automatisch zu lösen, alles andere ist halt ein
Kompromiss.

@ Danilo

Danke für die viele Arbeit mit dem Code :)

Ich hab mich jetzt an die 3 Stunden damit beschäftigt aber kriegs
nicht ans laufen: :cry:

Der Code hat ja 3 Teile:

Teil1: Listing der Geräte

Der erste Teil ist ok. Es werden alle
Komponenten gelistet, auch die SCSI Geräte mit Namen und so.

Was auffällt ist dass die SCSI Geräte auch dann gelistet werden
wenn sie nicht eingeschaltet sind auch unmittelbar nach einem
Reboot werden sie angezeigt, steht scheinbar ewig in der
Reg, aber das macht ja nichts.

durch die Einschränkung auf "SCSI" werden auch nur die
SCSI Geräte in die linked List eingetragen.

Teil 2 CM_Locate_DevNodeA

Die Funktion soll ja aufgrund des (langen) Namens eine DevNode
zurückgeben (was ist denn das ???, wohl eine art handle?)

Nun gibt aber diese Funktion keine Node zurück
wenn das SCSI Gerät neu eingeschaltet ist :|

Aber es gibt einen Node zurück wenn das SCSI Gerät
bereits angemeldet ist wenn man z.B. bootet und das Gerät ist
von Anfang an eingeschaltet.

So wie ichs verstehe solte ja diese Funktion bereits einen Node
zurückgeben wenn das Gerät nur eingeschaltet ist, tuts aber nicht.

Teil 3 CM_Reenumerate_DevNode_Ex

Das soll nun die Geräte neu anmelden, das tuts auch aber
nur wenn eine Node da ist, klar. Und die Node kommt aber nur dann
wenn das Gerät ohnedies schon angemeldet ist ..... :|

-----------------------------------------

Ich hab versucht eine Doku über die beiden Funktionen zu
finden aber die platform SDK kennt die Funktion nicht aber in google
war zumindest über CM_Reenumerate_DevNode_Ex was drinnen.
Da gibt es an der dritten Stelle Optionflags, aber da steht natürlich
kein Wert dabei und nix zu finden welcher Wert .
(Das macht mich krank nix zu finden und dumm rumzusuchen
und nicht wissen wie man zu einer exakten Doku kommt :evil:)

Jetzt hab ich eben mit Probiern diese Konstanten gesetzt und wie ich
bei CM_Locate_DevNodeA die 0 auf 1 setzte bekomme ich auf
einmal Nodes auch für die nicht angemeldeten Geräte, auch wenn
sie nicht eingeschaltet sind.

Aber ich hab mich zu früh gefreut, mit diesen Nodes fängt
CM_Reenumerate_DevNode_Ex nix an und verweigert. Bei dem Befehl
hat auch das Herumprobieren mit den Konstanten nicht genutzt.


Ich hab mir dann noch die Errorcodes ausgelesen:

Wenn CM_Locate_DevNodeA versagt, dann kommt 13 The data is invalid

Wenn man mit Nodes in CM_Reenumerate_DevNode_Ex reingeht und die
Funktion versagt, dann kommt 5 Access denied

Eventuell muss man noch irgendeine Berechtigung freischalten
das ist ja zb auch beim Öffnen von Laufwerken notwendig ??

Ich hoffe das Problem läßt sich lösen. Aufgeben tu ich so ungern.

Danke
LUPO
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Beitrag von Danilo »

Lupo hat geschrieben:Nun gibt aber diese Funktion keine Node zurück
wenn das SCSI Gerät neu eingeschaltet ist :|
Deshalb sagte ich auch am Schluß das Du besser Deine
SCSI-Karte scannen sollst. Konnte mir sowas schon denken.

SCSI\ sind die Geräte selbst. Du brauchst aber die SCSI-Karte,
und die wird wohl in PCI\ zu finden sein.

Lupo hat geschrieben:Ich hab versucht eine Doku über die beiden Funktionen zu
finden aber die platform SDK kennt die Funktion nicht aber in google
war zumindest über CM_Reenumerate_DevNode_Ex was drinnen.
Da gibt es an der dritten Stelle Optionflags, aber da steht natürlich
kein Wert dabei und nix zu finden welcher Wert .
(Das macht mich krank nix zu finden und dumm rumzusuchen
und nicht wissen wie man zu einer exakten Doku kommt :evil:)
Steht alles im MS DDK (Driver Development Kit)


Schau mal folgendes an:

Code: Alles auswählen

Structure _SCSI_NODES
  name.s
  devnode.l
EndStructure

NewList DevNode_SCSI._SCSI_NODES()

If OpenLibrary(1,"cfgmgr32.dll")

  If CallFunction(1,"CM_Get_Device_ID_List_SizeA",@size,0,0)=0
    If size
      buffer=AllocateMemory(size)
      If buffer
        If CallFunction(1,"CM_Get_Device_ID_ListA",0,buffer,size,0)=0
          Repeat
            Dev$ = PeekS(buffer,64000)
            If Dev$
              calli=0
              If CallFunction(1,"CM_Locate_DevNodeA",@calli,Dev$,0)=0
                Debug RSet(StrU(calli,#LONG),6,"0")+": "+Dev$
              Else
                Debug "------------: "+Dev$
              EndIf
              If Left(Dev$,4)="SCSI"
                AddElement(DevNode_SCSI())
                DevNode_SCSI()\name=Dev$
              EndIf
              buffer+Len(Dev$)+1
            EndIf
          Until Dev$ = ""
          Debug "----------"
        EndIf
        FreeMemory(buffer)
      EndIf
    EndIf
  EndIf

  If CountList(DevNode_SCSI())
    ForEach DevNode_SCSI()
      If CallFunction(1,"CM_Locate_DevNodeA",@calli,DevNode_SCSI()\name,0)=0
        DevNode_SCSI()\devnode = calli
        Debug "DevNode for "+DevNode_SCSI()\name+":"
        Debug "   - "+StrU(calli,#LONG)

        A$ = Space(1024)
        While CallFunction(1,"CM_Get_Parent",@out,calli,0)=0
          If CallFunction(1,"CM_Get_Device_IDA",out,@A$,1024,0)=0
            ParentName$ = "   ("+PeekS(@A$)+")"
          Else
            ParentName$ = "---"
          EndIf
          Debug "   - Parent: "+StrU(out,#LONG)+ParentName$
          calli = out
        Wend
      EndIf
      Debug "---"
    Next
    
;     Repeat
;       Debug "------------------------------------"
;       Debug "ReEnumerating:"
;       ForEach DevNode_SCSI()
;         If DevNode_SCSI()\devnode
;           Debug DevNode_SCSI()\name
;           If CallFunction(1,"CM_Reenumerate_DevNode_Ex",DevNode_SCSI()\devnode,0,0)=0
;             Debug "   - ReEnumeration OK"
;           Else
;             Debug "   - ReEnumeration failed!"
;           EndIf
;         EndIf
;       Next
;       Delay(5000)
;       
;       x+1
;     Until x = 5 ; Forever
  Else
    Debug "Nothing to re-enumerate"
  EndIf
  
  Debug "<<< END >>>"
  
  CloseLibrary(1)

EndIf
Das solltest Du mal mit eingeschalteten Geräten laufen lassen.
Dann zeigt es als letztes Deine Geräte an, die DevNode des
Gerätes, und dann noch die darüberliegenden DevNodes und
Gerätenamen - bis hin zu Root.

Der 1. Parent-Eintrag zu jedem Gerät müßte die SCSI-Karte
sein, und die dürfte ein PCI\-Gerät sein.

Diesen Namen der SCSI-Karte, bei mir zum Beispiel:
"PCI\VEN_1000&DEV_0020&SUBSYS_00000000&REV_01\3&61AAA01&0&40" (1.Port auf der Karte)
"PCI\VEN_1000&DEV_0020&SUBSYS_00000000&REV_01\3&61AAA01&0&41" (2.Port auf der Karte)
nimmst Du dann immer für Locate_DevNode:

Code: Alles auswählen

If OpenLibrary(1,"cfgmgr32.dll")
  If CallFunction(1, "CM_Locate_DevNodeA",@calli,"PCI\VEN_1000&DEV_0020&SUBSYS_00000000&REV_01\3&61AAA01&0&40",0)=0
    If CallFunction(1, "CM_Reenumerate_DevNode_Ex",calli,0,0)=0
      ok=1
    EndIf
  EndIf
  CloseLibrary(1)   
EndIf

If ok
  RunProgram("DeinScannerProgramm.exe")
EndIf
Wenn es mit Deiner SCSI-Karte nicht geht, dann nimm das
nächst-höhere Parent, bei mir z.B. "ACPI\PNP0A03\2&DABA3FF&0".

Das scannen der SCSI-Karte sollte aber eigentlich genügen.
Ich kann das hier selbst nicht testen, da ich keine ausschaltbaren
SCSI-Geräte habe, sondern nur interne Geräte die permanent
an sind.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
Eric
Beiträge: 303
Registriert: 05.09.2004 09:50
Wohnort: Göttingen

Beitrag von Eric »

Uns sonst könnte man doch ein kleines Programm schreiben, was den rescan macht und danach das eigendliche Scanprogramm aufruft, noch die Verknüpfungen auf das neue Programm ändern und fertig.
Benutzeravatar
Lupo
Beiträge: 147
Registriert: 16.02.2005 15:15

Beitrag von Lupo »

Uiiihh !! Es läuft !!!! :allright: :allright: :allright:

Danke Danilo für die viele Arbeit !

Also es funktioniert ganz einfach mit dem Code
mehr braucht man nicht. Ich hab mal meine eigene
SCSI-Karte eingetragen.

Code: Alles auswählen

  If OpenLibrary(1,"cfgmgr32.dll") 
      If CallFunction(1, "CM_Locate_DevNodeA",@calli,"PCI\VEN_9004&DEV_5078&SUBSYS_78509004&REV_03\4&11d7ad53&0&4040",0)=0 
        Debug "1"
        If CallFunction(1, "CM_Reenumerate_DevNode_Ex",calli,0,0)=0 
          Debug "2"
          ok=1 
        EndIf 
     EndIf 
    CloseLibrary(1)    
  EndIf
Ich hab jetzt noch aus der Schrottkiste ein paar alte
SCSI Laufwerke angehängt die ich einzeln abschalten kann
und alles ist perfekt. Was auffällt ist, dass es etwa 20 sekunden
braucht bis der obige Code neue Geräte findet, d.h. er läuft innerhalb
der ersten 20 sec. nach dem zuschalten wirkungslos durch.

Der Code ist überhaupt genial, weil wenn die SCSI Geräte
gleich geblieben sind laufen beide Funktionen blitzschnell durch.

Hat man ein SCSI Gerät dazugeschalten oder auch weggeschalten (!)
und sind die 20 sec vergangen dann merkt man das die Funktionen
einige Sekunden benötigen für das eintragen. Also richtig genial
für eine Repeat-Schleife ! :wink:

Einmal vor dem Scannen aufrufen nutzt nix wenn man nach dem
Scanner Einschalten nicht 20 sec wartet. Aber dafür gibts ja die Schleife.

Aber weil ich immer ein wenig lästig bin :mrgreen: und immer alles ziemlich
allgemein brauchbar machen will muß ich noch was zusätzliches
fragen:

Ich möchte jetzt noch aus der Registry diese SCSI-Karten Identifikation
auslesen weil die kann ja für jede Karte anders heissen, also z.B hier
das PCI\VEN_9004&DEV_5078&SUBSYS_78509004&REV_03\4&11d7ad53&0&4040

Jetzt hilft mir die Auflistung der PCI Devices aus der Liste von Danilos
Code (der erste ABschnitt ) nichts weil ich sehe daraus nicht was die
SCSI Karte ist :| Es gibt ja viele PCI Devices.

Jetzt hab ich mir gedacht ich kann das ja auch aus der Registry
rauslesen wie die SCSI Karten heissen. Auslesen kann ich das ja
mit RegOpenKeyEx_() und RegQueryValueEx_() und jetzt
ist nur mehr die Frage wo ich in der Reg suchen soll.

Ich hab mal in der Reg nach meinem SCSI Device gesucht
PCI\VEN_9004&DEV_5078&SUBSYS_78509004&REV_03\4&11d7ad53&0&4040
und hab das an mehreren Stellen gefunden:

Einmal unter
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\DeviceClasses\{1186654d-47b8-48b9-beb9-7df113ae3c67}

weiters
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\aic78xx\Enum

und
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet003\Control\DeviceClasses\{2accfe60-c130-11d2-b082-00a0c91efb8b}

und
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses\{2accfe60-c130-11d2-b082-00a0c91efb8b}

und
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aic78xx\Enum

Jetzt glaub ich wird wohl das CurrentControlSet das richtige sein (was
sind die anderen??) aber da ist jetzt die Frage wie ich von "SCSI-Karten"
auf den Eintrag >{2accfe60-c130-11d2-b082-00a0c91efb8b} komme :|

Irgendwie glaub ich manchmal ich kann das nie schaffen da einmal selbst
draufzukommen immer steh ich irgendwann an und komm mir doof vor :cry:

Danilo hat geschrieben
Steht alles im MS DDK (Driver Development Kit)
Ja das ist ein guter Hinweis aber wie ich da sehe muß man dafür
bezahlen und es kostet 199 $ und Spesen und das ist nicht drin
für die nächste Zeit weil ich spar auf einen neuen großen
Bildschirm (24") <) und der kostet 440,-- und ich hab erst 160,--
und da muss ich noch etliches proggen bis ich das zusammenhab.

Vielen Dank

LUPO
Antworten