Ευρώ Ολογράφως – VB Use

Είχα ξεκινήσει πριν από λίγο καιρό να μεταφράζω κώδικα σε C# με σκοπό να γίνει C++ για μετατροπή ενός ποσού σε Ευρώ Ολογράφως. Αφού έφτασε σε ένα σημείο που δούλευε ικανοποιητικά μαζεύτηκε αυτό και μερικές άλλες λειτουργίες στο DVAUtils.dll.  Αυτό το dll εξάγει μερικές functions που κάνουν αυτή τη μετατροπή του ποσού σε λεκτικό, αλλά και ενός COM object που κάνει το ίδιο πράγμα. Υπάρχουν και μερικές ακόμα functions και επιπλέον com objects αλλά είναι άσχετα με το συγκεκριμένο.

Ο λόγος που έγιναν και τα com objects και οι exported fucntions είναι ώστε να υπάρχουν περισσότερες επιλογές, συνεπώς και δυνατότητες, από τον τελικό χρήστη σχετικά με το πως θα χρησιμοποιήσει το dll.

  1. Αν έχει τη δυνατότητα (ή τη θέληση) να κάνει register το dll θα μπορεί να χρησιμοποιήσει το com object που εξάγεται.
  2. Αν δεν έχει αυτή τη δυνατότητα (ή τη θέληση) θα μπορεί να χρησιμοποιήσει πάλι την ίδια λειτουργικότητα μέσα από τις exported functions, δηλώνοντας τες χρησιμοποιώντας τη σύνταξη της declare function.

Για να αφήσουμε τα πολλά λόγια και να πάμε στο ψητό, να δούμε τι δυνατότητες  χρήσης υπάρχουν:

Αν ο χρήστης που έχει πάρει το dll μπορεί/θέλει να το κάνει register χρησιμοποιώντας την εντολή

regsvr32 <path>DVAUtils.dll

Τότε δεν χρειάζεται να απασχολεί την εφαρμογή του για το ποιό είναι το path στο οποίο βρίσκεται το dll. Θα το βρεί από το μητρώο των windows όποιο κι αν είναι αυτό.

Μπορεί να χρησιμοποιήσει το com object DVA.Euro είτε μέσα από early binding (το οποίο και συστήνεται) είτε μέσα από late binding.

Early Binding

References menu
References menu
DVA Tools 1.4 reference
DVA Tools 1.4 reference

Για να χρησιμοποιήσουμε early binding πρέπει να δώσουμε στην vb όλες τις πληροφορίες σχετικά με το com object. Αυτό γίνεται προσθέτοντας το dll στα references, επιλέγοντας από τη λίστα το “DVA Tools 1.4”. Κανονικά η λίστα πρέπει να είναι αλφαβητικά ταξινομημένη (έχοντας πρώτα τα ήδη επιλεγμένα στοιχεία) οπότε θα πρέπει να κατέβουμε μερικές οθόνες μέχρι να το βρούμε.

Τώρα μπορούμε να γράψουμε λίγο κώδικα όπως εδώ:

Public Sub COM_Early_Bind_Sample_SayEuro()
    Dim obj As DVA.Euro
    Dim s As String
    Dim money As Double

    Set obj = New DVA.Euro
    money = 9876543212345.67

    s = obj.SayEuro(money)
    Debug.Print s

    Set obj = Nothing
End Sub

ή χρησιμοποιώντας τον τύπο δεδομένων Currency αντί για Double:

Public Sub COM_Early_Bind_Sample_SayEuro2()
    Dim s As String
    Dim money As Currency
    Dim obj As DVA.Euro

    Set obj = New DVA.Euro
    money = 9876543212345.67

    s = obj.SayEuro2(money)
    Debug.Print s

    Set obj = Nothing
End Sub

Late Binding

Στην περίπτωση που δεν θέλουμε για τον οποιοδήποτε λόγο να χρησιμοποιήσουμε early binding, μπορούμε πάντα να χρησιμοποιήσουμε late binding. Η VB μας δίνει δυνατότητα επιλογής, αν όμως θέλαμε να χρησιμοποιήσουμε αυτό το dll σε κάποια php, ή asp σελίδα εκεί η μόνη δυνατότητα είναι το late binding.

Ο κώδικας χρησιμοποιώντας late binding μπορεί να είναι κάπως έτσι:

