Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Wind Tre 'accende' il 5G Standalone in Italia: si apre una nuova era basata sui servizi
Wind Tre 'accende' il 5G Standalone in Italia: si apre una nuova era basata sui servizi
Con la prima rete 5G Standalone attiva in Italia, WINDTRE compie un passo decisivo verso un modello di connettività intelligente che abilita scenari avanzati per imprese e pubbliche amministrazioni, trasformando la rete da infrastruttura a piattaforma per servizi a valore aggiunto
OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh
OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh
OPPO Find X9 Pro punta a diventare uno dei riferimenti assoluti nel segmento dei camera phone di fascia alta. Con un teleobiettivo Hasselblad da 200 MP, una batteria al silicio-carbonio da 7500 mAh e un display da 6,78 pollici con cornici ultra ridotte, il nuovo flagship non teme confronti con la concorrenza, e non solo nel comparto fotografico mobile. La dotazione tecnica include il processore MediaTek Dimensity 9500, certificazione IP69 e un sistema di ricarica rapida a 80W
DJI Romo, il robot aspirapolvere tutto trasparente
DJI Romo, il robot aspirapolvere tutto trasparente
Anche DJI entra nel panorama delle aziende che propongono una soluzione per la pulizia di casa, facendo leva sulla propria esperienza legata alla mappatura degli ambienti e all'evitamento di ostacoli maturata nel mondo dei droni. Romo è un robot preciso ed efficace, dal design decisamente originale e unico ma che richiede per questo un costo d'acquisto molto elevato
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 16-05-2005, 16:48   #1
leon84
Senior Member
 
L'Avatar di leon84
 
Iscritto dal: Jul 2002
Città: Napoli
Messaggi: 1964
Utilizzare un API in Visual Basic

Salve,
mi serve utilizzare la funzione di un'api in un mio programma ....

Su internet ho trovato che la funzione è la seguente :

Declare Function CreateDirectory Lib "kernel32.dll" Alias "CreateDirectoryA" _
(ByVal lpPathName As String, lpSecurityAttributes As SECURITY_ATTRIBUTES) _
As Long

Dove devo dichiararla ??? In quale parte del programma ????
leon84 è offline   Rispondi citando il messaggio o parte di esso
Old 16-05-2005, 17:03   #2
Massi91
Registered User
 
Iscritto dal: Apr 2005
Messaggi: 56
le api si dichiarano nella sezione "dichiarazioni" di una form o di un modulo oggetto, o in un modulo bas.
Da sola quella dichiarazione serve a poco perchè bisogna abbinare l'UDT (user defined type) SECURITY_ATTRIBUTES, dichiarato nel seguente modo:

Codice:
Type SECURITY_ATTRIBUTES
  nLength As Long
  lpSecurityDescriptor As Long
  bInheritHandle As Boolean
End Type
Per richiamare la funzione si usa il seguente metodo:
Codice:
Sub MakeDirectory(DirectoryPath As String)
Dim Attributes As SECURITY_ATTRIBUTES
Call CreateDirectory(DirectoryPath, Attributes)
End Sub
alla fine, il codice intero è questo:
Codice:
Declare Function CreateDirectory Lib "kernel32.dll" Alias "CreateDirectoryA" _
(ByVal lpPathName As String, lpSecurityAttributes As SECURITY_ATTRIBUTES) _
As Long

Type SECURITY_ATTRIBUTES
  nLength As Long
  lpSecurityDescriptor As Long
  bInheritHandle As Boolean
End Type

Sub MakeDirectory(DirectoryPath As String)
Dim Attributes As SECURITY_ATTRIBUTES
Call CreateDirectory(DirectoryPath, Attributes)
End Sub
ma non deve essere riportato dopo una end sub, function etc...

La struttura SECURITY_ATTRIBUTES definisce il livello ed il tipo di protezione da dare ad un oggetto. Le informazioni di sicurezza, sono usate più frequentemente sotto Windows NT/2000 che sotto Windows 95/98.

i membri sono:

