Evaluierung der Defaultwerte bei <DllImport>

  • VB.NET

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von ftzdOp.

    Evaluierung der Defaultwerte bei <DllImport>

    Hallo,
    man kann ja beim DLLImport selber DLLImportAttribute setzen. Mich interessiert, wie/ob ich herausfinden kann, welche Standardwerte gesetzt werden, wenn man keine Attribute angibt.
    Beim Ansehen der Definition erkennt man, dass sehr viele Varianten vom Framework überprüft werden. Das ist also ein sehr langer Weg da jeweils pro Funktion hinzukommen.

    Aber vielleicht weiß ja einer von Euch eine Möglichkeit, weil er sich schon einmal damit auseinander gesetzt hat.

    Wie immer herzliche Grüße

    Ein Beispiel:

    VB.NET-Quellcode

    1. <DllImport("user32.dll")> _
    2. Friend Shared Function MessageBeep(ByVal uType As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
    3. 'Geht natürlich nicht, weil u.a. nicht öffentlich....
    4. Diagnostics.Debug.WriteLine (DllImportAttribute.SetLastError)
    5. End Function







    .
    Hilfreiche Antworten als solche zu Kennzeichnen wäre klasse 8-)
    Ich bin verwirrt. Meintest Du bei
    Mich interessiert, wie/ob ich herausfinden kann, welche Standardwerte gesetzt werden, wenn man keine Attribute angibt.
    eigentlich "Konstruktor-Parameter"?
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Normalerweise ja, aber das ist eine NotInheritable Klasse mit privatem Konstruktor. Die wiederum sorgt dann für den Import der dll.
    Siehe Beispiel. Das ist angelehnt an die MSDN Anleitung: LINK

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public NotInheritable Class WinAPIs
    2. Public Enum SecurityFlag
    3. SF_01NativeMethode = 1 ' Most secure enviroment, but slower and cant be called by restricted code, but can use tracestack/stackwalk
    4. SF_02UnsaveNativeMethode ' Fast, medium secure, no tracestack, can be called by restricted code
    5. SF_03SaveNativeMethode ' Fast, low secure, no tracestack, can be called by restricted code
    6. End Enum
    7. Private Sub New()
    8. End Sub
    9. Protected Friend NotInheritable Class User32
    10. Private Sub New()
    11. End Sub
    12. Protected Friend NotInheritable Class Beep
    13. Private Sub New()
    14. End Sub
    15. Public Shared Sub PlayBeep()
    16. If Not NativeMethods.MessageBeep(-1) Then Throw New Win32Exception()
    17. End Sub
    18. Public Shared Sub PlayBeep(Security As SecurityFlag)
    19. Select Case Security
    20. Case SecurityFlag.SF_01NativeMethode
    21. If Not NativeMethods.MessageBeep(-1) Then Throw New Win32Exception()
    22. Case SecurityFlag.SF_02UnsaveNativeMethode
    23. Dim permission As New UIPermission(UIPermissionWindow.AllWindows)
    24. permission.Demand()
    25. If Not UnSafeNativeMethods.MessageBeep(-1) Then Throw New Win32Exception()
    26. Case SecurityFlag.SF_03SaveNativeMethode
    27. If Not SafeNativeMethods.MessageBeep(-1) Then Throw New Win32Exception()
    28. End Select
    29. End Sub
    30. Friend NotInheritable Class NativeMethods
    31. Private Sub New()
    32. End Sub
    33. <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    34. Friend Shared Function MessageBeep(ByVal uType As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
    35. End Function
    36. End Class
    37. <SuppressUnmanagedCodeSecurityAttribute()> _
    38. Friend NotInheritable Class SafeNativeMethods
    39. Private Sub New()
    40. End Sub
    41. <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    42. Friend Shared Function MessageBeep(ByVal uType As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
    43. End Function
    44. End Class
    45. <SuppressUnmanagedCodeSecurityAttribute()> _
    46. Friend NotInheritable Class UnSafeNativeMethods
    47. Private Sub New()
    48. End Sub
    49. <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    50. Friend Shared Function MessageBeep(ByVal uType As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
    51. End Function
    52. End Class
    53. End Class ' Beep
    54. End Class ' User32
    55. End Class ' WinAPIs

    Der Aufruf wäre dann wirklich simpel: WinAPIs.User32.Beep.PlayBeep(WinAPIs.SecurityFlag.SF_01NativeMethode)



    So, für Beep ist da ja nicht wirklich aufregend, aber für andere Calls schon. Und dann sehe ich in diversen Foren eben auch unterschiedliche Signaturen:

    Für PeekMessage z.B. <DllImport("user32.dll", CharSet:=CharSet.Auto)> oder auch <DllImport("user32.dll", CharSet:=CharSet.UniCode)>. Nun würde ich gerne wissen, was der Default-Wert für CharSet bei PeekMessage ist. Ich denke man kann bei recht populären Calls das auch über reine WWW-Suche hinbekommen, aber wohl nicht bei den meisten, die eh kaum genutzt werden.

    Hilfreiche Antworten als solche zu Kennzeichnen wäre klasse 8-)

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „ftzdOp“ ()

    Aha. Also doch Konstruktor-Parameter.
    Bei <Foo(A, B, C)> sind A, B und C Werte, die für die Konstruktor-Parameter der FooAttribute-Klasse verwendet werden. Der einzige Trick ist, dass jedes öffentliche Feld und jede öffentliche Property automatisch als optionaler Parameter im Konstruktor verfügbar ist, obwohl die Attributsklasse eigentlich keinen solchen Konstruktor besitzt. Das kommt einfach davon, dass Attribute in .NET was besonderes sind.
    Mir fällt gerade auf: Meintest Du mit "Attribute" zufällig "Properties" bzw "Felder"?

    Die Standardwerte, die verwendet werden, wenn man für die Konstruktor-Parameter keinen Wert angibt, sollten eigentlich dokumentiert sein.
    Sind sie hier aber leider nicht: msdn.microsoft.com/en-us/libra…tattribute(v=vs.110).aspx
    In solchen Fällen empfehle ich, es einfach auszuprobieren:
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    ftzdOp schrieb:

    Ich vermute die Standwerte können je nach Aufruf variieren.

    Da dieses Attribut ein Spezialfall ist, könnte das sogar möglich sein.
    Aber beachte, dass "normale" Attribute nichts über das Programmelement wissen, auf das sie angewendet werden. Also egal wo Du <Foo()> hinschreibst, die Standardwerte bleiben immer die gleichen.
    Wie gesagt: DllImport ist ein Spezialfall. Denn EntryPoint wird auf einen nicht-Standardwert gesetzt, obwohl der Wert nirgends festgelegt wurde.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    In dem Fall war das klar, aber ich bin für alle Hinweise sehr dankbar !!

    Neu war mir
    1) der "Trick" mit den Args als Argument in einer Prozedur und
    2) dass auch für Prozeduren, die Parameter bei einer Überlagerung als Konstruktoren bezeichnet werden.
    Hilfreiche Antworten als solche zu Kennzeichnen wäre klasse 8-)

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

    Mist, da war ich wohl zu voreilig.

    Ich kriege die Überwachung nicht so wie Du hin.
    ApiTest.Main(GetType("XYZ").GetMethod("MessageBeep").GetCustomAttributes(GetType(DllImportAttribute), False))

    Das XYZ erschliesst sich mir nicht ... ?(
    Hilfreiche Antworten als solche zu Kennzeichnen wäre klasse 8-)
    Hi
    das ist der Typ, in dem du die Methode definiert hast, also wohl NativeMethods/SafeNativeMethods/UnSafeNativeMethods. Es genügt übrigens eine davon.
    Schau' dir übrigens mal das Konzept von Namespaces an. Du hast sehr viele falsch verwendete verschachtelte Typen. Wenn du z.B. System.Windows.Forms anschaust, so sind das Namespaces.
    Protected Friend ist in diesem Fall ebenfalls unangebracht, da es mit NotInheritable kombiniert ist. Verwende für diesen Fall nur Friend (Friend heißt, es soll nur innerhalb der Assembly darauf zugegriffen werden können, Protected heißt, es soll nur innerhalb der Erbfolge darauf zugegriffen werden können, Protected Friend heißt, dass sowohl innerhalb der Assembly, als auch in der Erbfolge darauf zugegriffen werden können soll).

    Hier noch ein Beispiel zu Namespaces:

    VB.NET-Quellcode

    1. Namespace MyNamespace
    2. Namespace InnerNamespace
    3. Public Class MyClass1
    4. End Class
    5. End Namespace
    6. End Namespace
    7. Namespace Some.Other.Namespace
    8. End NameSpace


    Viele Grüße
    ~blaze~

    ftzdOp schrieb:

    dass auch für Prozeduren, die Parameter bei einer Überlagerung als Konstruktoren bezeichnet werden.

    Ich glaube, da war ich zu undeutlich. Ich habe in dieses Bild eingezeichnet, welche Begriffe so vorgekommen sind:

    Konstruktoren können Parameter haben. So wie auch andere Methoden bzw. Funktionen.
    Bei <DllImport("user32.dll")> wird der Konstruktor der DllImportAttribute-Klasse aufgerufen, genauso wie er aufgerufen werden würde, wenn man Dim x As New DllImportAttribute("user32.dll") schreiben würde.
    Das, was in den runden Klammern steht, wird als Parameter an den Konstruktor übergeben. Da es Parameter des Konstruktors sind -> Konstruktor-Parameter.

    "Parameter" und "Argument" wird gerne synonym verwendet, aber ich persönlich halte mich daran:
    "Parameter" ist das, was bei der Deklaration der Methode bzw. des Konstruktors hingeschrieben wird. Im Falle der DllImportAttribute-Klasse wäre das der Parameter dllName. (Das wird auch gerne als "formaler Parameter" bezeichnet.)
    "Argument" ist dann das, was beim Aufruf des Konstruktors für den Parameter "eingesetzt" wird. Bei <DllImport("user32.dll")> ist der String "user23.dll" also das Argument für den Parameter dllName des Konstruktors der Klasse DllImportAttribute.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Ich hab mir daran die Zähne ausgebissen, weil ich die API-Funktion "MessageBeep" aus meinem Code schnell rüberkopiert hatte. Dort war sie aber PRIVATE ....
    OK, alles klar.

    1) Danke für die Namespacehinweise (Namespace ist doch im Prinzip nur eine Möglichkeit, das Adressieren von Objekten abzukürzen, oder ? ) (Proteced Friend war nur schnell hingeschreiben mit dem Hintergrund das erstmal aufzumachen, damit ich da keine Probleme bekomme; siehe Satz 1 ;-). Aber trotzdem Danke. Wirklich, jeder Hinweis ist toll.)
    2) Danke für die genaue Erläuterung der spezifischen .NET VB Begriffs-Konzepte, also vielen Dank auch für die Mühe, die dahinter steht.
    3) Danke für den ILSpy. :)

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

    Dann noch: Wie ist Eure Einschätzung. Kann man den Signaturen für die API-Calls von pinvoke.net insoweit vertrauen, als dass man sie unverfizierte, aber wahrscheinlich für die meisten Verwendungen problemlose Aufrufe, klassifizieren könnte ? Oder sind dort zu oft kleine Fehler enthalten ?
    Hilfreiche Antworten als solche zu Kennzeichnen wäre klasse 8-)

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

    ftzdOp schrieb:

    kleine Fehler enthalten ?


    Bei oft genutzten Funktionen(recht bekannten) kann man eigendlich davon ausgehen das es stimmig ist. Es kommt allerdings vor, bei seltenen genutzten(bzw. weniger bekannten Funktinen), das nur eine VB-6 Deklaration vorhanden ist, da sollte man dann schon ein wenig korrigieren, ich schau mir dann meist im MSDN die Function im C++ bereich an um sicher zu gehen.
    And i think to myself... what a wonderfuL World!

    ftzdOp schrieb:

    Namespace ist doch im Prinzip nur eine Möglichkeit, das Adressieren von Objekten abzukürzen


    Das Abkürzen des vollständigen Pfades wird durch Imports gemacht (Imports Some.Other.Namespace oder Imports System.Drawing oder sowas). VB.Net hat in den Projekteinstellungen globale Imports, daher muss man es nicht in jede Codedatei schreiben. C# hat sowas z.B. nicht, da hast du oben an jeder Codedatei eine Liste aller Imports.
    Namensräume sind an sich eine "logische" Strukturierung. So gibt es bspw. eben
    - System
    -- Drawing
    -- Windows
    --- Forms
    -- Runtime
    --- InteropServices
    --- CompilerServices

    - MyNamespace
    -- MyInnerNamespace
    - Some
    -- Other
    --- Namespace

    diese Struktur wird durch das verschachteln von Namespaces gelöst.
    Klassen, usw. sind nur dann ohne vollständigen Pfad erreichbar, wenn sie importiert werden. Daher kannst du halt statt "System.Windows.Forms.TextBox" einfach "TextBox" schreiben, um die Klasse TextBox zu bezeichnen.

    Auf pinvoke habe ich schon des öfteren Fehler gefunden. Wenn Pointer vorkommen, wird an manchen Stellen statt IntPtr einfach nur Integer verwendet, was bei 64-Bit-Pcs zu Problemen führen wird. Ansonsten war es, glaube ich, ganz ok.

    Niko Ortner Schön gemacht! :)

    Edit: Wenn es dich interessiert, hier solltest du alle relevanten Infos rausziehen können: msdn.microsoft.com/de-de/library/eaw10et3(v=vs.110).aspx
    Zum Überführen von Werten vom verwalteten zum unverwalteten Code wird afaik immer ein Marshaller verwendet, der diese Aufgabe erledigt (so kann man bspw. einige .Net-Objekte angeben, wenn man eigentlich auf Pointern arbeitet). An sich wird das Marshalling vom System verwaltet; man kann auch einen eigenen Marshaller verwenden.

    Viele Grüße
    ~blaze~

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

    OK, das Thema Namespace also dann doch vorziehen.

    Ich arbeite ja erst seit ca. 14 Tagen mit NET, die ersten Tage wirklich voller Frust, aber so langsam lichtet es sich zumindest soweit, als dass man die ersten Sachen machen kann und nicht an den elementarsten Dingen scheitert. Die Theorie zu OOP ist mir marginal bekannt; wie gesagt, soviel wie möglich in VBA mit Klassen gearbeitet und einmal komplett einen dicken Wälzer zum Thema OOP durchgelesen. Aber die Praxis ist dann doch anders. Zum ersten die ungewohnte IDE, dann das Durcheinander im Kopf mit den vielen bisher theoretischen Begriffen. Ich hatte in der Vergangenheit schon ein paar Mal Versuche gestartet, aber diesmal kommt es mir so vor, als ob ich die erste Hürde erfolgreich genommen hab und dabei bleibe. VS und NET erschliessen sich einem einfach nicht intuitiv, zumindest am Anfang. Und die Anforderungen an den theoretischen Hintergrund sind doch eklatant höher. Was ja nicht unbedingt schlecht ist und natürlich auch in der Natur der Sache liegt, klar. Aber zum Einsteigen hilft das nicht unbedingt.

    Aber ich bin schon jetzt von der Leistungsfähigkeit begeistert. Und es sind so viele Dinge vorhanden, die mir bisher gefehlt haben, angefangen von Überlagerungen, Vererbung, solche Inspektionsmöglichkeiten wie hier oben dargestellt, etc. Einfach toll :thumbup: Ich freue mich auf mehr.

    Und mit VBA kann man heute einfach kein Geld mehr verdienen.



    .
    Hilfreiche Antworten als solche zu Kennzeichnen wäre klasse 8-)