Public Sub COM_Late_Bind_Sample_SayEuro()
    Dim s As String
    Dim money As Double
    Dim obj As Object

    Set obj = CreateObject("DVA.Euro")
    money = 9876543212345.67

    s = obj.SayEuro(money)
    Debug.Print s

    Set obj = Nothing
End Sub

ή χρησιμοποιώντας τον τύπο δεδομένων Currency αντί για Double:

Public Sub COM_Late_Bind_Sample_SayEuro2()
    Dim obj As Object

    Dim s As String
    Dim money As Currency

    Set obj = CreateObject("DVA.Euro")
    money = 9876543212345.67

    s = obj.SayEuro2(money)
    Debug.Print s

    Set obj = Nothing
End Sub

Αφού είναι προτιμότερο να χρησιμοποιείται early binding γιατί να χρησιμοποιήσει κάποιος late binding; Ο πιο βασικός λόγος που θα μπορούσα να βρώ είναι διότι το early binding δεν είναι πάντα διαθέσιμο. Για παράδειγμα όταν φτιάχνουμε μια .asp ιστοσελίδα μπορούμε να χρησιμοποιήσουμε μόνο late binding, αλλά εξακολουθούμε να έχουμε όλη τη λειτουργικότητα που μας προσφέρουν τα com objects.

<html>
<head>Sample .asp (JScript) web page</head>
<body>
<%
    function JScript_Sample(money)
    {
        var obj = new ActiveXObject("DVA.Euro");
        var s = obj.SayEuro(money);
        obj = null;
        return s;
    }
    Response.Write (JScript_Sample(123456.78));
%>
</body>
</html>

Αν ο χρήστης που έχει πάρει το dll δεν μπορεί/ δεν θέλει να το κάνει register, εξακολουθεί να μπορεί να το χρησιμοποιήσει μέσα από τις exported functions.

Η διαφορά εδώ είναι ότι θα πρέπει να έχει φροντίσει ο χρήστης να βάλει το dll σε κάποιο σημείο το οποίο έχει προκαθορίσει (π.χ. μέσα στο C:My Folder) και να δηλώσει από το path στη δήλωση της Declare Function, ή να το βάλει σε κάποιο σημείο στο οποίο ψάχνουν από μόνα τους τα windows (π.χ. στον φάκελο C:Windows ή στο C:WindowsSystem32) και στη δήλωση της Declare Function να βάλει μόνο το όνομα του dll, χωρίς το path.

Χρήση των functions

Οι functions που εξάγονται προσφέρονται σε δύο εκδόσεις ansi με ονομασία (xxxA) και unicode. Ολες οι functions παίρνουν μια output παράμετρο, την διεύθυνση του buffer που θα τοποθετήσουν το string, και σαν τιμή επιστροφής δίνουν το μέγεθος του string που επέστρεψαν. Για να χρησιμοποιηθούν από την VB πρέπει να δηλωθούν ως εξής:

Declare Function SayEuroA Lib "DVAUtils.dll" (ByVal money As Double, ByVal bufferA As Long) As Long
Declare Function SayEuroW Lib "DVAUtils.dll" (ByVal money As Double, ByVal bufferW As Long) As Long
Declare Function SayEuro2A Lib "DVAUtils.dll" (ByVal money As Currency, ByVal bufferA As Long) As Long
Declare Function SayEuro2W Lib "DVAUtils.dll" (ByVal money As Currency, ByVal bufferW As Long) As Long

Declare Function SayEuro Lib "DVAUtils.dll" Alias "SayEuroA" (ByVal money As Double, ByVal buffer As String) As Long
Declare Function SayEuro2 Lib "DVAUtils.dll" Alias "SayEuro2A" (ByVal money As Currency, ByVal buffer As String) As Long

Οι συγκεκριμένες δηλώσεις χρησιμοποιούν απλώς το όνομα του dll χωρίς το Path, οπότε θα πρέπει να έχει βάλει ο χρήστης κάπου που τα windows να μπορούν να το βρούν από μόνα τους, π.χ. στον φάκελο C:Windows.

Τώρα που έχουν δηλωθεί οι συναρτήσεις, μπορούν να χρησιμοποιηθούν ως εξής:

