2017-07-05 1 views
0

Ich bin neu zu versuchen, Code in VBA zu schreiben, um WinAPI-Funktionen zu verwenden. Mit welcher Codierung arbeitet die Funktion WinAPI Normalize()? UTF-16 ist, was ich erwarten würde, aber das Folgende funktioniert nicht. Die Anzahl der Zeichen scheint nicht richtig berechnet zu sein, und der Versuch, eine normalisierte Zeichenfolge zu erstellen, stürzt nur Access ab.VBA String Normalisierung (über WinAPI)

'normFormEnum 
'not random numbers, but from ... 
'https://msdn.microsoft.com/en-us/library/windows/desktop/dd319094(v=vs.85).aspx 
'for use in calling the Win API Function NormalizeString() 
Public Enum normFormEnum 
    normFOther = 0 
    normFC = 1  'the W3C (Internet) required normalization format 
    normFD = 2 
    normFKC = 5 
    normFKD = 6 
End Enum 

'https://msdn.microsoft.com/en-us/library/windows/desktop/dd319093(v=vs.85).aspx 
Private Declare Function NormalizeString Lib "Normaliz" (_ 
    ByVal normForm As normFormEnum, _ 
    ByVal lpSrcString As LongPtr, _ 
    ByVal cwSrcLength As Long, _ 
    ByRef lpDstString As LongPtr, _ 
    ByVal cwDstLength As Long _ 
    ) As Long 

Public Function stringNormalize(_ 
    ByVal theString As String, _ 
    Optional ByVal normForm As normFormEnum = normFC _ 
    ) As String 

    Dim nChars As Long 
    Dim newString As String 

    nChars = NormalizeString(normForm, StrPtr(theString), Len(theString), 0&, 0) 

    'prefill the string buffer so it can be altered shortly... 
    newString = String(nChars, " ") 

Debug.Print nChars 
'prints nChars, showing that it 3x the amount of characters. 

'The following will crash the application.... 

' NormalizeString normForm, StrPtr(theString), Len(theString), StrPtr(newString), nChars 

    stringNormalize = newString 

End Function 
+0

Stab im Dunkel: 'Len' gibt die Anzahl der * Zeichen * in der Zeichenfolge; Hast du stattdessen 'LenB' ​​probiert, welches die Anzahl von * Bytes * in der Zeichenkette zurückgibt? VBA-Zeichenfolgen verwenden 2 Byte pro Zeichen. –

+0

@ Mat'sMug: Die Funktion Len() gibt die Anzahl der UTF-16-Code-Einheiten zurück. Die LenB() - Funktion wird doppelt so groß sein und ein noch schlechteres Ergebnis liefern. – someprogrammer

+0

'Len' gibt die Anzahl der ANSI-Zeichen in einer Zeichenfolge zurück. Dass dies UTF-16-Code-Einheiten entspricht, ist ein Zufall. –

Antwort

1

Die Funktion NormalizeString eine geschätzte Größe in Bytes zurückgibt, wenn cwDstLength 0 ist, aber Sie es als die Anzahl der Zeichen verwenden.

vom ersten Anruf der Hälfte des Ergebnis So nehmen und den Puffer mit dem Ergebnis aus dem zweiten Aufruf gestutzt:

Private Declare PtrSafe Function NormalizeString Lib "Normaliz" (_ 
    ByVal normForm As Long, _ 
    ByVal lpSrcString As LongPtr, _ 
    ByVal cwSrcLength As Long, _ 
    ByVal lpDstString As LongPtr, _ 
    ByVal cwDstLength As Long _ 
) As Long 

Public Enum NormalizationForm 
    NormOther = 0 
    NormC = 1 
    NormD = 2 
    NormKC = 5 
    NormKD = 6 
End Enum 


Public Function NormalizeStr(source As String, ByVal normForm As NormalizationForm) As String 
    Dim buffer$, size& 

    size = NormalizeString(normForm, StrPtr(source), Len(source), 0, 0) 

    buffer = String(size \ 2 + 1, vbNullChar) 

    size = NormalizeString(normForm, StrPtr(source), Len(source), StrPtr(buffer), Len(buffer)) 

    NormalizeStr = Left$(buffer, size) 
End Function 


Public Sub Usage() 
    Debug.Print NormalizeStr(ChrW(196), NormD) 
    Debug.Print NormalizeStr("A" & ChrW(776), NormC) 
End Sub 
+0

Vielen Dank für Ihre Antwort. Es funktioniert hier nicht. Erstens gibt es ein Vielfaches von 3 für die Größe, nicht von 2. Wenn es ein Vielfaches von 2 wäre, würde ich denken, dass es Bytes waren, aber ein Vielfaches von 3 macht für mich keinen Sinn. Ich habe versucht, es auf verschiedene Arten zu optimieren und es stürzt jedes Mal ab. – someprogrammer

+0

Es funktioniert für mich. Die Größe von dem ersten Anruf ist eine geschätzte Kapazität in Bytes, die zugewiesen wird, um das Ergebnis für den schlimmsten Fall anzupassen. Es repräsentiert nicht die Größe des Ergebnisses. Da ein Unicode-Zeichen auf 2 Bytes dargestellt wird, müssen Sie diese Kapazität durch 2 teilen, um eine geschätzte Anzahl von Zeichen zu erhalten. Sie erhalten die tatsächliche Größe ab dem zweiten Anruf. –