nLength ---> Dimensione in byte della struttura
lpSecurityDescriptor ---> Il puntatore al descrittore per la sicurezza. Impostare a zero per il descrittore di default
bInheritHandle ---> Specifica se l'handle all'oggetto, sarà ereditato dal nuovo processo

ma sono opzionali, ti consiglio di impostarli tutti a zero, l'impostazione di partenza appena viene dicharata la variabile ma se ti servono, puoi modificare la funzione

Ultima modifica di Massi91 : 16-05-2005 alle 17:12.
Massi91 è offline   Rispondi citando il messaggio o parte di esso
Old 16-05-2005, 21:14   #3
leon84
Senior Member
 
L'Avatar di leon84
 
Iscritto dal: Jul 2002
Città: Napoli
Messaggi: 1964
Quote:
Originariamente inviato da Massi91
le api si dichiarano nella sezione "dichiarazioni" di una form o di un modulo oggetto, o in un modulo bas.
Da sola quella dichiarazione serve a poco perchè bisogna abbinare l'UDT (user defined type) SECURITY_ATTRIBUTES, dichiarato nel seguente modo:

Codice:
Type SECURITY_ATTRIBUTES
  nLength As Long
  lpSecurityDescriptor As Long
  bInheritHandle As Boolean
End Type
Per richiamare la funzione si usa il seguente metodo:
Codice:
Sub MakeDirectory(DirectoryPath As String)
Dim Attributes As SECURITY_ATTRIBUTES
Call CreateDirectory(DirectoryPath, Attributes)
End Sub
alla fine, il codice intero è questo:
Codice:
Declare Function CreateDirectory Lib "kernel32.dll" Alias "CreateDirectoryA" _
(ByVal lpPathName As String, lpSecurityAttributes As SECURITY_ATTRIBUTES) _
As Long

Type SECURITY_ATTRIBUTES
  nLength As Long
  lpSecurityDescriptor As Long
  bInheritHandle As Boolean
End Type

Sub MakeDirectory(DirectoryPath As String)
Dim Attributes As SECURITY_ATTRIBUTES
Call CreateDirectory(DirectoryPath, Attributes)
End Sub
ma non deve essere riportato dopo una end sub, function etc...

La struttura SECURITY_ATTRIBUTES definisce il livello ed il tipo di protezione da dare ad un oggetto. Le informazioni di sicurezza, sono usate più frequentemente sotto Windows NT/2000 che sotto Windows 95/98.

i membri sono:

nLength ---> Dimensione in byte della struttura
lpSecurityDescriptor ---> Il puntatore al descrittore per la sicurezza. Impostare a zero per il descrittore di default
bInheritHandle ---> Specifica se l'handle all'oggetto, sarà ereditato dal nuovo processo

ma sono opzionali, ti consiglio di impostarli tutti a zero, l'impostazione di partenza appena viene dicharata la variabile ma se ti servono, puoi modificare la funzione
Si ti ringrazio .... in realtà non capivo dove andava la funzione per il resto cioè il tipo definito dall'utente e come richiamarla questo si ... grazie molte ...
leon84 è offline   Rispondi citando il messaggio o parte di esso
Old 10-10-2005, 22:45   #4
guldo76
Senior Member
 
L'Avatar di guldo76
 
Iscritto dal: Nov 2002
Città: Morio Cho
Messaggi: 2595
Mi accodo per un problema analogo.
Qualcuno ha la bontà di spiegarmi come funziona?
Stavo cercando di usare questo:
Codice:
LONG RegOpenKeyEx(
  HKEY hKey,
  LPCTSTR lpSubKey,
  DWORD ulOptions,
  REGSAM samDesired,
  PHKEY phkResult
);
ma non ho proprio idea di come fare con tutti quei tipi di dati...
Ah, poi, io sto usando visual basic, che come avrete notato ha una sintassi diversa; la funzione la potrò usare ugualmente, no?
Cmq, credo di aver capito come si dichiarano le funzioni riferite a dll esterne; il mio problema sono i parametri...

