Είχα ξεκινήσει πριν από λίγο καιρό να μεταφράζω κώδικα σε C# με σκοπό να γίνει C++ για μετατροπή ενός ποσού σε Ευρώ Ολογράφως. Αφού έφτασε σε ένα σημείο που δούλευε ικανοποιητικά μαζεύτηκε αυτό και μερικές άλλες λειτουργίες στο DVAUtils.dll. Αυτό το dll εξάγει μερικές functions που κάνουν αυτή τη μετατροπή του ποσού σε λεκτικό, αλλά και ενός COM object που κάνει το ίδιο πράγμα. Υπάρχουν και μερικές ακόμα functions και επιπλέον com objects αλλά είναι άσχετα με το συγκεκριμένο.
Ο λόγος που έγιναν και τα com objects και οι exported fucntions είναι ώστε να υπάρχουν περισσότερες επιλογές, συνεπώς και δυνατότητες, από τον τελικό χρήστη σχετικά με το πως θα χρησιμοποιήσει το dll.
- Αν έχει τη δυνατότητα (ή τη θέληση) να κάνει register το dll θα μπορεί να χρησιμοποιήσει το com object που εξάγεται.
- Αν δεν έχει αυτή τη δυνατότητα (ή τη θέληση) θα μπορεί να χρησιμοποιήσει πάλι την ίδια λειτουργικότητα μέσα από τις exported functions, δηλώνοντας τες χρησιμοποιώντας τη σύνταξη της declare function.
Για να αφήσουμε τα πολλά λόγια και να πάμε στο ψητό, να δούμε τι δυνατότητες χρήσης υπάρχουν:
Αν ο χρήστης που έχει πάρει το dll μπορεί/θέλει να το κάνει register χρησιμοποιώντας την εντολή
regsvr32 <path>DVAUtils.dll
Τότε δεν χρειάζεται να απασχολεί την εφαρμογή του για το ποιό είναι το path στο οποίο βρίσκεται το dll. Θα το βρεί από το μητρώο των windows όποιο κι αν είναι αυτό.
Μπορεί να χρησιμοποιήσει το com object DVA.Euro είτε μέσα από early binding (το οποίο και συστήνεται) είτε μέσα από late binding.
Early Binding
Για να χρησιμοποιήσουμε 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.
Δείτε επίσης:
Εγινε μια μικρή διόρθωση στον κώδικα. Για το “μηδέν ευρώ” εμφανιζόταν λάθος λεκτικό.
Εγιναν μερικές διορθώσεις στο κείμενο ώστε να βγάζει καλύτερα νόημα. Αν κάτι φαίνεται “κινέζικο” είμαι ανοικτός σε προτάσεις.