Konstante verlangt, die nicht möglich ist

  • VB.NET
  • .NET 4.5

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von icewather.

    Konstante verlangt, die nicht möglich ist

    Ich möchte einem Programm eine DLL mitgeben, diese jedoch nicht unter \windows\system32 ablegen, sondern ins Programmverzeichnis. Das Problem ist nun folgendes: Beim Aufrufen der DLL muss ich ja den Pfad angeben. Dieser ist jedoch variabel - je nachdem, wie der Benutzer das Programm installiert. Ich habe es so lösen wollen:

    VB.NET-Quellcode

    1. Public vEverythingDLL As String = Path.GetDirectoryName(Application.ExecutablePath) & "Everything32.dll"
    2. Public Declare Function Everything_SetSearchA Lib vEverythingDLL (ByVal search As String) As UInt32


    Leider akzeptiert die Public Declare Function jedoch an dieser Stelle keine Variable, sondern will eine Konstante. Hat jemand eine Idee, wie ich das lösen könnte?

    Danke für eine Antwort
    Beat

    *Topic verschoben*

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Deine Dll, handelt es sich hier schon um eine Assembly oder? Weil dann kann die unter Verweise einfach eingebunden werden.

    Wenn es sich nicht um eine Assembly handelt, dann müsste sie einfach bei der exe-Datei liegen.
    Mit DllImport oder mit deiner oben erwähnten 'Everything_SetSearchA' kann darauf gegriffen werden im Normalfall. Selber geschrieben?

    EDIT:
    Dll muss bei der exe-Datei beiliegen und dann

    VB.NET-Quellcode

    1. ​Public Declare Function Everything_SetSearchA Lib "Everything32.dll" (ByVal search As String) As Int32


    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „exc-jdbi“ ()

    Ich verstehe nicht. Wenn Du die DLL hast und mitlieferst, dann kannst Du sie doch einbinden, wie exc-jdbi schrieb. Kein DllImport und schon gar kein VB6-Public-Declare-Ranz nötig.

    Dein Link führt ins Nirvana.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Ich verwende Everything auch bei mir in einem Programm und das funktioniert einwandfrei, wenn die DLL im Programmverzeichnis liegt und lediglich

    VB.NET-Quellcode

    1. <DllImport("Everything32.dll", CharSet:=CharSet.Unicode)>
    2. Private Shared Function Everything_SetSearch(ByVal lpSearchString As String) As Integer
    3. End Function

    verwendet wird.
    Es muss nichts weiter gemacht werden. Die Everything32.dll muss nur neben der ausgeführten .exe liegen.

    PS:
    Everything ist einn Segen. Ich weiß nicht, wie ich früher ohne das Teil überlebt habe.

    Edit: @VaporiZed
    Ist eine C-DLL, keine .NET-DLL. Und meh, Private Declare Unicode Function Everything_SetSearch Lib "Everything32.dll" (ByVal lpSearchString As String) As Integer kompiliert auch nur zu 'nem DllImport-Attribut, nur dass noch ExactSpelling = True und SetLastError = true dabei sind, was man Ordnungshalber sowieso machen sollte. Ob man jetzt dafür die eine oder die andere Syntax nimmt, macht kaum Unterschied. Ich würde sogar eher sagen, dass Declare in einer großen Datei besser lesbar ist, weil nur eine Zeile statt drei (oder zwei, wenn man spart).
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Niko Ortner“ ()

    Achso, C, na dann wird das nix mit Import über die Projekt-Properties, klar.

    Bzgl. Zeilenzahl: inzwischen kann man problemlos schreiben:

    VB.NET-Quellcode

    1. <DllImport("Everything32.dll", CharSet:=CharSet.Unicode)> Private Shared Function Everything_SetSearch(ByVal lpSearchString As String) As Integer : End Function
    Also alles in einer (langen) Zeile. Ist zwar dank des : ein schmutziger Trick, aber einer, den ich bei DllImport inzwischen gerne nutze, weil ich sonst es auch immer sehr unübersichtlich hatte.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Herzlichen Dank, euch allen! Wow, das ist echt zuvorkommend, dass ihr über Nacht geantwortet habt. Eure Antworten helfen sehr, das Problem lässt sich so auf verschiedene Weise lösen!

    @Niko Ortner - du schreibst, wie Everything ein Segen für dich ist! - Dann gehe ich davon aus, dass du intensiv damit arbeitest. Kann ich gleich ein paar weitere Fragen stellen oder sollten wir dafür eine Konversation eröffnen? Folgendes würde mich interessieren:

    1. Was ist, wenn auf einem PC die Applikation Everything selbst nicht installiert ist? - Auf meinem PC ist es so, dass Everything im Hintergrund immer läuft, weil es oft brauche. Genügt es auf einem PC ohne laufendes Everything, die everything32.dll in ein VB.NET-Programm zu integrieren? Everthing muss meines Wissens zuerst einen Index anlegen, auf den die schnelle Suche zugreifen kann. Wie wird der Index angelegt, wenn ich in meiner App nur die DLL für eine Suche aktiviere? Muss ich ev. auch die Indexierung programmieren? falls ja, wie?
    2. Alle Einstellungen, die ich auf meiner lokalen Everything-App eingestellt habe, stehen auch durch die everything32.dll in der eigenen VB-APP zur Verfügung. z.B. indexiere ich auch die Netzlaufwerke. Wie können diese Einstellungen gemacht und wo gepeichert werden, wenn ich meine App PCs ohne installiertes Everything installiere? Vermutlich müsste ich dafür eine eigene Everything-Schnittstelle schreiben, oder?
    3. Ich arbeite auf meinen PCs mit der 64-Bit-App von Everything. Doch ich habe versucht, das folgende Programm auf die 64-Bit-DLL umzuschreiben. Das habe ich leider nicht hingekriegt. Es kommen verschiedene Fehler. Doch ich vermute etwas: Ich kompiliere meine App mit der Einstellung "Any CPU" und kann vermutlich deshalb keine 64-Bit-DLL einbinden.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Public Declare Function Everything_SetSearchA Lib "c:\visualstudio\everything\Everything32.dll" (ByVal search As String) As UInt32
    3. Public Declare Function Everything_QueryA Lib "c:\visualstudio\everything\Everything32.dll" (ByVal bWait As Integer) As Integer
    4. Public Declare Function Everything_GetNumResults Lib "c:\visualstudio\everything\Everything32.dll" () As UInt32
    5. Public Declare Function Everything_GetResultFileNameA Lib "c:\visualstudio\everything\Everything32.dll" (ByVal index As UInt32) As String
    6. Public Declare Function Everything_GetLastError Lib "c:\visualstudio\everything\Everything32.dll" () As UInt32
    7. Public Declare Function Everything_GetResultFullPathNameA Lib "c:\visualstudio\everything\Everything32.dll" (ByVal index As UInt32, ByVal buf As String, ByVal size As UInt32) As UInt32
    8. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    9. Everything_SetSearchA(TextBox1.Text)
    10. Everything_QueryA(1)
    11. Dim NumResults As UInt32
    12. Dim i As UInt32
    13. NumResults = Everything_GetNumResults()
    14. ListBox1.Items.Clear()
    15. If NumResults > 0 Then
    16. For i = 0 To NumResults - 1
    17. Dim filename As New String("", 260)
    18. Everything_GetResultFullPathNameA(i, filename, 260)
    19. ListBox1.Items.Insert(i, filename)
    20. Next
    21. End If
    22. End Sub
    23. End Class


    Hast du da ev. Erfahrung? Hast du eigene Lösungen entwickelt, von denen ich lernen dürfte?
    Nochmals ein fettes DANKE für deine und eure Hilfe.
    Beat

    Ps. Der obige Code stammt von dem Link, der ins Nirwana ging. Man muss auf der Seite einen Login haben, damit da etwas kommt.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „icewather“ ()

    Den Vorteil von DllImport sieht man sofort. Es ist dort möglich eine Konstante einzufügen, was deinen Code um einiges Wartungsfreundlicher machen würde.

    VB.NET-Quellcode

    1. Const DllPath As String = "c:\visualstudio\everything\Everything32.dll"
    2. <DllImport(DllPath, CharSet:=CharSet.Unicode)>
    3. Private Shared Function Everything_SetSearch(ByVal lpSearchString As String) As Int32
    4. End Function


    Man kann so auch mit Relativen Pfaden arbeiten

    VB.NET-Quellcode

    1. ​Const DllPath As String = ".\..\..\Everything32.dll"


    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    Danke exc-jdbi - der Tipp, dass die dll einfach neben der aktuelle exe-Datei legen muss, ist super. So muss ich ja gar keinen Pfad angeben und habe keine Variable mehr. - Im Übrigen habe ich lieber eine Zeile Programmcode für eine Funktion - auch wenn es etwas altbacken erscheint. Ist für mich übersichtlicher.
    @icewather
    1.: Wenn Everything auf dem Gerät nicht installiert ist (oder nicht läuft), dann funktioniert die Everything32.dll (bzw. 64) nicht. Diese DLL kommuniziert nur mit der laufenden Everything-Instanz. Allerdings crashen Aufrufe an die DLL dann nicht, sondern es werden einfach keine Ergebnisse geliefert. Ich hab jetzt nicht viel getestet, aber z.B. Everything_Query gibt False zurück, wenn Everything nicht installiert ist.
    2.: Wegen 1. gelten auch manche Einstellungen, die du in Everything machst, in deinem Programm. Zum Beispiel die indizierten Laufwerke. Dagegen wird z.B. die Einstellung "Match Whole Word" nicht im Programm übernommen. Das soll wohl Inkonsistenzen vermeiden. Welche Einstellungen genau übernommen werden, und welche nicht, steht bestimmt in der Dokumentation von Everything.
    3.: Auf meinem Rechner läuft auch die 64-Bit-Version von Everything. Trotzdem verwende ich die Everything32.dll, da mein Programm als 32-Bit-Prozess läuft. Hier die Everything64.dll zu benennen schmeißt eine BadImageFormatException. Ich hab's mal in'nem 64-Bit-Prozess probiert. Da funktioniert es nur mit Everything64.dll. Die Everything32.dll schmeißt ebenfalls eine BadImageFormatException. Also die DLL muss mit dem eigenen Prozess zusammenstimmen, nicht mit der Everything-Installation.
    In diesem Fall ist das DllImport-Attribut tatsächlich überlegen:

    VB.NET-Quellcode

    1. #If PLATFORM = "x64" Then
    2. Const EverythingLibName As String = "Everything64.dll"
    3. #Else
    4. Const EverythingLibName As String = "Everything32.dll"
    5. #End If
    6. <DllImport(EverythingLibName, CharSet:=CharSet.Unicode)>
    7. Private Shared Function Everything_SetSearch(ByVal lpSearchString As String) As Integer
    8. End Function

    Das wählt automatisch die Everything64.dll, wenn mit x64 kompiliert wird, und Everything32.dll wenn nicht. (Wie das jetzt mit AnyCPU zusammenspielt weiß ich aber nicht.)
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Everything hat kurzfristig auf eine Anfrage geantwortet und eine Syntax für vb.net geschrieben, die nun definitiv läuft und genial ist! Vielen Dank Everything!

    VB.NET-Quellcode

    1. ​Public Class Form1
    2. Public Declare Function Everything_SetSearchA Lib "Everything32.dll" (ByVal search As String) As UInt32
    3. Public Declare Function Everything_SetRequestFlags Lib "Everything32.dll" (ByVal dwRequestFlags As UInt32) As UInt32
    4. Public Declare Function Everything_QueryA Lib "Everything32.dll" (ByVal bWait As Integer) As Integer
    5. Public Declare Function Everything_GetNumResults Lib "Everything32.dll" () As UInt32
    6. Public Declare Function Everything_GetResultFileNameA Lib "Everything32.dll" (ByVal index As UInt32) As String
    7. Public Declare Function Everything_GetLastError Lib "Everything32.dll" () As UInt32
    8. Public Declare Function Everything_GetResultFullPathNameA Lib "Everything32.dll" (ByVal index As UInt32, ByVal buf As System.Text.StringBuilder, ByVal size As UInt32) As UInt32
    9. Public Declare Function Everything_GetResultSize Lib "Everything32.dll" (ByVal index As UInt32, ByRef size As UInt64) As Integer
    10. Public Declare Function Everything_GetResultDateModified Lib "Everything32.dll" (ByVal index As UInt32, ByRef ft As UInt64) As Integer
    11. Public Const EVERYTHING_REQUEST_FILE_NAME = &H1
    12. Public Const EVERYTHING_REQUEST_PATH = &H2
    13. Public Const EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME = &H4
    14. Public Const EVERYTHING_REQUEST_EXTENSION = &H8
    15. Public Const EVERYTHING_REQUEST_SIZE = &H10
    16. Public Const EVERYTHING_REQUEST_DATE_CREATED = &H20
    17. Public Const EVERYTHING_REQUEST_DATE_MODIFIED = &H40
    18. Public Const EVERYTHING_REQUEST_DATE_ACCESSED = &H80
    19. Public Const EVERYTHING_REQUEST_ATTRIBUTES = &H100
    20. Public Const EVERYTHING_REQUEST_FILE_LIST_FILE_NAME = &H200
    21. Public Const EVERYTHING_REQUEST_RUN_COUNT = &H400
    22. Public Const EVERYTHING_REQUEST_DATE_RUN = &H800
    23. Public Const EVERYTHING_REQUEST_DATE_RECENTLY_CHANGED = &H1000
    24. Public Const EVERYTHING_REQUEST_HIGHLIGHTED_FILE_NAME = &H2000
    25. Public Const EVERYTHING_REQUEST_HIGHLIGHTED_PATH = &H4000
    26. Public Const EVERYTHING_REQUEST_HIGHLIGHTED_FULL_PATH_AND_FILE_NAME = &H8000
    27. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    28. Everything_SetSearchA(TextBox1.Text)
    29. Everything_SetRequestFlags(EVERYTHING_REQUEST_FILE_NAME Or EVERYTHING_REQUEST_PATH Or EVERYTHING_REQUEST_SIZE Or EVERYTHING_REQUEST_DATE_MODIFIED)
    30. Everything_QueryA(1)
    31. Dim NumResults As UInt32
    32. Dim i As UInt32
    33. Dim filename As New System.Text.StringBuilder(260)
    34. Dim size As UInt64
    35. Dim ftdm As UInt64
    36. Dim DateModified As System.DateTime
    37. NumResults = Everything_GetNumResults()
    38. ListBox1.Items.Clear()
    39. If NumResults > 0 Then
    40. For i = 0 To NumResults - 1
    41. Everything_GetResultFullPathNameA(i, filename, filename.Capacity)
    42. Everything_GetResultSize(i, size)
    43. Everything_GetResultDateModified(i, ftdm)
    44. DateModified = System.DateTime.FromFileTime(ftdm)
    45. ListBox1.Items.Insert(i, filename.ToString() & " size:" & size & " date:" & DateModified.ToString())
    46. Next
    47. End If
    48. End Sub
    49. End Class