Grazie
guldo76 è offline   Rispondi citando il messaggio o parte di esso
Old 10-10-2005, 23:00   #5
bertoz85
Bannato
 
L'Avatar di bertoz85
 
Iscritto dal: Jun 2002
Città: Nella Rossa Socialista Romagna (gambettola(fc))
Messaggi: 2066
x leon84: ti consiglio di impostare a Null il parametro security attributes se non lo usi.
Per farlo devi modificare la dichiarazione della funzione in questo modo:
Codice:
Declare Function CreateDirectory Lib "kernel32.dll" Alias "CreateDirectoryA" (ByVal lpPathName As String, ByVal lpSecurityAttributes As Long) As Long
E poi ogni volta che richiami la fuzione passi zero come secondo parametro.


Quote:
Originariamente inviato da guldo76
Mi accodo per un problema analogo.
Qualcuno ha la bontà di spiegarmi come funziona?
Stavo cercando di usare questo:
Codice:
LONG RegOpenKeyEx(
  HKEY hKey,
  LPCTSTR lpSubKey,
  DWORD ulOptions,
  REGSAM samDesired,
  PHKEY phkResult
);
Grazie
In visual basic c'è un comodo tool che si chiama API Viewer nel menu add-ins. Se non è abilitato vai in add-ins, add-in manager e attivalo. Dopo lo troverai sotto lo stesso menu.
Quando lo apri, fai File,apri e seleziona Win32api.txt ....avrai dihiarazioni di funzioni, costanti e tipi piu usati in windows, fatte per il vb.
Non è aggiornatissimo ma la maggior parte c'è (inclusa RegOpenKeyEx).


Comunque in linea di massima per convertirtele da te, hai bisogno della documentazione originale. Che tipo è REGSAM x esempio? Alla fine scopri che è un Long come la maggior parte d tipi strani, come anche HKEY.

ciao
bertoz85 è offline   Rispondi citando il messaggio o parte di esso
Old 10-10-2005, 23:33   #6
guldo76
Senior Member
 
L'Avatar di guldo76
 
Iscritto dal: Nov 2002
Città: Morio Cho
Messaggi: 2595
Grazie mille!!!
Ho trovato quello che mi serve, costanti comprese.
Ora (domani!) devo solo capire come usarla...


bye
guldo76 è offline   Rispondi citando il messaggio o parte di esso
Old 11-10-2005, 10:39   #7
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Per le API in VB scaricate APIGuide da www.allapi.net
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 12-10-2005, 09:52   #8
guldo76
Senior Member
 
L'Avatar di guldo76
 
Iscritto dal: Nov 2002
Città: Morio Cho
Messaggi: 2595
Grandioso, ragazzi!
Grazie MILLE a entrambi.

... però ho un piccolo problema...
Il valore binario che devo leggere dal registro contiene una data in formato esadecimale... Se uso la funzione di esempio per leggere un valore binario ottengo solo "2005" come risultato. E il resto della data?
Non ho idea di come recuperarlo...
Mi basterebbe anche avere la stringa contenente il valore esadecimale, che poi mi gestisco io; ma non ci riesco...
Un aiutino?
guldo76 è offline   Rispondi citando il messaggio o parte di esso
Old 12-10-2005, 11:09   #9
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
E se usi la funzione per leggere una stringa ?
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 12-10-2005, 11:23   #10
guldo76
Senior Member
 
L'Avatar di guldo76
 
Iscritto dal: Nov 2002
Città: Morio Cho
Messaggi: 2595
Ottengo una serie di caratteri non stampabili, e non il valore, che è una cosa del tipo:
hex:d5,03,...

Grazie
guldo76 è offline   Rispondi citando il messaggio o parte di esso
Old 12-10-2005, 17:00   #11
bertoz85
Bannato
 
L'Avatar di bertoz85
 
