Ribbon kann nicht mehr geprüft werden?, CopyMemory 64-Bit
#11
Hallo

Nur so:
Ich arbeite schon mehrere Jahre mit Excel 64 bit ohne Probleme, ich werde immer dabei bleiben.
Arbeite auch mit Addins die ich mir Dank mumpel erst in einer 32 bit Version vorbereitet habe und bei Gebrauch im Menü anzeigen lassen, auch dies klappt einwandfrei in 64 bit Version.
Viele Grüße
PIVPQ
Antworten Top
#12
Ich denke, Du solltest erst versuchen zu verstehen, was CopyMemory überhaupt macht. 

Anbei ein Beispiel, zum Verstehen und Debuggen!!
Quelle:  CopyMemory was ist das? - Sonstige Problemstellungen - VB-Paradise 2.0 – Die große Visual-Basic- und .NET-Community

Code:
Public Declare Sub CopyMemory Lib "kernel32" Alias _
    "RtlMoveMemory" (destination As Any, source As Any, _
    ByVal length As Long)

Sub test()

    Dim b1(19) As Byte
    Dim i As Long
    For i = 0 To 19
        b1(i) = i
    Next i
   
    Dim b2(5) As Byte

    CopyMemory b2(0), b1(9), 6
End Sub

Wir haben hier ein Byte-Array. Arrays sind zusammenhängender Speicher. Arrays werden niemals auf unterschiedliche Speicheradressen aufgeteilt; jedes Array-Element folgt unmittelbar auf das vorherige Array-Element im Speicher. Also ist das zweite Element hier im Array 1 Byte hinter dem ersten Element, das dritte 2 Byte usw.
Antworten Top
#13
Moin,

Ich bin selbst nicht sehr Firm in API-Calls, aber soweit ich informiert bin, ist der Unterschied bei CopyMemory, dass du im 32-Bit System eine Variable ByRef übergibst und CopyMemory dabei die Speicheradresse der Variable erhält. In der 64 Bit Version wird ein Zeiger auf die Variable byVal erwartet. Und die Speicheradresse also selbst die übergebene Zahl ist. Den Zeiger erhältst du eben mit den VarPtr oder ObjPtr. 

Schau mal im Beispielbereich des Forums, volti hat da seinen API-Viewer irgendwo hochgeladen da erhältst du immerhin die Deklarationen.

Viele Grüße 
derHöpp
Antworten Top
#14
https://stackoverflow.com/a/62127904/6600940

Es ist nicht so, dass die Benutzung von Any generell falsch ist, denn so ist CopyMemory definiert.
Zitat:Having declared the same parameters as ByVal pDest As LongPtr, ByVal pSrc As LongPtr, you lose the ability to pass Longs ByRef like in the first example and will need to explicitly use VarPtr each time, but you won't need to think too much how to call the function.

There is still some danger though, because you can still call it as CopyMemory a, b with Long parameters, and it will crash for passing values as pointers, but at least you will see from the function definition what you are passing something wrong, while As Any doesn't give you a hint.
Und man muss natürlich wissen, was VarPtr und ObjPtr zurückliefert.
Antworten Top
#15
Hallo zusammen,

ich weiß gar nicht, warum immer in den Foren auf der 64-Bit-Version rumgehakt wird  Smile

Ich habe die jetzt schon seit 2016 und keine Probleme. Ich verwende sehr viel API-Kram.

Hier zum Abschluss noch interessehalber meine seit Jahren funktionierende (aber für hier etwas veränderte) Version der Ribbonwiederherstellung.
Allerdings werden sämtliche Invalidates über eine eigene Funktion geleitet und der Ribbon-Pointer nicht in der Registry sondern in der jeweiligen Mappe gespeichert.

Vielleicht hilft es ja dem einen oder anderen oder einfach nur zum Gucken, wie es auch gehen kann.

Code:

Dim goRibbon    As IRibbonUI
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
        Destination As Any, Source As Any, ByVal Length As LongPtr)

'----- Ribbon initialisieren -----
'------ Diese Funktion ist im Ribbon für On‌Load="RibbonInit" angegeben -----
Private Sub RibbonInit(lpRibbon As IRibbonUI)
  Set goRibbon = lpRibbon       'globalen Pointer setzen und in einem Namen sichern
  ThisWorkbook.Names.Add Name:="MyRibbon", _
     RefersTo:=CStr(ObjPtr(lpRibbon)), Visible:=False
End Sub

Sub RefreshRibbon(Optional sID As String)
' Das angegebene Control oder der ganze Ribbon wird neu berechnet
  Dim lpRibbon As LongPtr
 
  If goRibbon Is Nothing Then
'Ribbon-Pointer aus Namen wiederherstellen
     On Error Resume Next
     lpRibbon = CLngPtr(Mid$(ThisWorkbook.Names("MyRibbon").RefersTo, 2))
     CopyMemory goRibbon, lpRibbon, LenB(lpRibbon)
  End If
  If sID <> "" Then
     goRibbon.InvalidateControl sID
  Else
     goRibbon.Invalidate
  End If
End Sub

_________
viele Grüße
Karl-Heinz
Antworten Top
#16
Guten Tag zusammen

Zunächst vielen Dank für Eure Unterstützung. Das mit dem Speichern in der Arbeitsmappe finde ich interessant, verstehe aber nicht ganz, wo das genau sein soll. Das habe ich so noch nie gesehen. Weil mir ein Fehler (wollte den String "ribValue" zusätzlich einsetzen) unterlaufen ist, poste ich hier nochmals den lauffähigen Code mit Registry.


