Einstecken von SD Karte erkennen Nicht USB Stick

  • VB.NET
  • .NET (FX) 4.0

Es gibt 65 Antworten in diesem Thema. Der letzte Beitrag () ist von Amelie.

    @Amelie In Post #6 und Post #9 sind ein paar lokale Konstanten drinne, in Post #12 hast Du festgestellt, dass auf einige nicht verwiesen wird.
    @-Franky- meint, dass Du die von ihm aufgelisteten mal da abfragen solltest.
    Die Wedrte stehen hier: pinvoke.net/default.aspx/Enums/SHCNE.html
    @-Franky- Beim nächsten mal schreibst Du die Werte gleich hin. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hi

    Ich hab mal meinen VB6 Code auf .NET umgeschrieben. Unwichtiges habe ich dabei mal rausgelassen und es werden nur die Events SHCNE_MEDIAINSERTED und SHCNE_MEDIAREMOVED abgefragt bzw ausgewertet. Der Code erkennt auch das einlegen einer CD in das CD-Rom Laufwerk. Deswegen müsstest Du das ermittelte Laufwerk noch auswerten ob es ein Removable-Laufwerk und kein CD-Rom Laufwerk ist. Ausgaben erfolgen im Debug-Fenster!
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Imports System.Runtime.InteropServices
    4. Public Class Form1
    5. Private Const S_OK As Integer = &H0
    6. Private Const WM_DESTROY As Integer = &H2
    7. Private Const WM_SHNOTIFY As Integer = &H488
    8. Private Const CSIDL_DESKTOP As Integer = &H0
    9. Private Const GPFIDL_DEFAULT As Integer = &H0
    10. Private Const SHCNE_MEDIAREMOVED As Integer = &H40
    11. Private Const SHCNE_MEDIAINSERTED As Integer = &H20
    12. Private Enum SHCNRF As Integer
    13. SHCNRF_InterruptLevel = &H1
    14. SHCNRF_ShellLevel = &H2
    15. SHCNRF_RecursiveInterrupt = &H1000
    16. SHCNRF_NewDelivery = &H8000
    17. End Enum
    18. <StructLayout(LayoutKind.Sequential)>
    19. Private Structure SHChangeNotifyEntry
    20. Dim pidl As IntPtr
    21. <MarshalAs(UnmanagedType.Bool)> Dim fRecursive As Boolean
    22. End Structure
    23. <StructLayout(LayoutKind.Sequential)>
    24. Private Structure SHNOTIFYSTRUCT
    25. Dim dwItem1 As IntPtr
    26. Dim dwItem2 As IntPtr
    27. End Structure
    28. <DllImport("ole32.dll", EntryPoint:="CoTaskMemFree")>
    29. Private Shared Sub CoTaskMemFree(
    30. <[In]> ByVal hMem As IntPtr)
    31. End Sub
    32. <DllImport("shell32.dll", EntryPoint:="SHChangeNotifyRegister")>
    33. Private Shared Function SHChangeNotifyRegister(
    34. <[In]> ByVal hWnd As IntPtr,
    35. <[In]> ByVal fSources As SHCNRF,
    36. <[In]> ByVal fEvents As Integer,
    37. <[In]> ByVal wMsg As Integer,
    38. <[In]> ByVal cEntries As Integer,
    39. <[In]> ByVal lpps As SHChangeNotifyEntry) As Integer
    40. End Function
    41. <DllImport("shell32.dll", EntryPoint:="SHChangeNotifyDeregister")>
    42. Private Shared Function SHChangeNotifyDeregister(
    43. <[In]> ByVal hNotify As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
    44. End Function
    45. <DllImport("shell32.dll", EntryPoint:="SHGetFolderLocation")>
    46. Private Shared Function SHGetFolderLocation(
    47. <[In]> ByVal hwndOwner As IntPtr,
    48. <[In]> ByVal nFolder As Integer,
    49. <[In]> ByVal hToken As IntPtr,
    50. <[In]> ByVal dwReserved As Integer,
    51. <Out> ByRef pidl As IntPtr) As Integer
    52. End Function
    53. <DllImport("shell32.dll", EntryPoint:="SHChangeNotification_Lock")>
    54. Private Shared Function SHChangeNotification_Lock(
    55. <[In]> ByVal hChange As IntPtr,
    56. <[In]> ByVal dwProcId As Integer,
    57. <Out> ByRef ppidl As IntPtr,
    58. <Out> ByRef plEvent As Integer) As IntPtr
    59. End Function
    60. <DllImport("shell32.dll", EntryPoint:="SHChangeNotification_Unlock")>
    61. Private Shared Function SHChangeNotification_Unlock(
    62. <[In]> ByVal hLock As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    63. End Function
    64. <DllImport("shell32.dll", EntryPoint:="SHGetPathFromIDListEx")>
    65. Private Shared Function SHGetPathFromIDListEx(
    66. <[In]> ByVal pidl As IntPtr,
    67. <[In]> <MarshalAs(UnmanagedType.LPWStr)> ByVal pszPath As String,
    68. <[In]> ByVal cchPath As Integer,
    69. <[In]> ByVal uOpts As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
    70. End Function
    71. Private m_hSHNotify As Integer = 0
    72. Private m_hNotifyLock As IntPtr = IntPtr.Zero
    73. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    74. m_hSHNotify = RegisterNotify()
    75. End Sub
    76. Protected Overrides Sub WndProc(ByRef m As Message)
    77. Select Case m.Msg
    78. Case WM_SHNOTIFY
    79. ProcessShellNotify(m)
    80. Case WM_DESTROY
    81. UnregisterNotify()
    82. End Select
    83. MyBase.WndProc(m)
    84. End Sub
    85. Private Function RegisterNotify() As Integer
    86. Dim hSHNotify As Integer = 0
    87. Dim pPIDL As IntPtr = IntPtr.Zero
    88. Dim tSHCNE As SHChangeNotifyEntry = New SHChangeNotifyEntry
    89. If SHGetFolderLocation(IntPtr.Zero, CSIDL_DESKTOP,
    90. IntPtr.Zero, 0, pPIDL) = S_OK Then
    91. With tSHCNE
    92. .pidl = pPIDL
    93. .fRecursive = True
    94. End With
    95. CoTaskMemFree(pPIDL)
    96. hSHNotify = SHChangeNotifyRegister(Me.Handle,
    97. SHCNRF.SHCNRF_ShellLevel Or
    98. SHCNRF.SHCNRF_InterruptLevel Or
    99. SHCNRF.SHCNRF_RecursiveInterrupt Or
    100. SHCNRF.SHCNRF_NewDelivery,
    101. SHCNE_MEDIAINSERTED Or
    102. SHCNE_MEDIAREMOVED,
    103. WM_SHNOTIFY, 1, tSHCNE)
    104. End If
    105. Return hSHNotify
    106. End Function
    107. Private Sub UnregisterNotify()
    108. If m_hSHNotify <> 0 Then
    109. If SHChangeNotifyDeregister(m_hSHNotify) = True Then
    110. m_hSHNotify = 0
    111. End If
    112. End If
    113. End Sub
    114. Private Shared Sub ShellNotifyEvent(ByVal intEvent As Integer,
    115. ByVal tSHNS As SHNOTIFYSTRUCT)
    116. Dim strNullChar As Char = Convert.ToChar(0)
    117. Dim strPath1 As String = New String(strNullChar, 255)
    118. Dim strPath2 As String = New String(strNullChar, 255)
    119. If tSHNS.dwItem1 <> IntPtr.Zero Then
    120. If SHGetPathFromIDListEx(tSHNS.dwItem1, strPath1,
    121. strPath1.Length, GPFIDL_DEFAULT) = True Then
    122. strPath1 = strPath1.Substring(0, strPath1.IndexOf(strNullChar))
    123. Debug.Print(strPath1 & " " & LookUpSHCNE(intEvent))
    124. End If
    125. End If
    126. If tSHNS.dwItem2 <> IntPtr.Zero Then
    127. If SHGetPathFromIDListEx(tSHNS.dwItem2, strPath2,
    128. strPath2.Length, GPFIDL_DEFAULT) = True Then
    129. strPath2 = strPath2.Substring(0, strPath2.IndexOf(strNullChar))
    130. Debug.Print(strPath2 & " " & LookUpSHCNE(intEvent))
    131. End If
    132. End If
    133. End Sub
    134. Private Sub ProcessShellNotify(ByVal m As Message)
    135. Dim intEvent As Integer = 0
    136. Dim pPIDL As IntPtr = IntPtr.Zero
    137. If m_hNotifyLock = IntPtr.Zero Then
    138. m_hNotifyLock = SHChangeNotification_Lock(m.WParam, m.LParam.ToInt32,
    139. pPIDL, intEvent)
    140. If m_hNotifyLock <> IntPtr.Zero Then
    141. Dim tSHNS As SHNOTIFYSTRUCT = CType(Marshal.PtrToStructure(pPIDL,
    142. GetType(SHNOTIFYSTRUCT)), SHNOTIFYSTRUCT)
    143. If SHChangeNotification_Unlock(m_hNotifyLock) = True Then
    144. m_hNotifyLock = IntPtr.Zero
    145. End If
    146. ShellNotifyEvent(intEvent, tSHNS)
    147. End If
    148. End If
    149. End Sub
    150. Private Shared Function LookUpSHCNE(ByVal intEvent As Integer) As String
    151. Dim strRet As String = String.Empty
    152. Select Case intEvent
    153. Case SHCNE_MEDIAINSERTED
    154. strRet = "MEDIA INSERTED"
    155. Case SHCNE_MEDIAREMOVED
    156. strRet = "MEDIA REMOVED"
    157. End Select
    158. Return strRet
    159. End Function
    160. End Class

    Mfg -Franky-
    Hi

    So. Test auf meinem Laptop war auch erfolgreich. Hab aber eine kleine Änderung am Code vorgenommen. Könnte sein das das ganze deswegen zum Fehler führte. Hier die geänderte Funktion RegisterNotify.

    VB.NET-Quellcode

    1. Private Function RegisterNotify() As Integer
    2. Dim hSHNotify As Integer = 0
    3. Dim pPIDL As IntPtr = IntPtr.Zero
    4. Dim tSHCNE As SHChangeNotifyEntry = New SHChangeNotifyEntry
    5. If SHGetFolderLocation(IntPtr.Zero, CSIDL_DESKTOP,
    6. IntPtr.Zero, 0, pPIDL) = S_OK Then
    7. With tSHCNE
    8. .pidl = pPIDL
    9. .fRecursive = True
    10. End With
    11. hSHNotify = SHChangeNotifyRegister(Me.Handle,
    12. SHCNRF.SHCNRF_ShellLevel Or
    13. SHCNRF.SHCNRF_InterruptLevel Or
    14. SHCNRF.SHCNRF_RecursiveInterrupt Or
    15. SHCNRF.SHCNRF_NewDelivery,
    16. SHCNE_MEDIAINSERTED Or
    17. SHCNE_MEDIAREMOVED,
    18. WM_SHNOTIFY, 1, tSHCNE)
    19. Marshal.FreeCoTaskMem(pPIDL) ' <- erst nach SHChangeNotifyRegister freigeben
    20. 'CoTaskMemFree(pPIDL) ' <- API CoTaskMemFree durch Marshal.FreeCoTaskMem ersetzt.
    21. End If
    22. Return hSHNotify
    23. End Function
    Mfg -Franky-
    @-Franky- SHChangeNotifyRegister() knallt, das ist vor Deiner Änderung.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich glaube der letzte Parameter von SHChangeNotifyRegister() muss als ByRef übergeben werden,

    Edit: Und laut codeproject.com/Articles/3054/Shell-Notifications-in-C muss man beim ​DllImport-Attribut noch den EntryPoint manuell setzen, das könnte man evtl. auch noch probieren.

    -Franky- schrieb:

    Ich verstehe Deine Aussage jetzt so,
    Nö.
    Du hast Code geändert, der im Code nach der Exception steht, also noch gar nicht ablief.
    @nafets Jou, hier stehts auch:
    docs.microsoft.com/en-us/windo…re-shchangenotifyregister
    ====
    @-Franky- Also:
    Stecken SD-Adapter: Keine Reaktion.
    Stecken SD-Karte in Adapter: Wird angezeigt. 8o
    Abmelden SD-Karte: Keine Reaktion.
    Abziehen SD-Karte: Keine Reaktion.
    Stecken USB-Stick: Keine Reaktion.
    Abmelden USB-Stick: Keine Reaktion.
    Abziehen USB-Stick: Keine Reaktion.
    Fazit:
    Da wäre noch was zu tun. ;(
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „RodFromGermany“ ()

    Hi

    @nafets Letzter Parameter ByRef kann sein. Wenn man es aber genau nimmt, müsste im letzten Parameter ein Array von SHChangeNotifyEntry übergeben werden. Da hier aber nicht mehrere Sachen überwacht werden (Laufwerksüberwachung und Überwachung eines Ordner zB. gleichzeitig), geht es auch so. In VB6 hab ich das ByVal und Übergebe einen Pointer auf das erste Element vom SHChangeNotifyEntry-Array. Das mit dem EntryPoint #2 war zu Zeiten als die API SHChangeNotifyRegister noch nicht offiziell von MS dokumentiert war bzw. es den Einsprungspunkt mit Namen "SHChangeNotifyRegister" in der Shell32.dll noch nicht gab. Man konnte diese Funktion aber schon über deren Ordinalzahl #2 aufrufen.

    @RodFromGermany Stecken SD-Adapter/Abmelden SD-Karte (CardReader auswerfen!)/Stecken USB-Stick usw: Keine Reaktion. Jupp weil nur SHCNE_MEDIAREMOVED und SHCNE_MEDIAINSERTED überwacht werden und nicht ob ein Laufwerk entfernt oder hinzugefügt wurde. Du kannst ja, falls Du das auch haben möchtest, noch SHCNE_DRIVEADD und SHCNE_DRIVEREMOVED hinzufügen. Ich hab das weggelassen weil im Ausgangspost vom "Einstecken von SD Karte erkennen" die Rede war. Stecken SD-Karte in Adapter: Wird angezeigt. Na dann läuft doch mein Code. ;) Dann sollte auch das rausziehen der SD-Karte aus dem CardReader angezeigt werden solange der CardReader selbst noch nicht ausgeworfen wurde.
    Mfg -Franky-

    -Franky- schrieb:

    Wenn man es aber genau nimmt, müsste im letzten Parameter ein Array von SHChangeNotifyEntry übergeben werden

    Ja, da hast du Recht. Effektiv macht es aber, wenn man nur ein Element übergibt, keinen Unterschied, ob man die Elementanzahl auf 1 setzt und den einen Eintrag per ByRef übergibt oder man alternativ die Elementzahl und ein Array (das dann ByVal) übergibt - am Ende wird bei beidem ein Pointer auf das erste Element übergeben.

    -Franky- schrieb:

    weil nur SHCNE_MEDIAREMOVED und SHCNE_MEDIAINSERTED überwacht werden
    Mag sein. Allerdings gehört da ein Hinweis hin, dass, wenn andere Mitglieder da mehr überwachen wollen, dass da und da das und das eingetragen werden muss.
    Manchmal lasse ich andere für mich denken. :thumbsup:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Amelie Poste mal die Deklaration der Proedur.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Amelie Nicht schreiben, dass Du Änderungen gemacht hast, sondern welche. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!