Iscritto dal: Jun 2002
Città: Nella Rossa Socialista Romagna (gambettola(fc))
Messaggi: 2066
dichiari un array dinamico di byte e ci butti dentro la stringa:
Codice:
Dim bArray() As Byte
bArray = StrConv(stringahex, vbFromUnicode)
dopodichè avrai un array base zero di Byte (stesso tipo che in C) con dentro i singoli valori interi che potrai tradurre in stringhe esadecimani con la funzione Hex$.

per trovare la prima e l'ultima cella di un array puoi utilizzare rispettivamente LBound e UBound

ciao
bertoz85 è offline   Rispondi citando il messaggio o parte di esso
Old 12-10-2005, 17:56   #12
guldo76
Senior Member
 
L'Avatar di guldo76
 
Iscritto dal: Nov 2002
Città: Morio Cho
Messaggi: 2595
Grazie mille della risposta, ma non sono troppo convinto...
Il contenuto del valore binario che mi interessa è una stringa di 16 numeri esadecimali; ma se lo leggo come stringa e lo metto in un array di byte, quest'ultimo ha dimensione 6. Che fine han fatto gli altri 10 numeri?!?

Grazie
guldo76 è offline   Rispondi citando il messaggio o parte di esso
Old 12-10-2005, 21:53   #13
bertoz85
Bannato
 
L'Avatar di bertoz85
 
Iscritto dal: Jun 2002
Città: Nella Rossa Socialista Romagna (gambettola(fc))
Messaggi: 2066
Quote:
Originariamente inviato da guldo76
Grazie mille della risposta, ma non sono troppo convinto...
Il contenuto del valore binario che mi interessa è una stringa di 16 numeri esadecimali; ma se lo leggo come stringa e lo metto in un array di byte, quest'ultimo ha dimensione 6. Che fine han fatto gli altri 10 numeri?!?

Grazie
sei sicuro di aver fatto la stringa che conterrà i dati lunga a sufficienza? devi prima crearla lunga abbastanza (usa Space$ con un valore abbast. alto da contenere il possibile valore del registro) ....
poi devi passargli la var con la lunghezza della stringa, che ti ritorna modificata...
di chie tipo sono i dati? a che scopo li leggi se posso saperlo (x aiutarti) ???

guarda bene la documentazione della funzione su msdn.microsoft.com

ciao
bertoz85 è offline   Rispondi citando il messaggio o parte di esso
Old 13-10-2005, 09:56   #14
guldo76
Senior Member
 
L'Avatar di guldo76
 
Iscritto dal: Nov 2002
Città: Morio Cho
Messaggi: 2595
La documentazione ufficiale non è che mi aiuti un granché...
L'array continua a essere di dimensione 6, perché è così l'intero che viene valorizzato dalla funzione RegQueryValueEx.
Il codice è il seguente.
Codice:
Sub Main()

Dim MyString As String
Dim bArray() As Byte
Dim Ret

'Set the string
MyString = Space$(1024)

'Open the key
RegOpenKey HKEY_LOCAL_MACHINE, "SOFTWARE\Symantec\Norton AntiVirus\LastScan", Ret

'Get the key's content
Dim lResult As Long, lValueType As Long, strBuf As String, lDataBufSize As Long

'retrieve nformation about the key
lResult = RegQueryValueEx(Ret, "SystemTime", 0, lValueType, ByVal 0, lDataBufSize)
If lResult = 0 Then
    If lValueType = REG_BINARY Then
        Dim strData As Long ' As Integer
        'retrieve the key's value
        lResult = RegQueryValueEx(Ret, "SystemTime", 0, 0, strData, lDataBufSize)
        If lResult = 0 Then
            MyString = strData
        End If
    End If
End If

'Close the key
RegCloseKey Ret

bArray = StrConv( _
    MyString, vbFromUnicode _
)

Debug.Print "Dimensione array = " & UBound(bArray) - LBound(bArray) + 1
For i = LBound(bArray) To UBound(bArray)
    Debug.Print CDec("&H" & bArray(i))
Next i

End Sub
Grazie
guldo76 è offline   Rispondi citando il messaggio o parte di esso
Old 13-10-2005, 17:28   #15
bertoz85
Bannato
 