'UNICODE Version
Public Function Sample_SayEuroW()
    Dim s As String
    Dim L As Long
    Dim money As Double

    money = 9876543212345.67

    L = SayEuroW(money, 0)
    s = String(L, Chr(0))
    L = SayEuroW(money, StrPtr(s))
    s = Left(s, L)
    Debug.Print s

End Function
'ANSI Version
Public Sub Sample_SayEuroA()
    Dim s As String
    Dim L As Long
    Dim money As Double

    money = 9876543212345.67

    L = SayEuroW(money, 0)
    s = String(L, Chr(0))
    L = SayEuroA(money, StrPtr(s))
    s = Left(StrConv(s, vbUnicode), L)
    Debug.Print s

End Sub
'ANSI Version only
Public Sub Sample_SayEuro()
    Dim s As String
    Dim L As Long
    Dim money As Double

    money = 9876543212345.67

    s = String(512, Chr(0))
    L = SayEuro(money, s)
    s = Left(s, L)
    Debug.Print s

End Sub

ή χρησιμοποιώντας τον τύπο δεδομένων Currency αντί για Double:

'UNICODE Version
Public Function Sample_SayEuro2W()
    Dim s As String
    Dim L As Long
    Dim money As Currency

    money = 9876543212345.67

    L = SayEuroW(money, 0)
    s = String(L, Chr(0))
    L = SayEuro2W(money, StrPtr(s))
    s = Left(s, L)
    Debug.Print s

End Function
'ANSI Version
Public Sub Sample_SayEuro2A()
    Dim s As String
    Dim L As Long
    Dim money As Currency

    money = 9876543212345.67

    L = SayEuroW(money, 0)
    s = String(L, Chr(0))
    L = SayEuro2A(money, StrPtr(s))
    s = Left(StrConv(s, vbUnicode), L)
    Debug.Print s

End Sub
'ANSI Version only
Public Sub Sample_SayEuro2()
    Dim s As String
    Dim L As Long
    Dim money As Double

    money = 9876543212345.67

    s = String(512, Chr(0))
    L = SayEuro2(money, s)
    s = Left(s, L)
    Debug.Print s

End Sub

Τι αξίζει να σημειωθεί επιπλέον:
Για να απλουστευθεί η χρήση, οι functions αυτές περιμένουν από τον χρήστη να δεσμεύσει ένα αρκετά μεγάλο string (που να χωράει τα περιεχόμενα), και να δώσει τη διεύθυνση του string σαν παράμετρο ώστε να το “γεμίσει” η function με το λεκτικό. Πως θα ξέρει όμως ο χρήστης πόσο μεγάλο string πρέπει να δημιουργήσει; Πρέπει να είναι 10 χαρακτήρες; Πρέπει να είναι 100 χαρακτήρες;
Η απλή και γρήγορη λύση είναι να φτιαχτεί ένας buffer τουλάχιστον 512 χαρακτήρες. Σε καμία περίπτωση το string που θα φτιαχτεί δεν πρόκειται να ξεπεράσει τους 300 χαρακτήρες (αλλά βάζουμε 512 για να είναι πιο στρογγυλό το νούμερο).

    s = String(512, Chr(0))

Η πιο ακριβής λύση είναι να καλέσουμε μια φορά την function περνώντας null (0) σαν παράμετρο για να δούμε πόσο χώρο χρειαζόμαστε και να δεσμεύσουμε τόσο χώρο. (Ο χώρος αυτός είναι τουλάχιστον όσο μεγάλος χρειάζεται για να χωρέσει το string συν ένας επιπλέον χαρακτήρας – ο τελικός χαρακτήρας nul τον χρησιμοποιεί η C ώστε να σηματοδοτήσει το τέλος του string).

    L = SayEuroW(money, 0)
    s = String(L, Chr(0))

Κατεβάστε το dll, τα source files, ένα παράδειγμα σε excel και ένα σε access.

Δείτε επίσης:

2 Comments

  1. Εγινε μια μικρή διόρθωση στον κώδικα. Για το “μηδέν ευρώ” εμφανιζόταν λάθος λεκτικό.

  2. Εγιναν μερικές διορθώσεις στο κείμενο ώστε να βγάζει καλύτερα νόημα. Αν κάτι φαίνεται “κινέζικο” είμαι ανοικτός σε προτάσεις.