Il mio nuovo "Hub dei contenuti": Patreon.com – Io ci sono e tu?

Ho deciso di pubblicare un avviso per comunicare che tutta la mia produzione sarà resa disponibile principalmente (in tempo reale) nella pagina https://www.patreon.com/garage40, mentre su YouTube e altri canali il materiale sarà pubblicato ad alcune settimane di distanza… video per i dettagli.

https://www.youtube.com/watch?v=_mfRuGWL-hE

image

Books and articles in English

For at least 15 years now, I have published at least 50 articles and 16 books on technical subjects: programming, databases, electronics (with Arduino), Office and so on.
So far, I have only published in Italian, but I feel the need to expand my horizons, so I am going to do an experiment: I will try to translate some of my articles from Italian into English. I will also try to translate my next posts in this blog.
I would appreciate it if you could point out any grammatical errors (or nonsense sentences) so that I can improve my translations.
Thank you!


TRADUZIONE | Trad&Co | Elisabetta Minetto

Un po’ di somme del 2018 e buoni propositi del 2019…

Approssimandosi la fine del 2018 bisogna tirare le somme e darsi dei nuovi obiettivi. Il 2018, come gli ultimi anni, dal punto di vista di uno “scrittore tecnico” non è stato granché:

  1. rilevo sempre di più un “abbandono” dei libri cartacei, aggravato dal fatto che i prodotti software si aggiornano sempre più velocemente: quando un libro tecnico è pronto, è già vecchio perché è uscita una nuova versione (o anche “n” aggiornamenti della stessa versione)
  2. le riviste di programmazione italiane non esistono più. Regge ancora l’ambito dell’elettronica, dove riviste come “Elettronica In” lavorano ancora, ma il mio primo esperimento di articolo “misto elettronica+sviluppo in Visual Studio” è stato consegnato a fine settembre e non è ancora stato pubblicato;
  3. le applicazioni (a pagamento) dallo Store di Microsoft per Windows 10 non hanno un così grande ritorno da essere convenienti. Ho tentato anche di creare una sorta di “libro digitale” in un’applicazione MS Store per Windows 10, ma i numeri sono veramente piccoli piccoli.

Vedo però che continuo a ricevere e-mail di apprezzamento per i libri e articoli che ho scritto in passato e, spesso, anche richieste di altri articoli e libri e quindi non voglio lasciare insoddisfatte queste richieste.

Dal 1° gennaio 2019 in poi, quindi, mi preparerò per una nuova modalità di distribuzione dei miei testi (articoli e/o libri), oltre che attraverso il solito canale dei libri autoprodotti con Amazon: si tratta del canale offerto dal sito http://www.sfogliami.it: con questo sito potrò pubblicare i testi in formato digitale e questi saranno fruibili sfogliandoli direttamente sullo schermo, come uno dei tanti quotidiani e notiziari che ormai hanno scelto questa forma di pubblicazione.



Con l’acquisto di un testo offrirò anche la possibilità di scaricare il testo stesso in formato digitale, in modo da poterlo fruire in qualunque modo voi desideriate (PC, tablet, smartphone o anche cartaceo se volete stamparvelo).

Per ciascun testo (articolo o libro) fisserò un prezzo proporzionale ai contenuti (lunghezza e complessità), ma limitandolo al minimo, visto che non ci sono particolari costi da affrontare (non ci sono costi di carta, stampa, distribuzione, del revisore, del grafico, del tipografo ecc. ecc.).

Sperando di incontrare così i vostri gusti e il vostro interesse, colgo l’occasione di questo post per augurare a tutti voi


B U O N         2 0 1 9 !!!

#4 Ottenere l’indirizzo IP [== AGGIORNATO ==]

Questo era un post che avevo pubblicato in questo blog ben 10 anni fa e ora lo riprendo perché è opportuno che venga modificato qualcosa…

In particolare il metodo Dns.GetHostByName() è deprecato e quindi bisogna utilizzare un codice diverso. Quello che vi consiglio io è questo:

Private Function GetIPv4Address() As String
    GetIPv4Address = String.Empty
    Dim strHostName As String = System.Net.Dns.GetHostName()
    Dim iphe As System.Net.IPHostEntry =
  System.Net.Dns.GetHostEntry(strHostName)

    For Each ipheal As System.Net.IPAddress In iphe.AddressList
        If ipheal.AddressFamily =
  System.Net.Sockets.AddressFamily.InterNetwork Then
            GetIPv4Address = ipheal.ToString()
            If GetIPv4Address.Substring(0, 7) = "192.168" Then
                Return GetIPv4Address
            End If
        End If
    Next
End Function

Ho sperimentato vari metodi, ma l’unico che ho trovato che permetta di estrarre un indirizzo IPv4 (in particolare l’indirizzo locale 192.168.xxx.xxx) è quello di questa variante.

Se togliete il test sulla stringa “192.168 è probabile che invece vi venga presentato l’indirizzo IP che il router ADSL ha sulla rete esterna.

[VECCHIO TESTO]:

Per ottenere l’indirizzo IP della macchina (collegata in rete) sulla quale gira il programma, ecco una soluzione valida per Visual Basic 2005:

Private Shared Sub NamedSub() 
  Dim loip() As System.Net.IPAddress = _ 
    System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName) 
  Dim ip As String = loip(0).ToString 
  MessageBox.Show(ip) 
End Sub

E’ possibile ottenere altre informazioni sulla connessione di rete leggendo questo articolo pubblicato su MSDN

Il metodo usato in Visual Basic 2003 è obsoleto e da evitare:

Dim ip As String = _ 
System.Net.Dns.GetHostByName(System.Net.Dns.GetHostName) 
.AddressList(0).ToString 

N.B.: l’istruzione deve essere scritta tutta su una singola riga

#56 – [VB.NET] Verificare lo stato della coda di stampa predefinita

Se avete la necessità di verificare lo stato della coda di stampa predefinita, potete utilizzare il namespace System.Printing che trovate però solo dal Framework .NET 3.0 in poi.

Per prima cosa dovete aggiungere un riferimento a System.Printing nella scheda Riferimenti delle proprietà del progetto.

Una volta aggiunto il riferimento, utilizzate un codice simile a questo:

Imports System.Printing
Public Class Form1

   Private Sub Button1_Click(ByVal sender As System.Object, _
         ByVal e As System.EventArgs) _
         Handles Button1.Click
      Dim ps As New LocalPrintServer()
      Dim pq As PrintQueue = ps.DefaultPrintQueue
      Dim err As Boolean = pq.IsInError
      If err = True Then
         MessageBox.Show("Errore di stampante")
      Else
         MessageBox.Show("Nessun errore di stampante")
      End If

   End Sub
End Class

#55: [VB.NET] Misurare il tempo di esecuzione

…Spesso ci capita di conoscere varie tecniche per risolvere un nostro problema applicativo e/o di programmazione e non sappiamo quali di queste tecniche è più efficace dal punto di vista delle prestazioni, cioè quale impiega meno tempo a terminare l’esecuzione.