L'Avatar di bertoz85
 
Iscritto dal: Jun 2002
Città: Nella Rossa Socialista Romagna (gambettola(fc))
Messaggi: 2066
Quote:
Originariamente inviato da guldo76
Codice:
Sub Main()

Dim MyString As String
Dim bArray() As Byte
Dim Ret

'Set the string
MyString = Space$(1024)

'Open the key
RegOpenKey HKEY_LOCAL_MACHINE, "SOFTWARE\Symantec\Norton AntiVirus\LastScan", Ret

'Get the key's content
Dim lResult As Long, lValueType As Long, strBuf As String, lDataBufSize As Long

'retrieve nformation about the key
lResult = RegQueryValueEx(Ret, "SystemTime", 0, lValueType, ByVal 0, lDataBufSize)
If lResult = 0 Then
    If lValueType = REG_BINARY Then
        Dim strData As Long ' As Integer
        'retrieve the key's value
        lResult = RegQueryValueEx(Ret, "SystemTime", 0, 0, strData, lDataBufSize)
        If lResult = 0 Then
            MyString = strData
        End If
    End If
End If

'Close the key
RegCloseKey Ret

bArray = StrConv( _
    MyString, vbFromUnicode _
)

Debug.Print "Dimensione array = " & UBound(bArray) - LBound(bArray) + 1
For i = LBound(bArray) To UBound(bArray)
    Debug.Print CDec("&H" & bArray(i))
Next i

End Sub
Sarebbe meglio usassi RegOpenKeyEx visto che la versione non-Ex è vecchia, ma non fa differenza
Poi non ho ben capito perchè dichiari strData di tipo long ... cosi son 4 byte e quando leggi dal reg i dati binari, viene fuori un numero casuale... poi facendo l'assegnazione diretta lui converte in stringa il numero e avrai una stringa tipo "489015" (ovviamete il numero non è quello). Nel tuo caso dev'essere un numero lungo 6 cifre, ed ecco perchè son 6 byte nell'array finale.
Devi farla di tipo String, devi inizializzarla ad u numer di spazi sufficientmenete grande (usa Space$(lDataBufSize)) e poi devi passarla come gia fai adesso.
Però devi modificare la dichiarazione della funzione RegQueryValueEx cosi:
al posto di "lpData As Any" metti "ByVal lpData As String"
Puoi anche togliere MyString, non serve.




Due consigli da seguire :
1) controlla nelle opzioni del vb (tools > options) e spunta la prima opzione "require variable declaration" ... questo farà si che VB metta Option Explicit come prima istruzione di ogni modulo e dovrai dichiarare esplicitamente ogni variabile. E' una questione di pulizia del codice e di prestazioni dato che le var non dichiarate vengono fatte Variant, e son lente.

2) sempre nelle opzioni, alla scheda Environment, seleziona l'opzinoe save changes in basso a sx. Questo perchè quando lavori con le API di windows e soprattuto con le stringhe e le dichiarazioni delle funzioni nelle API (o con funzioni non documentate, API oscure e potenzialmente incompatibili), c'è un grosso rischio che eseguendo il debug crashi tutto per un tuo errore (puntatori rulez) e VB viene chiuso brutalmente (è mono thread come tutto il linguaggio e ciò è uno dei due grossi svantaggi di vb!!!).
Se fai cosi ogni volta che avvii il progetto ti salva automaticamente le modifice e stai al sicuro.


ciao
bertoz85 è offline   Rispondi citando il messaggio o parte di esso
Old 13-10-2005, 17:55   #16
guldo76
Senior Member
 
L'Avatar di guldo76
 