Code:
Public Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, source As Any, ByVal Length As LongPtr)                                                                                           
Public Sub OnRibbonLoad(ribbon As IRibbonUI)
    SaveSetting "msoFile", CONmenuNEW, "objRibbonVar", ObjPtr(ribbon)
    On Error Resume Next
    If val(Application.Version) > 12 Then gobjRibbon.ActivateTab CONmenuNEW
    On Error GoTo 0
End Sub

….
If TestRibbon = True Then Call Application.OnTime(EarliestTime:=Now, Procedure:="SwitchTabMain")

….
If TestRibbon = True Then gobjRibbon.InvalidateControl "btnSpeichern"
Public Sub SwitchTabMain()
    On Error Resume Next
    gobjRibbon.ActivateTab CONmenuNEW: If Err.Number < 0 Then Err.Clear
End Sub

Public Function TestRibbon() As Boolean
Dim varRegWert As Variant
Dim ribValue As String
    If gobjRibbon Is Nothing Then
        varRegWert = CVar(GetAllSettings(appName:="msoFile", section:=CONmenuNEW))
        If IsEmpty(varRegWert) = False Then
            ribValue = GetSetting("msoFile", CONmenuNEW, "objRibbonVar")
            If Len(ribValue) > 0 Then
                Set gobjRibbon = GetRibbon(CLngPtr(ribValue))
                If gobjRibbon Is Nothing Then
                    TestRibbon = False
                Else
                    TestRibbon = True
                End If
            Else
                TestRibbon = False
            End If
        End If
    Else
        TestRibbon = True
    End If
End Function

Public Function GetRibbon(ByVal lRibbonPointer As LongPtr) As Object
Dim NewobjRibbon As IRibbonUI
    CopyMemory VarPtr(NewobjRibbon), lRibbonPointer, LenB(lRibbonPointer)
    Set GetRibbon = NewobjRibbon
    Set NewobjRibbon = Nothing
    CopyMemory NewobjRibbon, 0&, 4
    If Err.Number > 0 Then Err.Clear
End Function
Antworten Top
#17
Zitat:verstehe aber nicht ganz, wo das genau sein soll.
Das wird als Name in der Tabelle gespeichert. Das müsstest Du dann als Name auch finden, wie auch beim manuellen Eibfügen eines Namens (Einfügen=>Name).
Antworten Top
#18
Hallo Stefan,

noch mal 'ne Frage zu Deinem Code.

Was steht denn in  ConMenueNew? Ein Tabellenname oder der gerade aktuelle Tabellenname?

Hierfür wird ja dann wohl ein Eintrag in der Registry gemacht. Warum ich das mit der Registry nicht gemacht habe ist folgender Gedanke:

Was passiert, wenn man mehrere Mappen mit Ribbons aufmacht? Wird jetzt für jedes Ribbon ein Eintrag in der Registry gesetzt oder nur ein Eintrag mit dem jeweils zuletzt Geöffneten. Dann könnte es beim Wiederherstellen Probleme geben.
Wird der Eintrag in der Registry auch wieder entfernt, z.B. beim Schließen der Mappe, oder bleibt der jetzt nach z.B. einmaligen Öffnen der Mappe für immer dort drin?

Sicher alles nur theoretisch und ohne weitere Probleme, aber vielleicht mal denkenswert.

Gruß
KH
Antworten Top
#19
Ihr könnt auch mal mein Beispiel testen. https://www.rholtz-office.de/ribbonx/iri...herstellen
[-] Folgende(r) 2 Nutzer sagen Danke an mumpel für diesen Beitrag:
  • Stefan1, Stefan1
Antworten Top
#20
Wink 
Guten Tag KH

ConMenueNew ist eine Konstante. Dahinter steht ein Name z.B. Dim const ConMenueNew as String = "Menü01" oder so. Es gibt Beispiele mit ThisWorkbook.Name, jedoch wollte ich das nicht, weil ich Versioniere im Dateinamen sowie den Dateinamen häufig bis zu letzt wieder anpasse und damit ungewohnt in der Tat immer wieder neue Registry eröffnen würde. Ja, zunächst habe ich das Registry jeweils beim schließen wieder gelöscht, doch mittlerweile ist das mir ziemlich egal, weil ja sowieso wieder mal ein neuer PC kommt und ich dafür alle in der gleichen Registry am gleichen zentralen Ort "objRibbonVar" ablege mit der kleinen generischen oder auch funktional wiedererkennbaren Unterscheidung "Menü01", "Menü02", "Tool X" usw. und so hat jede Arbeitsmappe, die ein eigenes Ribbon hat, sein eigener Ablageort in der Registry. Ich überlege trotzdem das Registry-Löschen wieder einführen. Gibt es dafür wirklich einen valablen Grund?

Zunächst bin ich mal dankbar, dass es nun mit dieser letztendlich banalen 64-bit-Version ohne Veränderung der Microsoft-Empfehlung für die Schreibweise dieser API CopyMemory wieder stabil funktioniert bis dann die 128-bit-Version kommt oder VBA nur noch Geschichte ist, was ich Nostalgiker vermissen werde (Smiley). Freuen wir uns, so lange wir noch können.

64-bit VBA-Version von Microsoft
Public Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, source As Any, ByVal Length As LongPtr)

Vielen Dank für Eure Beiträge.

Gruß
Stefan1
Antworten Top


Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste