Treeview aus Stringelementen erzeugen

  • VB.NET

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von HolgerNils.

    Treeview aus Stringelementen erzeugen

    Hallo Leute,
    ich habe folgende Herausforderung. Aus folgenden beispielhaften Daten soll eine Tree-View erzeugt werden.
    Die Strings jeweils beschreiben den Pfad bis zur untersten Ebene, dem letzten Wert pro Zeile.

    D0/Da/Db/Dc/Df
    D0/Da/Db/Dc/Df
    D0/Da/Db/Df
    D0/Da/Db/Df/Dx
    D0/Da/Db/1
    D0/Da/Db/2
    D0/Da/Db/3
    D0/Db/dc/1/2
    D0/Db/dc/1/2/1
    D0/Dc/dc/1/2/3/4/5/6/a
    usw.

    Nu weiß ich nicht, wie tief die Schachtelung gehen wird. ;(
    Der notwendige rekursive Ansatz ist mir nicht klar genug um es in Code zu packen respektive soo fit mit VB2008 bin ich noch nicht. Vielleicht hätte der ein oder andere von Euch einen Tipp oder eine Vorlage.

    Vielen Dank schon jetzt!
    HNils
    Hi,

    mir ist nicht ganz klar, wie das TreeView nach dem Befüllen aussehen soll. Nehmen wir z.B. die beiden letzten Zeilen:

    D0/Db/dc/1/2/1
    D0/Dc/dc/1/2/3/4/5/6/a

    So wie ich den Sachverhalt verstanden habe, müsste das TreeView dann so aussehen:
    D0 - root

    D0->Db - node1 in D0
    D0->Dc - node2 in D0

    D0->Db->dc->rest von Zeile 1 - node(s) in D0->Db
    D0->Dc->dc->rest von Zeile 2 - node(s) in D0->Dc

    Ist diese Annahme richtig? Wenn nicht, dann beschreibe die Stuktur bitte nochmal genauer.
    Gruß
    hal2000
    Hi Hal,
    ja, das war sehr missverständlich von mir ausgerückt. Sehe DC z. B. ist doppelt sozusagen. Sorry, for that.
    Deine Grundsatzannahme ist korrekt, gleiche Bezeichner teilen sich dann die Ebene und darunter hängen wieder andere.
    Zwischenzeitlich habe ich eine weitere Möglichkeit gefunden. Die schon existente (aber halt nicht ausreichende)API, die ich ergänzen möchte, bietet die Möglichkeit sozusagen einen Level anzugeben und liefert dann die direkten Childs zurück. So konnte ich nach eingiebiger nach eingiebiger Recherche über Rekusionen etc. zwischenzeitlich diese Funktion nutzen und mir jeweils (rekursiv) den Tree ausgehend von der Rootnode aufbauen. Möglicherweise durch die Brust ins Auge, aber es funktioniert sauber ;)

    Nu muss ich nur noch versuchen einen iStream zu lesen, weil die (existente) API bietet ein iStream-Object mit dem dazugehörigen Icon an, da die Icons den Einträgen (also den Nodes) benutzerdefiniert zugewiesen sind und leider keine feste Zuweisung haben. Die Recherche läuft, allerdings finde ich da mehr was zu C als zu VB. Wenn Du da auch Aktien drin hättest, mein Dank wäre Dir auf Ewig sicher ;)

    VB.NET-Quellcode

    1. Dim sNode As Windows.Forms.TreeNode = MyWin.TreeView1.Nodes(0)
    2. CreateTreeFromReqID(0, sNode)
    3. ...
    4. Private Function CreateTreeFromReqID(ByVal inReqID As Integer, ByRef inNode As Windows.Forms.TreeNode) As Integer
    5. Dim subReqList = QCCn.ReqFactory.GetChildrenList(inReqID)
    6. Dim nCount As Integer = 0
    7. Dim lastNode As Windows.Forms.TreeNode
    8. If subReqList.Count > 0 Then
    9. Dim creNode As Windows.Forms.TreeNode
    10. MyWin.TreeView1.SelectedNode = inNode
    11. For Each rq In subReqList
    12. lastNode = MyWin.TreeView1.SelectedNode
    13. creNode = MyWin.TreeView1.SelectedNode.Nodes.Add(rq.Name & " #[" & CStr(rq.TypeID) & "]")
    14. MyWin.TreeView1.ImageList = myImgList
    15. MyWin.TreeView1.SelectedNode.ImageIndex = 0
    16. MyWin.TreeView1.SelectedNode.SelectedImageIndex = 1
    17. inReqID = CreateTreeFromReqID(rq.ID, creNode)
    18. MyWin.TreeView1.SelectedNode = lastNode
    19. nCount = +1
    20. Next
    21. Else
    22. If nCount > 0 Then
    23. If MyWin.TreeView1.SelectedNode Is Nothing Then
    24. MyWin.TreeView1.SelectedNode = MyWin.TreeView1.Nodes(0)
    25. Else
    26. MyWin.TreeView1.SelectedNode = MyWin.TreeView1.SelectedNode.Parent
    27. End If
    28. Else
    29. MyWin.TreeView1.SelectedNode = MyWin.TreeView1.SelectedNode
    30. End If
    31. Return inReqID
    32. End If
    33. End Function

    VB.NET-Quellcode

    1. MyWin.TreeView1.ImageList = myImgList

    Wie du mit obiger Zeile schon richtig herausgefunden hast, benötigt das TreeView eine ImageList, um Icons anzeigen zu können. Das Hinzufügen, Zuweisen und Indizieren der Elemente steht hier erklärt.

    Was verstehst du unter einem iStream-Objekt? Die Bezeichnung "iStream" ist sehr allgemein - IStream ist ein Interface. Dahinter kann sich jeder Typ verbergen, der das Interface implementiert. Daher kann ich keine konkrete Antwort darauf geben, wie der Stream zu verarbeiten ist. Wenn er eine geöffnete Datei darstellt, kannst du entsprechende Klassen aus System.IO verwenden, um ihn zu lesen (z.B. den BinaryReader für binär zu lesende Daten). Enthält der Stream ein Bild, kannst du auch Image.FromStream() verwenden, um ein Bild-Objekt zu erhalten, welches sich in die ImageList einfügen lässt.
    Gruß
    hal2000
    Sodele. Einen kleinen Schritt vorwärts gekommen.

    Der Support der API war wenigstens in der Lage mir zumindest mit einem Codebeispiel zu zeigen, wie man aus einem File einen Stream machen könnte. Demnach müsste ich diesen Vorgang nun "nur noch" rumdrehen - und da verliessen sie mich...

    In "reqType.Icon" steht also ein String mit dem Stream, den müsste ich in eine - offenbar BMP - Grafik umwandeln, da ich die Icons verwenden möchte, die im Datensatz als Stream abgelegt sind. Nur wie? Habe mit "GetHGlobalFromStream" experimentiert, aber leider ohne Erfolg. Weiß jemand einen Tipp?

    DANKE!

    VB.NET-Quellcode

    1. Dim bytes() As Byte
    2. bytes = System.IO.File.ReadAllBytes("C:\\Icon.bmp") 'only a 16x16 bmp can be used as a Req Type Icon
    3. Dim icon As Runtime.InteropServices.ComTypes.IStream = Nothing
    4. Dim hGlobal As IntPtr
    5. hGlobal = System.Runtime.InteropServices.Marshal.AllocHGlobal(bytes.GetLength(0))
    6. CreateStreamOnHGlobal(hGlobal, 0, icon)
    7. Dim written As IntPtr
    8. written = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(System.Runtime.InteropServices.Marshal.SizeOf(4))
    9. icon.Write(bytes, bytes.GetLength(0), written)
    10. icon.Seek(0, 0, Nothing)
    11. Dim wr As Integer = System.Runtime.InteropServices.Marshal.ReadInt32(written)
    12. If wr <> bytes.GetLength(0) Then
    13. System.Console.WriteLine("Error writing data to stream")
    14. System.Runtime.InteropServices.Marshal.FreeHGlobal(hGlobal)
    15. Exit Sub
    16. End If
    17. For i = 1 To reqTypes.Count
    18. reqType = reqTypes.Item(i)
    19. If reqType.Name = "My_New_Req_Type" Then
    20. icon.Seek(0, 0, Nothing)
    21. reqType.Icon = icon
    22. cust.Commit()
    23. End If
    24. Next
    25. System.Runtime.InteropServices.Marshal.FreeHGlobal(hGlobal)
    Hi.

    Ich bin noch da ^^ - hatte nur gerade keine Zeit zum Antworten. Dein letztes Codebeispiel zeigt, wie aus einer Datei ein IStream-Objekt in reqTypes.Icon wird. Mit dem Codebeispiel ist auch klar geworden, dass es sich um einen COM-IStream handelt. Diesen Vorgang musst du umdrehen - eigentlich kein Problem. Ich habe reqTypes mal als Collection(Of HelpClass) nachgebildet - wenn du mir noch sagst, welcher Typ reqTypes ist und ob die Variable "cust" eigentlich "icon" heißen müsste, kann ich dir den Ablauf umdrehen. Ein TreeNode kann es nicht sein, da der verwalteten Definition die Eigenschaft "Icon" fehlt. Hier meine Nachbildung - stellt sie den Sachverhalt richtig dar?

    VB.NET-Quellcode

    1. Declare Function CreateStreamOnHGlobal Lib "ole32" (ByVal hGlobal As IntPtr, ByVal fDeleteOnRelease As Boolean, ByRef ppstm As IStream) As Int32
    2. 'Nachbildung
    3. Shared reqTypes As New Collection(Of HelpClass)
    4. Shared reqType As HelpClass
    5. '---
    6. Dim hGlobal As IntPtr
    7. Shared Sub StoreBmpToStream()
    8. Dim bytes() As Byte
    9. bytes = System.IO.File.ReadAllBytes("C:\\file.bmp") 'only a 16x16 bmp can be used as a Req Type Icon
    10. Dim icon As Runtime.InteropServices.ComTypes.IStream = Nothing
    11. hGlobal = System.Runtime.InteropServices.Marshal.AllocHGlobal(bytes.GetLength(0))
    12. Dim result = CreateStreamOnHGlobal(hGlobal, False, icon)
    13. Dim written As IntPtr
    14. written = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(System.Runtime.InteropServices.Marshal.SizeOf(4))
    15. icon.Write(bytes, bytes.GetLength(0), written)
    16. icon.Seek(0, 0, Nothing)
    17. Dim wr As Integer = System.Runtime.InteropServices.Marshal.ReadInt32(written)
    18. If wr <> bytes.GetLength(0) Then
    19. System.Console.WriteLine("Error writing data to stream")
    20. System.Runtime.InteropServices.Marshal.FreeHGlobal(hGlobal)
    21. Exit Sub
    22. End If
    23. 'Nachbildung
    24. reqTypes.Add(New HelpClass)
    25. '---
    26. For i = 1 To reqTypes.Count
    27. reqType = reqTypes.Item(i - 1)
    28. If reqType.Name = "My_New_Req_Type" Then
    29. icon.Seek(0, 0, Nothing)
    30. reqType.Icon = icon
    31. 'cust.Commit()
    32. icon.Commit(0)
    33. End If
    34. Next
    35. 'Auskommentiert, denn wir wollen den Stream wieder auslesen.
    36. 'System.Runtime.InteropServices.Marshal.FreeHGlobal(hGlobal)
    37. End Sub
    38. '-----------------------------------------
    39. Public Class HelpClass
    40. Dim _name As String, _ico As IStream
    41. Public Property Icon() As IStream
    42. Get
    43. Return _ico
    44. End Get
    45. Set(ByVal value As IStream)
    46. _ico = value
    47. End Set
    48. End Property
    49. Public Property Name() As String
    50. Get
    51. Return _name
    52. End Get
    53. Set(ByVal value As String)
    54. _name = value
    55. End Set
    56. End Property
    57. End Class


    Das Auslesen des Streams funktioniert so:

    VB.NET-Quellcode

    1. Dim icon As IStream = reqTypes.Item(0).Icon 'Beispiel - 1. Item auswählen
    2. icon.Seek(0, 0, Nothing) 'Zeiger an den Anfang des Streams setzen
    3. Dim streamLen As Int64
    4. Dim hr As Int32 = IStream_Size(icon, streamLen) 'Länge des Streams ermitteln
    5. Dim buffer(CInt(streamLen - 1)) As Byte 'Puffer bereitstellen
    6. Dim pBytesRead As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(4)) 'Speicher für den 3. Read-Parameter bereitstellen
    7. icon.Read(buffer, CInt(streamLen), pBytesRead) 'Stream auslesen
    8. Dim bytesRead As Int32 = Marshal.ReadInt32(pBytesRead) 'Zeigerwert ermitteln
    9. If bytesRead <> streamLen Then Throw New InvalidOperationException("Die Länge stimmt nicht") 'Angeforderte Länge mit der zurückgegebenen vergleichen
    10. Marshal.FreeCoTaskMem(pBytesRead) 'Zeiger freigeben
    11. File.WriteAllBytes(My.Computer.FileSystem.SpecialDirectories.Desktop & "\result.bmp", buffer) 'Daten abspeichern
    12. 'Speicher freigeben (in StoreBmpToStream auskommentiert, wird hier nachgeholt)
    13. System.Runtime.InteropServices.Marshal.FreeHGlobal(hGlobal)


    Achtung: Du musst den Speicher freigeben, den du selbst allokierst (wie z.B. in StoreBmpToStream). Wenn du den Speicher zu früh freigibst, funktioniert der Code trotzdem, liefert aber nur Datensalat. Ich habe zwei Beispieldateien angehängt - die erste ist intakt, bei der zweiten wurde der Speicher zu früh freigegeben. Betrachte beide mit dem Programm HxD oder einem anderen Hex-Editor deiner Wahl. Da das Forum die Endung ".bmp" nicht zulässt, habe ich die Endung .txt angehängt.
    Dateien
    • result.bmp.txt

      (63,65 kB, 176 mal heruntergeladen, zuletzt: )
    • datensalat.bmp.txt

      (63,65 kB, 144 mal heruntergeladen, zuletzt: )
    Gruß
    hal2000

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

    Hey Hal,
    vielen Dank! Habe erst heute den Beitrag gesehen ;( das Datum in meiner Übersicht wird offensichtlich nicht aktualisiert mit der Angabe "letztes Post".
    Seisdrum.

    Werde Deine Mühen direkt ausprobieren und berichten!
    Vorab unabhängib vom Ergebnis: DANKE!

    Holger
    Hi Hal,
    was die Rückfrage angeht: In der API steht "Property Icon() as IStream" und dort dann "Refer to Microsoft documentation".
    Cust ist das Sammelobject für das "Customizing", welches halt als Unterobjekt das "Req"-Object hat. In dem Beispiel wird ja ein Req-Objekt gefüllt respektive gezeigt, wie das erstellen eines eigenen Icons aus einer BMP zu erfolgen hat. Das Ganze wird dann abschliessend mit der API-Funktion Commit für das Gesamtobjekt zurückgeschrieben und so erzeugt und gespeichert.

    Cust dürfte nur beim Schreiben interessant sein. Die Routine würde das Ganze so weit vorbereiten, daß eigentlich "nur noch" das Objekt .Icon in ein ImageFile im Speicher umzusetzen wäre, welches dann als Image für die Nodes einer Treeview verwendet würden.

    Seek kennt das Ding leider nicht, nur RemoteRead:
    Public Sub RemoteRead( _
    ByRef pv As Byte, _
    ByVal cb As ULong, _
    ByRef pcbRead As ULong _
    )

    Und RemoteSeek:
    Public Sub RemoteSeek( _
    ByRef dlibMove As LARGE_INTEGER, _
    ByVal dwOrigin As ULong, _
    ByRef plibNewPosition As ULARGE_INTEGER _
    )


    Das Icon als Feld aus der DB meckert bei der Zuweisung, daß es String wäre; per Definition vom Feldtyp her ist es VarChar(2000) definiert.
    Sorry für's dumm anstellen, komme von VB6 und der Wechsel ist doch schon ordentlich auf .Net ;(
    Was ich zu dem Thema bisher im INet gefunden habe und in Büchern ist leider nicht die Menge.

    Danke Dir für die grandiose Hilfe!

    PS: Könnte auch die API zur Verfügung stellen, aber möchte Deine Hilfsbereitschaft wirklich nicht über-beanspruchen.
    Holger
    Bilder
    • qc_ReqData.jpg

      76,87 kB, 1.198×209, 135 mal angesehen

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „HolgerNils“ ()

    Irgendwie ist bei der ganzen Sache untergegangen, was eigentlich das Ziel war. Fassen wir also mal zusammen:

    - Du hast eine Datenbank. Sie hat ein Feld "Icon", in dem ein Icon gespeichert ist.
    - Die Datenbank wird über die API ausgelesen.
    - Die API liefert dir eine Liste mit Datensätzen als Liste von Objekten
    - Jedes Element der Liste hat demnach eine Eigenschaft "Icon".
    - Du möchstest die Datensätze in einem TreeView anzeigen, und zwar mit passenden Icons.
    -- Dazu muss die Eigenschaft (die einen Stream enthält) ausgelesen werden.
    -- Jedes Icon muss im Speicher so transformiert werden, dass es vom TreeView dargestellt werden kann.

    soweit korrekt? Du kannst mir die API zukommen lassen, denn dann kann ich die exakten Datentypen nachschlagen.
    Gruß
    hal2000
    Hi Hal,
    Exaktamente, genau getroffen. Das ist die Herausforderung.
    Werde das Mail gleich fertig machen.
    Hättest Du einen Tipp wo man adäuates Nachlesematerial findet?
    Zu dem Thema iStream finde ich leider sehr verhaltene Infos.
    Vielen lieben Dank!
    Holger

    HolgerNils schrieb:

    Hättest Du einen Tipp wo man adäuates Nachlesematerial findet?

    Nein - solche komplexen Themen fallen in den Bereich "selbst aneignen". Dabei ist es hilfreich, wenn man COM-Interop und P/Invoke aus dem Ärmel schütteln kann, sodass man sich nicht ewig mit Deklarationen und Imports aufhalten muss. Es ist von elementarer Wichtigkeit, dass du C++-Methodensignaturen aus dem MSDN quasi direkt in eine .NET-Signatur umschreiben kannst, wodurch du letztlich den Marshaller konfigurierst, der deine Schnittstelle zur unverwalteten Welt ist.

    Ich habe mal was gebastelt. Wenn du wirklich eine Liste mit Datensatz-Objekten hast, von der jedes Element eine IStream-Icon-Eigenschaft hat, ist das die Lösung:

    VB.NET-Quellcode

    1. Dim lst As New List(Of Record) 'Liste der ausgelesenen Datensätze (hier im Beispiel ist die Liste leer - sie wird durch die API gefüllt)
    2. Dim il As New ImageList() 'ImageList erstellen
    3. TreeView1.ImageList = il 'ImageList zuweisen
    4. For Each l In lst 'Für jeden Datensatz
    5. Dim icon As IStream = l.TPR_ICON_STREAM 'gib Icon. Hier ist evtl. noch ein TryCast(...) nötig, falls die Typen nicht passen.
    6. icon.Seek(0, 0, Nothing) 'Zeiger an den Anfang des Streams setzen
    7. Dim streamLen As Int64
    8. Dim hr As Int32 = IStream_Size(icon, streamLen) 'Länge des Streams ermitteln
    9. Dim buffer(CInt(streamLen - 1)) As Byte 'Puffer bereitstellen
    10. Dim pBytesRead As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(4)) 'Speicher für den 3. Read-Parameter bereitstellen
    11. icon.Read(buffer, CInt(streamLen), pBytesRead) 'Stream auslesen
    12. Dim bytesRead As Int32 = Marshal.ReadInt32(pBytesRead) 'Zeigerwert ermitteln
    13. If bytesRead <> streamLen Then Throw New InvalidOperationException("Die Länge stimmt nicht") 'Angeforderte Länge mit der zurückgegebenen vergleichen
    14. Marshal.FreeCoTaskMem(pBytesRead) 'Zeiger freigeben
    15. Using ms As New IO.MemoryStream(buffer)
    16. il.Images.Add(l.TPR_NAME, Image.FromStream(ms)) 'Icon unter TPR_NAME in die ImageList schreiben
    17. End Using
    18. 'Datensatz in das TreeView eintragen
    19. Dim n As New TreeNode(l.TPR_NAME)
    20. n.ImageKey = l.TPR_NAME 'Icon auswählen
    21. TreeView1.Nodes.Add(n)
    22. Next

    Hier noch das verwendete Datensatz-Objekt:

    VB.NET-Quellcode

    1. Structure Record
    2. Dim TPR_NAME As String
    3. Dim TPR_ICON_STREAM As IStream
    4. '... etc.
    5. End Structure


    Edit: Hier noch die Signatur von IStream_Size():

    VB.NET-Quellcode

    1. <DllImport("Shlwapi.dll")> _
    2. Shared Function IStream_Size(<[In]()> ByVal pstm As IStream, <Out()> ByRef pui As Int64) As Int32
    3. End Function
    Gruß
    hal2000

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

    Da hier ein komplett anderes Codebeispiel folgt, halte ich einen Doppelpost für angemessen.

    Ich verwende eine Struktur "Record", um die beiden wesentlichen Eigenschaften von "CustomizationReqTypeClass" nachzubilden. Die Typen sind exakt gleich - der Rest ist irrelevant. In einer Liste mit Objekten dieser Struktur befindet sich ein gültiges Record-Objekt mit dem Namen "blue" und einem gültigen IStream, den ich zuvor erzeugt habe (Details dazu stehen weiter oben).

    VB.NET-Quellcode

    1. Structure Record
    2. Dim Name As String
    3. Dim Icon As TDAPIOLELib.IStream
    4. '... etc.
    5. End Structure
    6. Dim reqTypes As New List(Of Record) 'enthält ein gültiges Objekt.


    Der Stream soll nun ausgelesen werden. Weiterhin wird ein TreeNode erstellt, dem die ausgelesene Bitmap als Icon zugewiesen wird.

    VB.NET-Quellcode

    1. Sub GetIcons()
    2. 'COM-Spezifische Typen für RemoteSeek
    3. Dim lintNull As New TDAPIOLELib._LARGE_INTEGER With {.QuadPart = 0}
    4. Dim ulint As New TDAPIOLELib._ULARGE_INTEGER
    5. Dim il As New ImageList() 'ImageList erstellen
    6. TreeView1.ImageList = il 'ImageList zuweisen
    7. For Each custObj In reqTypes 'Für jeden Datensatz
    8. Dim icon As TDAPIOLELib.IStream = custObj.Icon 'gib Icon
    9. icon.RemoteSeek(lintNull, 0, ulint) 'Zeiger an den Anfang des Streams setzen
    10. Dim streamLen As Int64
    11. Dim hr As Int32 = IStream_Size(icon, streamLen) 'Länge des Streams ermitteln
    12. Dim buffer(CInt(streamLen - 1)) As Byte 'Puffer bereitstellen
    13. Dim bytesRead As UInt32
    14. icon.RemoteRead(buffer(0), CUInt(streamLen), bytesRead) 'Stream auslesen
    15. If bytesRead <> streamLen Then Throw New InvalidOperationException("Die Länge stimmt nicht") 'Angeforderte Länge mit der zurückgegebenen vergleichen
    16. Using ms As New IO.MemoryStream(buffer)
    17. il.Images.Add(custObj.Name, Image.FromStream(ms)) 'Icon unter TPR_NAME in die ImageList schreiben
    18. End Using
    19. Dim n As New TreeNode(custObj.Name)
    20. n.ImageKey = custObj.Name 'Icon auswählen
    21. TreeView1.Nodes.Add(n)
    22. Next
    23. End Sub

    Das sieht dann so aus:
    Gruß
    hal2000
    Hi hal,
    das sieht verdammt gut aus. Beim Beladen der Liste aus den Sätzen stört sich die Routine allerdings noch daran, daß beim Icon "System.String" nicht in "TDAPIOLELib.iStream" umgewandelt werden kann. Aus der DB kommt das Teilchen als VarChar. Konvertieren kenn ich schon ein wenig, aber wie konvertiert man String zum iStream? ?(

    Habe hier was gefunden vonwegen Umsetzen in einen Memorystream!?
    Aber da meckert er bei der Zuweisung auf das Icon der Record-Struktur, daß er System.IO.MemoryStream nicht in TDAPIOLELib.iStream umwandeln kann.

    HolgerNils

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

    Hi Hal,
    hatte ich auch so erwartet, gemäss API-Beschreibung ist das Icon vom Typ iStream.
    (PS: File erhalten?)

    Wenn ich mir die DB aber anschaue, dann ist das Teil als VarChar definiert.
    Möchte jetzt nicht ausschliessen, daß VarChar die Daten eines iStreams aufnehmen kann.
    Jedenfalls verweigert sich der Befehl mit der genannten Fehlermeldung String geht nicht auf IStream.
    Watt ein Gedöns!

    HolgerNils schrieb:

    File erhalten?

    Ja. Deswegen wundert mich das ein wenig - CustomizationReqTypeClass hat eine Eigenschaft vom Typ IStream - es ist doch irrelevant, wie die API aus dem VarChar-Feld einen IStream macht. Ich bin davon ausgegangen, dass dir der Stream wie im folgenden Bild zur Verfügung steht:

    Wenn dem nicht so ist: Wo bekommst du ihn dann her (und wie bist du dann am Anfang überhaupt auf den IStream gekommen, wenn die Daten doch als VarChar (String in VB) vorliegen)?
    Gruß
    hal2000
    Sorry, mein Fehler.
    Habe die Sätze direkt aus der DB gelesen und nicht die API bemüht.
    Klar, daß das Feld dann anders aussieht.

    Sorry for that.
    Nach Umbiegung auf die API als Quelle aus der ich eine Liste aller ReqTypes abrufe akzeptiert das Programm den Input.
    Meckert aber dennoch "Der Einstiegspunkt "IStream_Size" wurde in der DLL "Shlwapi.dll" nicht gefunden allerdings wird die Variable "hr" nirgendwo benutzt. Wenn ich die Zeile dann rausnahme geht er mit 0 als Länge überall rein. Sollte nicht streamlen aus Istream_size gefüllt werden?

    Holger


    EDIT:
    Habe streamLen mal auf 578 gesetzt, das liest er jedenfalls als Streamlenge (bytesRead)
    und zusätzlich die Zuweisung von "hr" ausgesternt.

    Dann gehts.
    Beim zweiten Satz krieg ich allerdings einen "allgemeiner Fehler in GDI+"
    bei Ausführung von
    Using ms As New IO.MemoryStream(buffer)
    il.Images.Add(custObj.Name, Image.FromStream(ms))
    End Using

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

    HolgerNils schrieb:

    allerdings wird die Variable "hr" nirgendwo benutzt

    Das ist Absicht. IStream_Size liefert ein HRESULT (=Int32) zurück; der Wert wird in "hr" festgehalten (zu Debugzwecken). Haltepunkt drauf, F5, 1x Einzelschritt, Wert von hr anschauen (?hr <Enter> im Direktfenster, 0 = alles ok, alles andere: Fehler)

    HolgerNils schrieb:

    Sollte nicht streamlen aus Istream_size gefüllt werden?

    Ja, das sollte es. streamLen wird ByRef[erence] übergeben, wird also von IStream_Size "gefüllt".

    HolgerNils schrieb:

    allgemeiner Fehler in GDI+

    Das liegt daran, dass nicht alle Daten des Bildes ausgelesen wurden. Das Bild muss vollständig sein, sonst kann Image.FromStream die Daten nicht interpertieren. Selbst meine kleine "blau"-Bitmap aus dem Screenshot hat schon über 1000 Byte - 578 ist als Streamlänge viel zu kurz.

    Der Einstiegspunkt "IStream_Size" wurde in der DLL "Shlwapi.dll" nicht gefunden

    Hast du die Deklaration richtig abgeschrieben? Die Groß- und Kleinschreibung ist z.B. wichtig. Die Dokumentation gibt als minimales Betriebssystem Windows 2000 an (falls du für ein älteres System schreiben solltest). Link: msdn.microsoft.com/en-us/library/bb773805%28VS.85%29.aspx. Diese Funktion ist essentiell für das Auslesen des Icons (schließlich liefert sie die Länge des zu lesenden Datenblocks).
    Gruß
    hal2000
    Ah, danke für die Erklärungen!

    Steht also alles mit der Ausführung von "iStream_Size" an der Stelle.
    Hab die 578 als Länge mal zurückgebaut ;)

    Was die Deklaration angeht habe ich die kopiert und somit exakt übernommen und ein Vergleich war positiv.

    Auf meinem Rechner (WinXP) ist von der shlwapi.dll die Version 6.0.2900.5912 (WinXP SP3) vorhanden, sollte also ausreichen.
    Dennoch weigert er sich.

    Die Deklaration habe ich vor das Sub gepackt, ist das richtig? Zumindest meckert .NET nicht.
    Wenn ich versuche die Datei nochmal zu registrieren meckert Windows, die DLL würde gefunden aber der Einstiegspunkt wäre nicht auffindbar.

    Holger

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