Le prestazioni di diversi algoritmi, talvolta, hanno una piccola differenza di tempo nell’esecuzione di singoli passi di programma, ma se moltiplichiamo la differenza di tempo per centinaia di migliaia di elementi da elaborare, il tempo totale diventa percepibile in modo pesante dall’utente. E’ quindi necessario sperimentare i vari algoritmi o frammenti di codice per verificare quale sia preferibile tra le varie possibilità.

Un modo semplice è quello di utilizzare un oggetto di classe TimeSpan, rilevando i “ticks” all’inizio del frammento di codice e alla fine del frammento, calcolando poi la differenza tra le due registrazioni.

I “tick” sono le più piccole unità di tempo in .NET, equivalenti a 100 nanosecondi.

Per esempio:

...

‘ prima registrazione
Dim ts1 As New TimeSpan(Now.Ticks)
‘ frammento di codice o ciclo da valutare
...
‘ registrazione finale e visualizzazione della differenza di tempo
Dim ts2 As New TimeSpan(Now.Ticks)
MessageBox.Show((ts2 - ts1).ToString)

...

In questo modo sarà possibile esaminare i tempi di diversi algoritmi ed effettuare così la scelta del migliore, nel caso preso in esame.

Attenzione: non è un metodo che permette di effettuare dei veri e propri benchmark, perché i tempi di esecuzione spesso dipendono da molti altri fattori. Per esempio servizi e programmi attivi, disponibilità di RAM nel momento dell’esecuzione, carico del processore e così via. In ogni caso, il metodo proposto è un metodo empirico sufficientemente significativo e soprattutto semplice per fare delle valutazioni “a spanne” ma con dei dati alla mano. Per un migliore risultato e una maggiore sicurezza delle misurazioni è consigliabile ripetere la misurazione più volte.

 

#47: VB.NET – ADO.NET 2.0 – Supporto a Vista 64 bit e Access 2007