Iscritto dal: Nov 2002
Città: Morio Cho
Messaggi: 2595
Quote:
Originariamente inviato da bertoz85
Poi non ho ben capito perchè dichiari strData di tipo long ... cosi son 4 byte e quando leggi dal reg i dati binari, viene fuori un numero casuale... poi facendo l'assegnazione diretta lui converte in stringa il numero e avrai una stringa tipo "489015" (ovviamete il numero non è quello). Nel tuo caso dev'essere un numero lungo 6 cifre, ed ecco perchè son 6 byte nell'array finale.
Devi farla di tipo String, devi inizializzarla ad u numer di spazi sufficientmenete grande (usa Space$(lDataBufSize)) e poi devi passarla come gia fai adesso.
Però devi modificare la dichiarazione della funzione RegQueryValueEx cosi:
al posto di "lpData As Any" metti "ByVal lpData As String"

Ora funziona!
Avevo anche pensato di passargli una stringa, quello che mi mancava era che dovevo (e potevo!) cambiare la dichiarazione della funzione...
GRAZIE!

Quote:
Due consigli da seguire :
1) controlla nelle opzioni del vb (tools > options)
Oh oh...
Lo farei volentieri, ma non ho nessuna voce "options" da nessuna parte... né nel menù tools né negli altri... né niente di simile, tipo "preferences"...
Hai idea del perché?!?
Nel menù tools ho tre voci:
Add procedure
Procedure attributes
Menu editor

Cmq, GRAZIE!
guldo76 è offline   Rispondi citando il messaggio o parte di esso
Old 13-10-2005, 18:15   #17
bertoz85
Bannato
 
L'Avatar di bertoz85
 
Iscritto dal: Jun 2002
Città: Nella Rossa Socialista Romagna (gambettola(fc))
Messaggi: 2066
Quote:
Originariamente inviato da guldo76
Oh oh...
Lo farei volentieri, ma non ho nessuna voce "options" da nessuna parte... né nel menù tools né negli altri... né niente di simile, tipo "preferences"...
Hai idea del perché?!?
Nel menù tools ho tre voci:
Add procedure
Procedure attributes
Menu editor

Cmq, GRAZIE!
ma che versione di vb hai?
posso chiederti a che serviva il programma ?


ciao
bertoz85 è offline   Rispondi citando il messaggio o parte di esso
Old 13-10-2005, 22:44   #18
guldo76
Senior Member
 
L'Avatar di guldo76
 
Iscritto dal: Nov 2002
Città: Morio Cho
Messaggi: 2595
E' per lavoro.
Sono costretto a usare VB6.
In realtà ho già risolto con regedit e un file temporaneo; però ero curioso di capire come funziona con le API. Immagino sia più efficiente...
guldo76 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Wind Tre 'accende' il 5G Standalone in Italia: si apre una nuova era basata sui servizi Wind Tre 'accende' il 5G Standalone in Italia: s...
OPPO Find X9 Pro: il camera phone con teleobiettivo da 200MP e batteria da 7500 mAh OPPO Find X9 Pro: il camera phone con teleobiett...
DJI Romo, il robot aspirapolvere tutto trasparente DJI Romo, il robot aspirapolvere tutto trasparen...
DJI Osmo Nano: la piccola fotocamera alla prova sul campo DJI Osmo Nano: la piccola fotocamera alla prova ...
FUJIFILM X-T30 III, la nuova mirrorless compatta FUJIFILM X-T30 III, la nuova mirrorless compatta
SpaceX risponde alla NASA sul lander lun...
Bitcoin compie 17 anni: il Whitepaper ch...
Attenzione agli HDD Western Digital Blue...
MacBook Air M4 a un super prezzo su Amaz...
Dal 12 novembre stretta sui siti porno: ...
Recensione Synology DS725+: tornano i di...
Car of the Year 2026, rivelate le 7 fina...
Il mouse diventa indossabile: Prolo Ring...
Animal Crossing: New Horizons torna in v...
Task Manager impazzito su Windows 11: in...
NZXT: il PC in abbonamento finisce in tr...
Halo 2 e 3: remake in arrivo, multiplaye...
Robot Phone e un nuovo ecosistema AI: HO...
Amazon sorprende tutti: extra 15% di sco...
HONOR 400 Lite 5G a 209,90€: smartphone ...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 16:44.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v