Prendendo spunto da una discussione nel forum dedicato a VB & .NET (http://www.visual-basic.it/forum/thread.asp?m=163649) della Community Visual Basic Tips & Tricks (www.visual-basic.it), ma anche da un mio problema personale proprio su questo argomento, ho pensato che fosse opportuno fissare un paio di appunti e di precisazioni, in particolare sull’uso del Provider JET 4.0 per l’accesso ai database in formato Access 2007 e sul problema del sistema operativo Windows Vista a 64 bit.

Partiamo dal caso dei 64 bit. Come molti sapranno, Vista è distribuito in due edizioni: a 32 bit, che è la piattaforma che molti di noi sono abituati ad utilizzare da molto tempo, e a 64 bit. Prossimamente, le nuove versioni di Windows arriveranno esclusivamente a 64 bit e quindi ci dobbiamo abituare a convivere con questa nuova piattaforma, con le sue particolarità.

Il problema deriva dal fatto che Windows Vista a 64 bit non supporta JET 4.0, in quanto questo provider dati è fornito solo a 32 bit.

Le alternative per risolvere questo problema sono sostanzialmente due:

  • evitare di utilizzare Access e orientarsi direttamente all’uso di SQL Server Express, Compact o edizioni superiori (consigliato!);
  • compilare il progetto Visual Basic 2008 o Visual C# 2008 con il solo supporto per la piattaforma x86 (cioè a 32 bit).

Per questa seconda possibilità, dobbiamo eseguire i seguenti passi:

  1. fare click con il pulsante destro del mouse sul nome del progetto e scegliere “Proprietà”;
  2. passare alla scheda “Compilazione”;
  3. fare click sul pulsante “Opzioni di compilazione avanzate”;
  4. nella combo “CPU di destinazione” selezionare “x86”, anziché “AnyCPU”.

A questo punto potremo eseguire l’applicazione anche su Vista a 64 bit, tenendo però conto che la nostra applicazione non sarà compilata a 64 bit ma bensì a 32 bit. Questo potrebbe comportare qualche problema nel futuro, se Microsoft deciderà prima o poi di chiudere il supporto ai 32 bit sui sistemi operativi a 64 bit.

Vediamo ora come si utilizza il provider JET 4.0 per Access: in particolare le stringhe di connessione ai database Access cambiano a seconda che utilizziamo Access 2003 o Access 2007:

' Access 2003:
Dim stringaconn As String = _
    "Provider=Microsoft.JET.OLEDB.4.0;Data Source=" & _
    "c:\test\prova2.mdb"

' Access 2007:
Dim stringaconn As String = _
    "Provider=Microsoft.ACE.OLEDB.12.0;" & _
    "Data Source=c:\test\prova2.accdb;" & _
    "Persist Security Info=False;"

Per maggiori dettagli sulle stringhe di connessione di ciascun provider dati (anche non-Access), date un’occhiata al sito www.connectionstrings.com.

Scriviamo quindi il programma finale per inserire un record in una tabella Access (2003 o 2007):

  1. creiamo un nuovo progetto in Visual Basic 2008;
  2. nel form predefinito aggiungiamo due TextBox di nome txtCognome e txtNome, nonché un pulsante per eseguire il frammento di codice;
  3. inserire il seguente codice a livello di form (di nome Form1):
Imports System.Data.OleDb

Public Class Form1
   Private Sub cmdInserisci_Click(ByVal sender As System.Object, _
         ByVal e As System.EventArgs) Handles cmdInserisci.Click

      ' Access 2003:
      'Dim stringaconn As String = _
      '    "Provider=Microsoft.JET.OLEDB.4.0;Data Source=" & _
      '    "c:\test\prova2.mdb"

      ' Access 2007:
      Dim stringaconn As String = _
         "Provider=Microsoft.ACE.OLEDB.12.0;" & _
         "Data Source=c:\test\prova2.accdb;" & _
         "Persist Security Info=False;"

      Dim objconn As New OleDbConnection(stringaconn)
      objconn.Open()
      Dim stringasql As String = _
         "Insert into prova2(Cognome,Nome) " & _
         "values(@cognome, @nome)"
      Dim objcomm As New OleDbCommand(stringasql, objconn)
      objconn = New OleDbConnection(stringaconn)
      objconn.Open()
      objcomm = New OleDbCommand(stringasql, objconn)
      objcomm.Parameters.Add(New OleDbParameter("@cognome", _
         Me.txtCognome.Text))
      objcomm.Parameters.Add(New OleDbParameter("@nome", _
         Me.txtNome.Text))
      Try
         Dim righeAggiornate As Integer = objcomm.ExecuteNonQuery
         If righeAggiornate = 1 Then MessageBox.Show("tutto bene")
      Catch ex As Exception
         MessageBox.Show(ex.Message & _
            Environment.NewLine & ex.StackTrace, "Errore")
      Finally
         objconn.Close()
         Me.txtCognome.Text = ""
         Me.txtNome.Text = ""
         Me.txtCognome.Focus()
      End Try
   End Sub
End Class

Naturalmente, per utilizzare alternativamente Access 2003 o Access 2007, è sufficiente commentare/decommentare la definizione della stringa di connessione opportuna.

[VS 2008] Tabella comparativa dei prodotti

Ogni tanto leggo che qualcuno chiede di conoscere quali sono le differenze tra le varie versioni di Visual Studio 2008, dalla Express alla Team System, e quindi eccomi pronto a soddisfare ogni curiosità! 

E’ possibile scaricare da qui un file in formato Word (.docx), PDF o XPS, con tutte le differenze tra le varie versioni. Sono ben 35 pagine di tabelle! … Purtroppo tutte in inglese.

Ma non c’è problema: per chi non conosce bene l’inglese, c’è anche la pagina specifica in italiano. Unico problema che quando provate a stamparla, anche se espandete tutte le voci, vi apparirà la pagina con le voci compresse   ;-P

Del resto è inutile lamentarsi: “per ben apparire, un po’ bisogna soffrire”!    😀

#46: VB.NET – impedire lo spostamento di un form

Prendo l’occasione di una discussione intercorsa oggi nella lista/forum “dotnet” di VB T&T, tra me e Riccardo Girardi, il quale aveva la necessità di trovare il modo per bloccare la posizione di un form. La gestione dell’evento di spostamento del form stesso non andava bene, perché causava un brutto sfarfallìo (flickering).

Ho trovato nel blog di Luciano Bastianello il codice in C# con cui viene realizzata questa funzionalità e l’ho convertito in VB.NET, con una correzione da parte di Riccardo Girardi:

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
   Const WM_NCLBUTTONDOWN As Integer = 161
   Const WM_SYSCOMMAND As Integer = 274
   Const HTCAPTION As Integer = 2
   Const SC_MOVE As Integer = 61456
   If (m.Msg = WM_SYSCOMMAND) AndAlso _
         (m.WParam.ToInt32() = SC_MOVE) Then
      Return
   End If
   If (m.Msg = WM_NCLBUTTONDOWN) AndAlso _
         (m.WParam.ToInt32() = HTCAPTION) Then
      Return
   End If
   MyBase.WndProc(m)
End Sub

E’ sufficiente inserire questo codice all’interno del codice del form da bloccare e il gioco è fatto.

#45: ADO.NET Leggere la chiave del record appena inserito in SQL Server

Uno dei problemi che più frequentemente mi vengono posti riguarda la possibilità di inserire un nuovo record in una tabella e di conoscere il valore assegnato dal DBMS al campo auto incrementante.

Questo problema è solitamente risolto, peraltro in modo brillante ed elegante, con una specifica stored procedure (SP) di SQL Server. Qualcuno, però, chiede come si può fare direttamente da codice, senza “scomodare” una stored procedure.

Ad un primo esame, non abbiamo la possibilità di inserire il record e subito dopo leggere il valore del campo IDENTITY, perché nel frattempo, tra la nostra scrittura del record e la nostra lettura della chiave, qualche altro utente potrebbe aver inserito un nuovo record.

Queste due operazioni, invece, devono essere fatte in un unico blocco, cioè devono essere eseguite in un’unica transazione (principio di “atomicità” della transazione).

A questo proposito c’è una particolarità di SQL Server che possiamo utilizzare per risolvere questo problema: in T-SQL possono essere eseguite più istruzioni in sequenza, senza soluzione di continuità, semplicemente separando ciascuna istruzione con un punto e virgola (;).

In questo modo le singole istruzioni saranno eseguite una dopo l’altra senza interrompere la transazione e restituendo, così, il corretto valore della colonna IDENTITY.

Un esempio di codice di questa tecnica è il seguente:

      Dim cn As System.Data.SqlClient.SqlConnection
      Dim cnStr = "Data Source = HP\SQL2008EXPRESS;" & _
         "Initial Catalog=NOMEDATABASE;" & _
         "Password=PIPPO;" & _
         "User ID=sa;" & _
         "Persist Security Info=True"
      cn = New System.Data.SqlClient.SqlConnection(cnStr)
      cn.Open()
      Dim cmd As New System.Data.SqlClient.SqlCommand( _
         "SET NOCOUNT ON; INSERT INTO Tabella (ANAnome) " & _
         "VALUES ('De Ghetto Mario'); " & _
         "SELECT SCOPE_IDENTITY() AS ANAID;", cn)
      Dim risultato = cmd.ExecuteScalar()
      MessageBox.Show("Il nuovo ID inserito è " & risultato)
      cn.Close()
      cn = Nothing

Attenzione a impostare correttamente i parametri della stringa di connessione (nome dell’istanza, nome del database, utente e password), altrimenti non potrete collegarvi correttamente alla fonte dati.

#43: Spostare un insieme di file in una diversa cartella con VB.NET (anche con LINQ)

Per spostare un file da una cartella a un’altra, possiamo utilizzare semplicemente il metodo My.Computer.FileSystem.MoveFile.

Il problema consiste nel fatto che questo metodo non consente di utilizzare i caratteri jolly e quindi non possiamo eseguire questa istruzione:

My.Computer.FileSystem.MoveFile( _

            “C:\Test1\*.jpg”, “C:\Test2\*.jpg”)

Abbiamo quindi la necessità di recuperare prima di tutto i nomi di tutti i file che rispondono a un determinato schema come *.jpg, poi potremo spostare i file singolarmente, utilizzando un ciclo For Each:

Imports System.IO

Public Class Form1

   Private Sub Button1_Click(ByVal sender As System.Object, _

         ByVal e As System.EventArgs) Handles Button1.Click

      ‘ creazione array con elenco file *.jpg:

      Dim d As New DirectoryInfo(“C:\Test1”)

      Dim f As FileInfo() = d.GetFiles(“*.jpg”)

      ‘ ciclo di spostamento:

      For Each fNext In f

         My.Computer.FileSystem.MoveFile( _

            “C:\Test1\” & fNext.Name, _

            “C:\Test2\” & fNext.Name)

      Next

   End Sub

End Class

Da qui possiamo poi creare una procedura riutilizzabile più volte, inserendola in un modulo di codice:

Imports System.IO

Module Utility

   Public Sub spostaGruppoFile(ByVal nomeFile As String, _

         ByVal dir1 As String, ByVal dir2 As String)

      ‘ creazione array con elenco file *.jpg:

      Dim d As New DirectoryInfo(dir1)

      Dim f As FileInfo() = d.GetFiles(nomeFile)

      ‘ ciclo di spostamento:

      For Each fNext In f

         My.Computer.FileSystem.MoveFile( _

            dir1 & fNext.Name, _

            dir2 & fNext.Name)

      Next

   End Sub

End Module

Tale procedura può essere chiamata semplicemente come segue, passando il nome del file o lo schema (con i caratteri jolly), la cartella di origine e la cartella di destinazione:

spostaGruppoFile(“*.jpg”, “C:\Test1\”, “C:\Test2\”)

Ovviamente è possibile passare una qualsiasi parte del nome dei file che vogliamo selezionare, non solo l’estensione. Per esempio:

 

Imports System.IO

Module Utility

   Public Sub spostaGruppoFile(ByVal nomeFile As String, _

         ByVal dir1 As String, ByVal dir2 As String)

      ‘ creazione array con elenco file:

      Dim d As New DirectoryInfo(dir1)

      Dim f = From elenco In d.GetFiles(nomeFile) _

              Select elenco.Name

      ‘ ciclo di spostamento:

      For Each fNext In f

         My.Computer.FileSystem.MoveFile( _

             dir1 & fNext, _

             dir2 & fNext)

      Next

   End Sub

End Module

 

 

#42: Abbreviare la dimensione di un file con VB.NET

Come tutti i programmatori sanno, in informatica vengono utilizzate delle abbreviazioni per indicare l’unità di misura per la dimensione di un file, della RAM o di un hard disk: per esempio un file di 1.024 byte equivale a un file di 1 “kB”.

Le abbreviazioni utilizzate attualmente sono le seguenti:

  • kiloByte –> kB –> 1.024 (circa 10^3)
  • MegaByte –> MB –> 1.048.576 (circa 10^6)
  • GigaByte –> GB –> 1.073.741.824 (circa 10^9)
  • TeraByte –> TB –> 1.099.511.627.776 (circa 10^12)
  • PetaByte –> PB –> 1.125.899.906.842.620 (circa 10^15)
  • ExaByte –> EB –> 1.152.921.504.606.850.000 ( circa 10^18 )
  • ZettaByte –> ZB –> 1,180.591.620.717.41E+21 (circa 10^21)
  • YottaByte –> YB –> 1,208.925.819.614.63E+24 (circa 10^24)

Per noi programmatori potrebbe quindi essere utile avere una funzione in grado di abbreviare un numero molto grande, così da avere una rappresentazione molto più compatta. Il seguente codice fa proprio questo:

Module Module1

   Public Function ConvertiByte( _

         ByVal strNumero As String) As String

      Dim risultato As String

      Dim potenza As Integer = 0

      Dim nByte As Decimal = 0

      ‘ verifico se è stato passato un parametro:

      ‘ se si, lo converto nel tipo Decimal

      ‘ se no, esco

      ‘TODO: aggiungere verifica se è un numero valido!

      If strNumero <> “” Then

         Try

            nByte = CType(strNumero, Decimal)

         Catch ex As Exception

            Return “Numero troppo grande: Overflow”

         End Try

      Else

         Return “Errore: nessun numero da valutare”

      End If

      ‘ ciclo di riduzione del numero, estraendo

      ‘ il numero di iterazioni effettuate

      Do While ((nByte / 1000) >= 1)

         nByte = nByte / 1024

         potenza += 1

      Loop

      ‘ conversione in stringa con arrotondamento

      risultato = Decimal.Round(nByte, 2).ToString

      ‘ aggiunta della giusta unità di misura

      Select Case potenza

         Case 0

            risultato &= ” byte”

         Case 1

            risultato &= ” KB”

         Case 2

            risultato &= ” MB”

         Case 3

            risultato &= ” GB”

         Case 4

            risultato &= ” TB”

         Case 5

            risultato &= ” PB”

         Case 6

            risultato &= ” EB”

         Case 7

            risultato &= ” ZB”

         Case 8

            risultato &= ” YB”

         Case Else

            risultato = “Non valutabile”

      End Select

      Return risultato

   End Function

End Module

A questo punto basta creare un form, aggiungere una casella di testo e un pulsante. Il codice per gestire l’evento Click del pulsante è il seguente:

Public Class Form1

   Private Sub Button1_Click(ByVal sender As System.Object, _

         ByVal e As System.EventArgs) Handles Button1.Click

      MessageBox.Show(ConvertiByte(Me.TextBox1.Text))

   End Sub

End Class

Semplice vero? Ma proviamo a migliorare un po’ la nostra funzione. E’ sufficiente sostituire tutto il codice seguente al commento “aggiunta della giusta unità di misura”:

      ‘ aggiunta della giusta unità di misura

      Dim misure() As String = _

         {“byte”, “KB”, “MB”, “GB”, “TB”, “PB”, “EB”, “ZB”, “YB”}

      If potenza > 8 Then

         risultato &= ” Non valutabile”

      Else

         risultato &= ” “ & misure(potenza)

      End If

      Return risultato

Con una semplice modifica, poi, possiamo fare in modo che la nostra funzione rappresenti un’abbreviazione di potenze di 10^3. Per esempio (i punti di separazione delle migliaia sono inseriti solo per chiarezza visiva):

– 1.000 –> 1 x 10^3
– 1.000.000 –> 1 x 10^6
– 55.555.555.555 –> 55,56 x 10^9

Ecco quindi la nostra funzione modificata:

Module Module1

   Public Function ConvertiByte( _

         ByVal strNumero As String) As String

      Dim risultato As String

      Dim potenza As Integer = 0

      Dim nByte As Decimal = 0

      ‘ verifico se è stato passato un parametro:

      ‘ se si, lo converto nel tipo Decimal

      ‘ se no, esco

      ‘TODO: aggiungere verifica se è un numero valido!

      If strNumero <> “” Then

         Try

            nByte = CType(strNumero, Decimal)

         Catch ex As Exception

            Return “Numero troppo grande: Overflow”

         End Try

      Else

         Return “Errore: nessun numero da valutare”

      End If

      ‘ ciclo di riduzione del numero, estraendo

      ‘ il numero di iterazioni effettuate

      Do While ((nByte / 1000) >= 1)

         nByte = nByte / 1000

         potenza += 1

      Loop

      ‘ conversione in stringa con arrotondamento

      risultato = Decimal.Round(nByte, 2).ToString

      ‘ aggiunta della giusta unità di misura

      risultato &= ” x 10^” & (potenza * 3).ToString

      Return risultato

   End Function

End Module

Come potete vedere, le uniche differenze sono date dal diverso divisore (1000 anziché 1024) e nella parte finale, dove viene composta la stringa che viene restituita dalla funzione al codice chiamante.

Una precisazione, prima che qualcuno possa pensare che si tratti di un errore. Il seguente codice:

      Do While ((nByte / 1000) >= 1)

         nByte = nByte / 1024

         potenza += 1

      Loop

potrebbe apparire strano o perfino sbagliato. Perché confronto la divisione per 1000 e poi divido per 1024?

E’ molto semplice: nel caso in cui, per esempio, volessi abbreviare 1000 byte, con il confronto per 1024 otterrei la non esecuzione dell’abbreviazione e quindi il risultato sarebbe “1000 byte” anziché “0,98 KB”. Di solito è abbastanza brutto veder superare il valore di 1000 in questi casi e quindi si preferisce comunque arrivare al massimo a 999 (confrontate per esempio con la visualizzazione dell’Esplora Risorse di Windows).

Una curiosità: notate come sia possibile, in VB.NET, scrivere una cosa del genere:

(potenza * 3).ToString

senza dover memorizzare il calcolo matematico in una variabile.

C’è ancora qualcuno che non è convinto a passare a VB.NET?   🙂

#41: Scaricare il contenuto HTML di una pagina web con VB.NET

Nel precedente post abbiamo visto come è possibile estrarre il testo semplice da una pagina HTML registrata sul disco fisso. In questo post, invece, vedremo come è possibile scaricare il contenuto HTML di una pagina web, fornendo semplicemente l’URL, e come da questa è possibile estrarre il testo semplice.

Procediamo per gradi: innanzi tutto creiamo una nostra classe (ScaricaURL) per gestire la comunicazione con il web server.

Imports System.Text

Imports System.IO

Imports System.Net

Public Class ScaricaURL

   Private m_strURL As String

   Public Sub SetURL(ByVal strURL As String)

      m_strURL = strURL

   End Sub

   Public Function Scarica() As String

      Dim wreq As WebRequest = WebRequest.Create(m_strURL)

      Dim wres As WebResponse = wreq.GetResponse()

      Dim iBuffer As Integer = 0

      Dim buffer( 128 ) As [Byte]

      Dim stream As Stream = wres.GetResponseStream()

      iBuffer = stream.Read(buffer, 0, 128 )

      Dim strRes As New StringBuilder(“”)

      While iBuffer <> 0

         strRes.Append(Encoding.ASCII.GetString(buffer, 0, iBuffer))

         iBuffer = stream.Read(buffer, 0, 128 )

      End While

      Return strRes.ToString()

   End Function

End Class

Successivamente inseriamo in un form: due pulsanti (Button1 e Button2) e un textbox (TextBox1). Quest’ultimo dovrà essere configurato come nel post precedente: proprietà Multiline a True e Scrollbar verticale.

Il codice dei gestori degli eventi Click dei due pulsanti sono i seguenti:

Public Class Form1

   Private Sub Button1_Click(ByVal sender As System.Object, _
         ByVal e As System.EventArgs) Handles Button1.Click

      Dim URL As String

      URL = “http://community.visual-basic.it/mario/&#8221; & _
         “archive/2008/06/29/23164.aspx”

      Dim objScaricaURL As New ScaricaURL

      objScaricaURL.SetURL(URL)

      Me.TextBox1.Text = objScaricaURL.Scarica

   End Sub

   Private Sub Button2_Click(ByVal sender As System.Object, _
         ByVal e As System.EventArgs) Handles Button2.Click

      Dim URL As String

      URL = “http://community.visual-basic.it/mario/&#8221; & _
         “archive/2008/06/29/23164.aspx”

      Dim objScaricaURL As New ScaricaURL

      objScaricaURL.SetURL(URL)

      Me.TextBox1.Text = _
         System.Text.RegularExpressions.Regex.Replace( _
         objScaricaURL.Scarica, “<[^>]*>”, “”)

   End Sub

End Class

Vedrete quindi che premendo il primo pulsante il programma scaricherà la pagina e visualizzerà il relativo codice HTML, mentre nel secondo caso scaricherà la pagina ed estrarrà solamente il testo semplice, eliminando tutti i tag HTML.

#40: Estrarre il testo da una pagina HTML con VB.NET

Le espressioni regolari sono uno strumento estremamente potente per estrarre del testo da una pagina HTML registrata su disco.

Una delle cose più interessanti è il fatto che possiamo raggiungere questo obiettivo con una sola riga di codice!

Ecco qui la nostra funzione:

Public Function EstraiTestoDaHTML(ByVal HTML As String) As String

   ‘ rimuove i tag HTML

   Return System.Text.RegularExpressions.Regex.Replace( _

      HTML, “<[^>]*>”, “”)

End Function

 

… ed ecco il codice, inserito nel gestore dell’evento Click di un pulsante:

Dim testoHTML As String

testoHTML = My.Computer.FileSystem.ReadAllText(“C:\paginaX.html”)

Me.TextBox1.Text = EstraiTestoDaHTML(testoHTML)

 

A questo punto basta inserire una casella di testo di nome TextBox1, impostare la sua proprietà Multiline a True e definire la scrollbar verticale e il gioco è fatto!

 

#39: Aggiungere un collegamento ai Preferiti con VB.NET

Tempo addietro ho avuto la necessità di creare un piccolo programma per aggiungere un collegamento ai Preferiti, per permettere a un numero consistente di utenti dell’azienda dove lavoro di collegarsi a un nostro sito interno, nella Intranet aziendale.

Il programma è estremamente semplice, come si può vedere dal seguente codice:

Public Class Form1

   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

      CreaShortcut(“Prova”, http://www.visual-basic.it&#8221;)

   End Sub

 

   Public Sub CreaShortcut(ByVal Titolo As String, ByVal URL As String)

      ‘ crea uno shortcut nella cartella Preferiti

      Dim strCartellaPreferiti As String

      ‘ recupera la cartella Preferiti

      strCartellaPreferiti = System.Environment.GetFolderPath( _

         Environment.SpecialFolder.Favorites)

      ‘ crea uno shortcut basato su Titolo

      Dim objSW As System.IO.StreamWriter = _

         System.IO.File.CreateText(strCartellaPreferiti & _

         “\” & Titolo & “.url”)

      ‘ scrive l’URL nel file

      objSW.WriteLine(“[InternetShortcut]”)

      objSW.WriteLine(“URL=” & URL)

      ‘ chiude il file

      objSW.Close()

   End Sub

End Class


 

Nel form ho inserito un pulsante che semplicemente richiama la Sub CreaShortcut, passandogli il titolo del collegamento e l’indirizzo (URL) del collegamento vero e proprio.

Nella Sub CreaShortcut, invece, viene prima di tutto recuperato il percorso della cartella speciale dei Preferiti, poi viene aperto uno stream per la scrittura del file, all’interno del quale vengono inserite due righe di testo: la prima con un “tag” speciale che specifica che il file costituisce una “scorciatoia” a un indirizzo internet e la seconda con l’URL vero e proprio. Infine il file viene correttamente chiuso.

N.B.: questo mio post fa parte di alcuni suggerimenti di programmazione per i quali traggo ispirazione, spesso, da richieste che vedo nelle liste VB T&T oppure in giro per la Rete. Spero che vi possano interessare…   🙂

#38: spostare un file nel Cestino con VB.NET

Per permettere agli utenti dei vostri programmi di spostare un file nel Cestino di Windows (alias “Recycle Bin”) dobbiamo utilizzare una funzione della libreria di sistema shell32.dll.

Per rendere più semplici le cose, potete utilizzare il seguente modulo di codice:

Imports System.IO

Module SpostaFileCestino

    Private Structure ShFileOpStruct

        Dim hwnd As Integer

        Dim wFunc As Integer

        Dim pFrom As String

        Dim pTo As String

        Dim fFlags As Short

        Dim fAnyOperationAborted As Boolean

        Dim hNameMappings As Integer

        Dim lpszProgressTitle As String

    End Structure

 

    Private Const SFC_DELETE As Short = &H3S

    Private Const SFC_ALLOWUNDO As Short = &H40S

    Private Const SFC_NOCONFIRMATION As Short = &H10S

 

    Private Declare Function ShFileOperation _

        Lib “shell32.dll” _

        Alias “SHFileOperationA” _

        (ByRef lpFileOp As ShFileOpStruct) As Integer

 

    Public Function Ricicla(ByRef sPath As String) As Integer

        Dim FileOp As ShFileOpStruct

        If Not File.Exists(sPath) Then

            MessageBox.Show(“File “ & sPath & ” non trovato.”)

            Return -1

            Exit Function

        End If

        With FileOp

            .wFunc = SFC_DELETE

            .pFrom = sPath & vbNullChar

            .pTo = vbNullChar

            .fFlags = SFC_NOCONFIRMATION Or SFC_ALLOWUNDO

            .lpszProgressTitle = “Invio file “ & _

                sPath & ” al Cestino di Windows.”

        End With

        Try

            ShFileOperation(FileOp)

        Catch ex As Exception

            MessageBox.Show(ex.Message)

        End Try

        Return 0

    End Function

End Module 

 

 

Infine, per utilizzare effettivamente la funzione Ricicla potete fare riferimento al seguente esempio:

Dim esito As Integer = 0

esito = Ricicla(“C:\prova.txt”)

If esito = -1 Then

   MessageBox.Show(“Errore: operazione annullata!”)

Else

   MessageBox.Show(“Spostamento nel Cestino “ & _

      “eseguito correttamente.”)

End If

 

 

 

L’utilizzo non richiede ulteriori commenti, dato che è sufficiente passare alla funzione Ricicla il nome del file completo del percorso.

#37: Trucco per commentare blocchi di codice con VB.NET

Come è noto a tutti i programmatori Visual Basic, con questo linguaggio non è possibile commentare blocchi di codice o di testo e ci si deve rassegnare a commentare riga per riga con l’apice singolo (‘). I programmatori C#, C++ e JAVA, invece, hanno una sintassi specifica estremamente comoda che si presenta così:

/*
   Qui posso scrivere quello che voglio
   senza nessun problema!!
*/

Con il seguente trucco, però, possiamo simulare la stessa situazione di cui sopra: è sufficiente utilizzare la direttiva #If … #End If.

Create una nuova applicazione Windows Forms (linguaggio Visual Basic) e aggiungete un pulsante nel form principale. Sostituite poi il codice sottostante con il seguente:

Public Class Form1
   Private Sub Button1_Click( _
       
ByVal sender As System.Object, _
         ByVal e As System.EventArgs) _
         Handles Button1.Click
      MessageBox.Show(“Trucco per ” & _
         “
commentare blocchi di codice…”)

#If False Then
   MessageBox.Show(“Questo non dovrebbe apparire…”)
   Posso scrivere qualsiasi cosa!
#End If

      MessageBox.Show(“Fine trucco!”)
   End Sub
End Class

Eseguendo il programma, vedrete apparire il primo messaggio (“Trucco per…”) e poi l’ultimo messaggio (“Fine trucco!”), mentre tutto ciò che è stato inserito nel blocco #If … #End If è totalmente ignorato, sia che si tratti di un’istruzione valida, sia che si tratti di puro testo.

Certo, non è così ordinato e intuitivo come la coppia /* … */ di C#, ma è utile per commentare velocemente parti di codice che vogliamo temporaneamente disattivare o per inserire lunghi commenti descrittivi.

Come funziona? Il blocco #If … #End If è tecnicamente una direttiva per il compilatore: quest’ultimo, trovando #If, eseguirà il test indicato subito dopo. Se il test risulterà negativo (False), come nel caso sopra illustrato, ignorerà tutto ciò che troverà successivamente fino a #End If, se invece risulterà positivo (True), eseguirà il codice contenuto al suo interno.

Uno degli usi più importanti di questa direttiva è, oltre tutto, eseguire del codice condizionale a seconda che ci si trovi in modalità di DEBUG o in modalità RELEASE.

#36: Calcolare il tempo di esecuzione di un frammento di codice (VB.NET)

Sviluppando o studiando una nuova tecnica, in un qualsiasi linguaggio di programmazione, spesso abbiamo bisogno di avere una valutazione oggettiva del tempo di esecuzione di più frammenti di codice, per poter valutare quale dei due impiega meno tempo. Infatti il minore tempo di esecuzione di certe parti di codice, specialmente quelle ripetute più volte nel corso del programma o utilizzate in più parti del programma stesso, ha per conseguenza un minore tempo di esecuzione dell’intero programma e quindi migliori prestazioni che vengono percepite positivamente dall’utente.

In questo post vedremo quindi come si crea e come si utilizza una classe in grado di memorizzare il momento iniziale di un test e la differenza tra un momento successivo e il momento iniziale.

La classe è la seguente:
 

Public Class Cronometro

   Private inizio As DateTime

   Private durata As TimeSpan

   Public Sub New()

      inizio = New DateTime

      durata = New TimeSpan

   End Sub

   Public Sub ferma()

      durata = CType(DateTime.Now.Subtract(inizio), TimeSpan)

   End Sub

   Public Sub avvia()

      GC.Collect()

      GC.WaitForPendingFinalizers()

      inizio = DateTime.Now

   End Sub

   Public ReadOnly Property Result() As TimeSpan

      Get

         Return durata

      End Get

   End Property

End Class

 

Le istruzioni GC.Collect() e GC.WaitForPendingFinalizers() servono per avviare la “raccolta della spazzatura” da parte del Garbage Collector, cioè l’eliminazione degli oggetti non più utilizzati. Infatti, come sappiamo, gli oggetti non vengono eliminati immediatamente al termine del loro utilizzo, ma rimangono in memoria finché il Garbage Collector non decide di eliminarli. In particolare la seconda istruzione (GC.WaitForPendingFinalizers) attende che siano terminati tutti i metodi Finalizer degli oggetti in corso di eliminazione.

Perché avviare esplicitamente il Garbage Collector? E’ presto detto: vogliamo che nel corso del nostro test non avvenga la “raccolta dei rifiuti” che rallenterebbe l’esecuzione e causerebbe l’invalidazione del test stesso.

In un’applicazione Console possiamo poi testare la classe Cronometro con questo codice:

Option Strict On

Imports System.Console

Module Module1

   Sub Main()

      Dim numeri(99999) As Integer

      BuildArray(numeri)

      Dim tObj As New Cronometro()

      tObj.avvia()

      ScriviNumeri(numeri)

      tObj.ferma()

      Console.WriteLine(“tempo in secondi: “ & _

         tObj.Result.TotalSeconds)

      Console.Read()

   End Sub

   Sub BuildArray(ByVal arr() As Integer)

      Dim indice As Integer

      For indice = 0 To 99999

         arr(indice) = indice

      Next

   End Sub

   Sub ScriviNumeri(ByVal arr() As Integer)

      Dim indice As Integer

      For indice = 0 To arr.GetUpperBound(0)

         Console.Write(arr(indice) & ” “)

      Next

   End Sub

End Module

 

Quella che abbiamo visto è la soluzione “classica” che viene spesso utilizzata e che, peraltro, va bene con qualsiasi linguaggio OOP (anche quelli non-.NET, fatti gli opportuni adattamenti).

E’ possibile ottenere una soluzione più ordinata e pulita utilizzando la classe System.Diagnostics.Stopwatch, implementata in tutti i Framework .NET dalla versione 2.0 in poi. Per esempio questo è il codice di un’applicazione Console che fa uso di tale classe:

Public Class Test

    Shared Sub main()

        Dim str As String = “”

        Dim watch As New System.Diagnostics.Stopwatch()

        watch.Start()     ‘ avvio del cronometro

        ‘ … fai qualcosa …

        Dim i As Integer = 0

        For i = 1 To 100

            str &= “*”

            Console.WriteLine(“<“ & str & “>”)

        Next

        watch.Stop()    ‘ stop del cronometro

        Console.WriteLine(“Tempo impiegato: “ + watch.Elapsed.ToString())

        Console.ReadLine()

    End Sub

End Class

 

Attenzione che il test può non funzionare perfettamente in tutti i casi: se il nostro computer è pieno di programmi e servizi in esecuzione, potremmo ottenere dei risultati non corretti. In particolare, quando dobbiamo confrontare i tempi di due versioni di codice diverse (per esempio due algoritmi di ordinamento diversi), lo stato del computer dovrebbe essere il più possibile uguale in entrambe le esecuzioni, altrimenti si rischia di falsare i risultati.

Il consiglio è sempre quello, se possibile, di utilizzare un’installazione “pulita”, con solo i programmi e i servizi indispensabili per l’esecuzione del programma e del relativo test.

 

#35: Cancellare la lista dei progetti

Sono molti i programmatori che sentono la mancanza di un metodo per cancellare la lista (o una parte della lista) dei progetti nell’ambiente di sviluppo.

L’unico modo per farlo è quello di intervenire a livello di registro di sistema, eliminando le chiavi contenute nelle seguenti voci di registro:

Visual Studio 2008 Professional:

HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\ProjectMRUList

Visual Basic 2008 Express:

HKEY_CURRENT_USER\Software\Microsoft\VBExpress\9.0\ProjectMRUList

Visual Web Developer 2008 Express:

HKEY_CURRENT_USER\Software\Microsoft\VWDExpress\9.0\ProjectMRUList

Visual C# 2008 Express:

HKEY_CURRENT_USER\Software\Microsoft\VCSExpress\9.0\FileMRUList

NOTA – attenzione alle modifiche che apportate al registro di sistema: basta molto poco per danneggiare l’installazione di Windows!

*** AGGIORNAMENTO ***

Su questo argomento si sono “sbizzarriti” anche, dapprima, Alessandro Del Sole che ha pubblicato nel suo blog l’annuncio di un add-in creato da lui stesso e pubblicato su Code Gallery di MSDN, poi Diego Cattaruzza che ha pubblicato nel suo blog l’annuncio di un “non-add-in” per le versioni Express.

In conclusione, ora avete anche degli strumenti più “user-friendly” per eliminare la lista dei progetti anche senza rischiare di maneggiare maldestramente il registro di sistema!

#34: Problema di duplicazione menu con IDE di VS 2008 Pro

A ogni avvio, VS 2008 Professional (Trial) aveva iniziato a segnalare l’impossibilità di caricare alcuni pacchetti (add-in o altri) e per ognuno consigliava di digitare “devenv /ResetSkipPkgs” da riga di comando per risolvere il problema.
Oggi ho eseguito tale comando e il risultato è che… i menu si sono duplicati al loro interno e quadruplicati nel loro insieme! In pratica questo è il menu principale risultante:

File File Modifica Modifica Visualizza Visualizza Strumenti Strumenti Test Test Finestra Finestra ? ? File File Modifica Modifica Visualizza Visualizza Strumenti Strumenti Test Test Finestra Finestra ? ? File File Modifica Modifica Visualizza Visualizza Strumenti Strumenti Test Test Finestra Finestra ? ? File File Modifica Modifica Visualizza Visualizza Strumenti Strumenti Test Test Finestra Finestra ? ?

E’ vero che le voci sono ugualmente accessibili, ma è anche vero che è abbastanza fastidioso, oltre al fatto che occupa spazio prezioso.

Ho provato a reinstallare con il CD di setup utilizzando l’opzione “ripara” e fortunatamente ha funzionato.

Mi piacerebbe proprio sapere il motivo per cui quel comando ha dato un esito così infausto…

 

#33: Creare un GUID con Visual Studio 2008

Questa tip è un po’ diversa dal solito perché non presenta codice, ma mostra una funzionalità dell’IDE di Visual Studio 2008 Professional.

Infatti l’IDE di Visual Studio 2008 Professional offre la possibilità di creare automaticamente un GUID, cioè un Globally Unique Identifier, adatto anche all’uso nel registro di sistema. Alcuni esempi di GUID sono i seguenti:

{8ED66C10-25DC-4d49-9A7B-17E400202B81}
{B359036E-53BD-492f-AE3C-28D8771759A0}
{D310A47C-E9CD-48db-86B0-88439C7E5344}

La funzione per creare il GUID la trovate nel menu Strumenti > Crea GUID: scegliendo il formato “Registry format” otterrete proprio una stringa simile a quelle mostrate qui sopra. Se poi ne volete creare più di una, è sufficiente premere più volte il pulsante “New GUID” e naturalmente copiare ciascun GUID con il pulsante “Copy” (la copia avviene negli appunti di Windows, quindi bisogna poi “riversare” il codice GUID con CTRL+V da qualche altra parte).

#32: Elencare hard disk con spazio libero disponibile

In realtà la tip che presento oggi elenca gli hard disk ma anche gli eventuali dischi di altro tipo che dovessero essere disponibili nel sistema. Dato che alcune unità possono essere al momento prive di disco (es. l’unità per floppy disk A:, unità con disco removibile, lettori CD/DVD ecc.), è necessario gestire l’eccezione che interromperebbe l’esecuzione del programma.

Per provare questa tip è sufficiente creare un form, aggiungere un pulsante e una TextBox, impostare quest’ultima a “MultiLine” e inserire il seguente codice:

Public Class Form1
   Private Sub Button1_Click(ByVal sender As System.Object, _
        
ByVal e As System.EventArgs) Handles Button1.Click
      Dim driveInfo As System.IO.DriveInfo() = _
         System.IO.DriveInfo.GetDrives()
      For Each d As System.IO.DriveInfo In driveInfo
         Try
            TextBox1.Text += “Drive: “ + d.Name.ToString _
               + System.Environment.NewLine +
“Size: “ _
               + d.TotalSize.ToString + System.Environment.NewLine _

               + “Free Space: “ + d.TotalFreeSpace.ToString _
               + System.Environment.NewLine + System.Environment.NewLine
         Catch ex As Exception
            ‘ ignora gli errori dovuti a dischi “non hard disk”
            ‘ es. A:\ oppure lettori CD/DVD e unità non pronte
            ‘ (senza disco)
         End Try
      Next
   End Sub
End Class 

 

Ecco un esempio del risultato che possiamo ottenere:

Esempio tip #32

 

#31: Aprire file XLS e creare un file CSV

Talvolta è necessario esportare i dati di un foglio Excel in un file di tipo testo con Campi Separati da Virgola (CSV) o, meglio, da punto e virgola.

Per ottenere questo risultato possiamo creare un nuovo progetto, inserire tra i riferimenti nelle proprietà del progetto la libreria Microsoft.Office.Interop.Excel, aggiungere un pulsante al form e, all’interno del suo evento Click, il codice seguente:

Imports Microsoft.Office.Interop.Excel
Public Class Form1
   Private Sub Button1_Click(ByVal sender As System.Object, _
         ByVal e As System.EventArgs) Handles Button1.Click
      Dim appExcel As Application = New Application
      Dim cartella As Workbook = _
         CType(appExcel.Workbooks.Open(“C:\ExcelVsCSV\Dati.xls”), Workbook)
      cartella.SaveAs(“C:\ExcelVsCSV\Dati.csv”, XlFileFormat.xlCSV, _
         CreateBackup:=False)
      With appExcel
         .DisplayAlerts = False
         .Quit()
      End With
   End Sub
End Class 

Provando l’esempio dopo aver creato il foglio Excel di nome Dati.xls (con qualsiasi dato in forma tabellare, comprese le intestazioni dei campi) nella cartella C:\ExcelVsCSV\, vedrete che verrà creato un file Dati.csv nella stessa cartella, con i dati separati da punto e virgola.

#30: Conteggio record con ADO.NET

L’articolo http://support.microsoft.com/kb/308050/en-us spiega che non è possibile conoscere in anticipo il numero di record restituiti dalla query con un DataReader, perché per conoscere il numero di
record è necessario spostarsi all’ultimo record. In quest’altro articolo viene sostanzialmente spiegata la stessa cosa: http://www.velocityreviews.com/forums/t112093-datareader-and-recordcount.html.

Per risolvere questo problema è possibile eseguire un conteggio PRIMA di aprire il DataReader, con istruzioni simili alle seguenti:

VB:

Dim cmd As SqlCommand = _
   New SqlCommand("SELECT COUNT(*) FROM Clienti;", conn)
Dim numeroClienti As Integer = CInt(cmd.ExecuteScalar())

C#:

SqlCommand cmd = _
   new SqlCommand("SELECT Count(*) FROM Clienti", conn);
Int32 count = (Int32)cmd.ExecuteScalar;

#28: Progetti “usa e getta” in Visual Studio 2008

Specialmente quando studiamo una nuova tecnologia o una nuova tecnica di programmazione, in Visual Basic o in C#, può esserci utile evitare di salvare il progetto.

Infatti quello che vorremmo fare, dato che siamo persone ordinate (!), è semplicemente aprire un nuovo progetto senza salvarlo alla creazione, provare il codice e poi chiudere il progetto eliminando ogni sua traccia. In questo modo possiamo evitare di avere l’hard disk pieno di progetti di prova che provocano solo una grande confusione.

Possiamo realizzare tutto questo semplicemente modificando un’opzione di Visual Studio 2008, di Visual Basic 2008 Express o di Visual C# 2008 Express:

  1. selezionate il menu Strumenti > Opzioni > Progetti e soluzioni > Generale (nella versione inglese: Tools > Options > Projects and Solutions > General);
  2. nella scheda che apparirà, esiste una casella di controllo con la voce “Salva nuovi progetti alla creazione” (in inglese “Save new projects when created”): togliendo la spunta potremo disattivare la richiesta di salvataggio del progetto al momento della creazione!

#27: Conversione di una data da formato stringa a DateTime

Per convertire una stringa in formato “gg/mm/aaaa” in un oggetto di tipo DateTime, è possibile utilizzare la seguente funzione:

Private Function ToDateTime(ByVal _ 
      dataGG_MM_AAAA  As String) As DateTime 
   Dim myCultureInfo As New _ 
      System.Globalization.CultureInfo("it-IT", _ 
      True) 
   Dim formato As String = "dd/MM/yyyy" 
   Return _ 
     System.DateTime.ParseExact(dataGG_MM_AAAA, _ 
        formato, myCultureInfo) 
End Function

Per testare questa funzione, invece, potete provare il seguente codice:

Private Sub Form1_Load(ByVal sender _ 
      As System.Object, _ 
      ByVal e As System.EventArgs) _ 
      Handles MyBase.Load 
    Dim dataStringa As String 
    Dim data As Date 
    dataStringa = "01/03/2008" 
    data = ToDateTime(dataStringa) 
    MessageBox.Show(Month(data))  ' <-- visualizza "3" 
End Sub 

#26: VB 2008 e LINQ to Objects

LINQ to Objects permette di eseguire interrogazioni su oggetti presenti in memoria.

Questa tecnica può essere applicata anche a un array, come possiamo vedere dal seguente esempio:

Public Class Form1 
    Private Sub Button1_Click(ByVal sender _ 
          As System.Object, _ 
          ByVal e As System.EventArgs) _ 
          Handles Button1.Click 
        ' variabili per composizione
        ' del messaggio finale: 
        Dim messaggio As String = "" 
        Dim NL As String = Environment.NewLine 
        ' dichiarazione array: 
        Dim frutti() As String = _ 
           {"mela", "pera", "banana", "mandarino"} 
        ' dichiarazione della variabile che conterrà
        ' l'insieme delle stringhe restituite dalla
        ' query. La query è dichiarata nella stessa
        ' istruzione: 
        Dim fruttiPreferiti = _ 
           From f In frutti _ 
           Where f.StartsWith("m") _ 
           Select f 
        ' scorrimento dell'insieme delle stringhe
        ' per la composizione del messaggio: 
        For Each frutto In fruttiPreferiti 
            messaggio &= "Frutto: " & frutto & NL 
        Next 
        MessageBox.Show(messaggio) 
    End Sub 
End Class

Le stringhe restituite dalla query sono “mela” e “mandarino”.

#25: Conversione di data e ora in stringa

Per convertire un dato di tipo DateTime in stringa formattata, possiamo utilizzare una delle forme del metodo ToString. Il seguente esempio mostra come è possibile ricavare la data e ora corrente, solo la data corrente e solo l’ora corrente:

Dim dt As DateTime
dt = DateTime.Now
‘ data e ora:
Dim dataOra As String = dt.ToString
‘ solo data in formato GG/MM/AAAA:
Dim data As String = dt.ToString(“dd/MM/yyyy”)
‘ solo ora in formato HH.MM.SS (ore da 0 a 23):
Dim ora As String = dt.ToString(“T”)
‘ stampa i tre valori:
Dim s As String = dataOra & Environment.NewLine & _
    data & Environment.NewLine & ora
MessageBox.Show(s)

Il risultato sarà simile al seguente:

27/02/2008 20.36.23
27/02/2008
20.36.23