Thursday, August 26, 2010

Riporto uno scritto di Baricco apparso su Repubblica il 26/08/2010
http://www.repubblica.it/spettacoli-e-cultura/2010/08/26/news/barbari_2026-6516602/?rss

Il capovolgimento dei concetti di profondità-superficialità mi pare estremamente attuale, se non addirittura urgente.

2026, la vittoria dei barbari
Uno scrittore viaggia nel futuro, alla scoperta di un'èra dominata dalla superficialità. Con una sorpresa: non sarà poi così male
di ALESSANDRO BARICCO

2026, la vittoria dei barbari

Ci crediate o no, questo articolo l'ho scritto nel luglio 2026, cioè fra sedici anni. Diciamo che mi son portato un po' avanti col lavoro. Prendetela così.
Ecco l'articolo.
Alle volte si scrivono libri che sono come duelli: finita la sparatoria guardi chi è rimasto in piedi, e se non sei tu, hai perso. Quando ho scritto I barbari, venti anni fa, poi mi son guardato attorno ed erano ancora tutti lì, belli in piedi. Aveva tutta l'aria di una disfatta, ma la cosa non mi quadrava. Allora mi son seduto e ho aspettato. Il gioco è stato vederli cadere uno ad uno, tardivi ma stecchiti. Ci vuole solo pazienza. Alle volte agonizzano molto elegantemente. Alcuni franano a terra tutto d'un colpo. Non la prenderei come una vittoria, probabile che cadano per consunzione loro, non per i miei proiettili: ma certo non avevo mirato male, mi viene da dire, a parziale consolazione.
L'ultimo che ho visto crollare, dopo aver vacillato a lungo con grande lentezza e dignità, mi ha emozionato, perché lo conoscevo bene. Credo di avere in passato anche lavorato per lui (con pistole caricate a parole, come sempre). Più che uno, è una: la profondità. Il concetto di profondità, la pratica della profondità, la passione per la profondità. Forse qualcuno se li ricorda, erano animali ancora in forma, ai tempi dei Barbari. Li alimentava l'ostinata convinzione che il senso delle cose fosse collocato in una cella segreta, al riparo dalle più facili evidenze, conservato nel freezer di una oscurità remota, accessibile solo alla pazienza, alla fatica, all'indagine ostinata. Le cose erano alberi - se ne sondavano le radici. Si risaliva nel tempo, si scavava nei significati, si lasciavano sedimentare gli indizi. Perfino nei sentimenti si aspirava a quelli profondi, e la bellezza stessa la si voleva profonda, come i libri, i gesti, i traumi, i ricordi, e alle volte gli sguardi. Era un viaggio, e la sua meta si chiamava profondità.

La ricompensa era il senso, che si chiamava anche senso ultimo, e ci concedeva la rotondità di una frase a cui, anni fa, credo di aver sacrificato una marea di tempo e luce: il senso ultimo e profondo delle cose.
Non so quando, esattamente, ma a un certo punto questo modo di vedere le cose ha iniziato a sembrarci inadatto. Non falso: inadatto. Il fatto è che il senso consegnatoci dalla profondità si rivelava troppo spesso inutile, e talvolta perfino dannoso. Così, come in una sorta di timido preludio, ci è accaduto di mettere in dubbio che esistesse poi davvero un "senso ultimo e profondo delle cose". Provvisoriamente ci si orientò per definizioni più soft che sembravano rispecchiare meglio la realtà dei fatti. Che il senso fosse un divenire mai fissabile in una definizione ci sembrò, ad esempio, un buon compromesso. Ma oggi credo si possa dire che semplicemente non osavamo abbastanza, e che l'errore non era tanto credere in un senso ultimo quanto il relegarlo in profondità. Quel che cercavamo esisteva, ma non era dove pensavamo.

Non era lì per una ragione sconcertante che la mutazione avvenuta negli ultimi trent'anni ci ha buttato in faccia, emanando uno dei suoi verdetti più affascinanti e dolorosi: la profondità non esiste, è un'illusione ottica. È l'infantile traduzione in termini spaziali e morali di un desiderio legittimo: collocare ciò che abbiamo di più prezioso (il senso) in un luogo stabile, al riparo dalle contingenze, accessibile solo a sguardi selezionati, attingibile solo attraverso un cammino selettivo. Così si nascondono i tesori. Ma nel nasconderlo avevamo creato un Eldorado dello spirito, la profondità, che in realtà non sembra mai essere esistito, e che alla lunga sarà ricordato come una delle utili menzogne che gli umani si sono raccontati. Piuttosto scioccante, non c'è santo.

Infatti uno dei traumi cui la mutazione ci ha sottoposto è proprio il trovarsi a vivere in un mondo privo di una dimensione a cui eravamo abituati, quella della profondità. Ricordo che in un primo momento le menti più avvedute avevano interpretato questa curiosa condizione come un sintomo di decadenza: registravano, non a torto, la sparizione improvvisa di una buona metà del mondo che conoscevano: oltretutto, quella che veramente contava, che conteneva il tesoro. Da qui l'istintiva inclinazione a interpretare gli eventi in termini apocalittici: l'invasione di un'orda barbarica che non disponendo del concetto di profondità stava ridisponendo il mondo nell'unica residua dimensione di cui era capace, la superficialità. Con conseguente dispersione disastrosa di senso, di bellezza, di significati - di vita. Non era un modo idiota di leggere le cose, ma ora sappiamo con una certa esattezza che era un modo miope: scambiava l'abolizione della profondità con l'abolizione del senso. Ma in realtà quello che stava accadendo, tra mille difficoltà e incertezze, era che, abolita la profondità, il senso si stava spostando ad abitare la superficie delle evidenze e delle cose. Non spariva, si spostava. La reinvenzione della superficialità come luogo del senso è una delle imprese che abbiamo compiuto: un lavoretto d'artigianato spirituale che passerà alla storia.

Sulla carta, i rischi erano enormi, ma va ricordato che la superficie è il luogo della stupidità solo per chi crede nella profondità come luogo del senso. Dopo che i barbari (cioè noi) hanno smascherato questa credenza, collegare automaticamente superficie e insignificanza è diventato un riflesso meccanico che tradisce un certo rincoglionimento. Dove molti vedevano una semplice resa alla superficialità, molti altri hanno intuito uno scenario ben differente: il tesoro del senso, che era relegato in una cripta segreta e riservata, ora si distribuiva sulla superficie del mondo, dove la possibilità di ricomporlo non coincideva più con una discesa ascetica nel sottosuolo, regolata da un'élite di sacerdoti, ma da una collettiva abilità nel registrare e collegare tessere del reale. Non suona poi tanto male. Soprattutto sembra più adatto alle nostre abilità e ai nostri desideri. Per gente incapace di stare ferma e di concentrarsi, ma in compenso velocissima nello spostarsi e nel collegare frammenti, il campo aperto della superficie sembra la sede ideale dove giocarsi la partita della vita: perché mai dovremmo giocarcela, e perderla, in quei cunicoli nel sottosuolo che si ostinavano a insegnarci a scuola?

Così non sembriamo aver rinunciato a un senso, nobile e alto, delle cose: ma abbiamo iniziato a inseguirlo con una tecnica diversa, cioè muovendoci sulla superficie del mondo con una velocità e un talento che gli umani non hanno mai conosciuto. Ci siamo orientati a formare figure di senso mettendo in costellazione punti del reale attraverso cui passiamo con inedita agilità e leggerezza. L'immagine del mondo che i media restituiscono, la geografia di ideali che la politica ci propone, l'idea di sapere che il mondo digitale ci mette a disposizione non hanno ombra di profondità: sono collezioni di evidenze sottili, perfino fragili, che organizziamo in figure di una certa potenza. Le usiamo per capire il mondo. Perdiamo capacità di concentrazione, non riusciamo a fare un gesto alla volta, scegliamo sempre la velocità a discapito dell'approfondimento: l'incrocio di questi difetti genera una tecnica di percezione del reale che cerca sistematicamente la simultaneità e la sovrapposizione degli stimoli: è ciò che noi chiamiamo fare esperienza. Nei libri, nella musica, in ciò che chiamiamo bello guardandolo o ascoltandolo, riconosciamo sempre più spesso l'abilità a pronunciare l'emozione del mondo semplicemente illuminandola, e non riportandola alla luce: è l'estetica che ci piace coltivare, quella per cui qualsiasi confine tra arte alta e arte bassa va scomparendo, non essendoci più un basso e un alto, ma solo luce e oscurità, sguardi e cecità. Viaggiamo velocemente e fermandoci poco, ascoltiamo frammenti e mai tutto, scriviamo nei telefoni, non ci sposiamo per sempre, guardiamo il cinema senza più entrare nei cinema, ascoltiamo reading in rete invece che leggere i libri, facciamo lente code per mangiare al fast food, e tutto questo andare senza radici e senza peso genera tuttavia una vita che ci deve apparire estremamente sensata e bella se con tanta urgenza e passione ci preoccupiamo, come mai nessuno prima di noi nella storia del genere umano, di salvare il pianeta, di coltivare la pace, di preservare i monumenti, di conservare la memoria, di allungare la vita, di tutelare i più deboli e di difendere il lardo di Colonnata. In tempi che ci piace immaginare civili, bruciavano le biblioteche o le streghe, usavano il Partenone come deposito di esplosivi, schiacciavano vite come mosche nella follia delle guerre, e spazzavano via popoli interi per farsi un po' di spazio. Erano spesso persone che adoravano la profondità.
La superficie è tutto, e in essa è scritto il senso. Meglio: in essa siamo capaci di tracciare un senso. E da quando abbiamo maturato questa abilità, è quasi con imbarazzo che subiamo gli inevitabili sussulti del mito della profondità: oltre ogni misura ragionevole patiamo le ideologie, gli integralismi, ogni arte troppo alta e seria, qualsiasi sfacciata pronuncia di assoluto. Probabilmente abbiamo anche torto, ma sono cose che ricordiamo saldate in profondità a ragioni e sacerdozi indiscutibili che ora sappiamo fondati sul nulla, e ne siamo ancora offesi - forse spaventati. Per questo oggi suona kitsch ogni simulazione di profondità e in fondo sottilmente cheap qualsiasi concessione alla nostalgia. La profondità sembra essere diventata una merce di scarto per i vecchi, i meno avveduti e i più poveri.

Vent'anni fa avrei avuto paura a scrivere frasi del genere. Mi era chiaro perfettamente che stavamo giocando col fuoco. Sapevo che i rischi erano enormi e che in una simile mutazione ci giocavamo un patrimonio immenso. Scrivevo I barbari, ma intanto sapevo che lo smascheramento della profondità poteva generare il dominio dell'insignificante. E sapevo che la reinvenzione della superficialità generava spesso l'effetto indesiderato di sdoganare, per un equivoco, la pura stupidità, o la ridicola simulazione di un pensiero profondo. Ma alla fine, quel che è accaduto è stato soltanto il frutto delle nostre scelte, del talento e della velocità delle nostre intelligenze. La mutazione ha generato comportamenti, cristallizzato parole d'ordine, ridistribuito i privilegi: ora so che in tutto ciò è sopravvissuta la promessa di senso che a suo modo il mito della profondità tramandava. Sicuramente tra coloro che sono stati più svelti a capire e gestire la mutazione ce ne sono molti che non conoscono quella promessa, né sono capaci di immaginarla, né sono interessati a tramandarla. Da essi stiamo ricevendo un mondo brillante senza futuro. Ma come sempre è successo, ostinata e talentuosa è stata anche la cultura della promessa, e capace di estorcere al disinteresse dei più la deviazione della speranza, della fiducia, dell'ambizione. Non credo sia stolto ottimismo registrare il fatto che oggi, nel 2026, una cultura del genere esiste, sembra più che solida, e spesso presidia le cabine di comando della mutazione. Da questi barbari stiamo ricevendo un'impaginazione del mondo adatta agli occhi che abbiamo, un design mentale appropriato ai nostri cervelli, e un plot della speranza all'altezza dei nostri cuori, per così dire. Si muovono a stormi, guidati da un rivoluzionario istinto a creazioni collettive e sovrapersonali, e per questo mi ricordano la moltitudine senza nomi dei copisti medievali: in quel loro modo strano, stanno copiando la grande biblioteca nella lingua che è nostra. È un lavoro delicato, e destinato a collezionare errori. Ma è l'unico modo che conosciamo per consegnare in eredità, a chi verrà, non solo il passato, ma anche un futuro.

(26 agosto 2010) © Riproduzione riservata

Tuesday, June 08, 2010

USB communications with Zebra printers in C#

The best way to create your own application which uses a Zebra printer is to send ZPL commands directly to the printer. This is easy on RS232 or TCP/IP connections, but it's not so simple on USB, because Zebra does not offer (at least officially) an SDK which exposes APIs for USB.

I've found on the internet several articles about how to communicate with a Zebra printer through a USB connection. Most of them refer to an article by Microsoft's Knowledge Base which explains how to send raw data to the printer driver. Apart from performance issues, this is useful only if your communication is monodirectional (from the PC to the printer). It can be enough for most printers, but if you are using an RFID printer this is definitely not acceptable, as you probably need to read data from the printer in order to check the result of RFID operations for logging/printing purposes.

I searched the web for a C# based solution and I've found an excellent implementation of a communication framework using different media, like USB. It is part of a larger project hosted on SourceForge called ZBar (a collection of MS VS.NET components, controls and class libraries to aid development of printing functionality in .NET applications that make use of some barcode printers).

I took some classes from that project and with some modifications I got a nice USB stream for Zebra printers, which can be easily used to send and receive ZPL (or other scripting language) commands. The printer driver must be installed on the PC, but commands do not go through it.

Here are the files. Notice that they work both on x86 and x64 systems, but on x64 they must be compiled with the x86 option.

I collected all these files in this post because it was (at least for me) hard to find a solution for this issue, which is all in all very basic (just an I/O class for a printer!)



//-------------------------------
// ZebraUsbStream.cs
//-------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Zebra.Printing;

namespace RfidPrinter
{
///


/// Stream subclass which incorporates low-level USB access to Zebra printers
///

public class ZebraUsbStream : Stream
{
UsbPrinterConnector usb;

public ZebraUsbStream(string port)
{
usb = new UsbPrinterConnector(port);
usb.IsConnected = true;
base.ReadTimeout = usb.ReadTimeout;
base.WriteTimeout = usb.WriteTimeout;
}

public ZebraUsbStream()
{
System.Collections.Specialized.NameValueCollection devs =
UsbPrinterConnector.EnumDevices(true, true, false);

if (devs.Count < 1)
throw new Exception("No Zebra printers found");

usb = new UsbPrinterConnector(devs[0].ToString());
usb.IsConnected = true;
}


public override bool CanRead
{
get { return true; }
}

public override bool CanSeek
{
get { return false; }
}

public override bool CanWrite
{
get { return true; }
}

public override bool CanTimeout
{
get { return true; }
}

public override void Flush()
{
;
}

public override long Length
{
get { throw new NotSupportedException(); }
}

public override long Position
{
get
{
throw new NotSupportedException();
}
set
{
throw new NotSupportedException();
}
}

public override int Read(byte[] buffer, int offset, int count)
{
return usb.Read(buffer, offset, count);
}

public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}

public override void SetLength(long value)
{
throw new NotSupportedException();
}

public override void Write(byte[] buffer, int offset, int count)
{
usb.Send(buffer, offset, count);
}

protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
usb.IsConnected = false;
}

public override void Close()
{
base.Close();
if (usb.IsConnected)
usb.IsConnected = false;
}

public override int ReadTimeout
{
get
{
return usb.ReadTimeout;
}
set
{
usb.ReadTimeout = value;
}
}

public override int WriteTimeout
{
get
{
return usb.WriteTimeout;
}
set
{
usb.WriteTimeout = value;
}
}
}
}


//-------------------------------
//FileIO.cs
//-------------------------------


#region License
/* ---------------------------------------------------------------------------
* Creative Commons License
* http://creativecommons.org/licenses/by/2.5/au/
*
* Attribution 2.5 Australia
*
* You are free:
*
* - to copy, distribute, display, and perform the work
* - to make derivative works
* - to make commercial use of the work
*
* Under the following conditions:
*
* Attribution: You must attribute the work in the manner specified by the
* author or licensor.
*
* For any reuse or distribution, you must make clear to others the license
* terms of this work. Any of these conditions can be waived if you get
* permission from the copyright holder. Your fair use and other rights
* are in no way affected by the above.
*
* This is a human-readable summary of the Legal Code (the full license).
* http://creativecommons.org/licenses/by/2.5/au/legalcode
* ------------------------------------------------------------------------ */

/* ---------------------------------------------------------------------------
* Special Note
*
* A special mention and thanks to the contributions of several parties in
* blogging and publishing this complex API.
*
* P/Invoke .NET - http://www.pinvoke.net
*
* MSDN Magazine
*
* ------------------------------------------------------------------------ */
#endregion License

// $Header: /cvsroot/z-bar/msvs/zbar/Zebra.Printing/fileio.cs,v 1.4 2006/11/16 10:55:04 vinorodrigues Exp $

#if WindowsCE || PocketPC
#define WINCE
#endif

using System;
using System.Runtime.InteropServices;
using System.Threading;

#if WINCE
#error This module is not intended for Mobile platform
#endif

namespace Zebra.Printing
{
internal class FileIO
{

internal const int INVALID_HANDLE_VALUE = -1;

internal const int ERROR_FILE_NOT_FOUND = 2;
internal const int ERROR_INVALID_NAME = 123;
internal const int ERROR_ACCESS_DENIED = 5;
internal const int ERROR_IO_PENDING = 997;
internal const int ERROR_IO_INCOMPLETE = 996;

internal class NullClass
{
public NullClass()
{
throw new Exception("Cannot create instance of NullClass");
}
}

#region CreateFile

[Flags]
internal enum FileAccess : uint // from winnt.h
{
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_ALL = 0x10000000
}

[Flags]
internal enum FileShareMode : uint // from winnt.h
{
FILE_SHARE_READ = 0x00000001,
FILE_SHARE_WRITE = 0x00000002,
FILE_SHARE_DELETE = 0x00000004
}

internal enum FileCreationDisposition : uint // from winbase.h
{
CREATE_NEW = 1,
CREATE_ALWAYS = 2,
OPEN_EXISTING = 3,
OPEN_ALWAYS = 4,
TRUNCATE_EXISTING = 5
}

[Flags]
internal enum FileAttributes : uint // from winnt.h
{
FILE_ATTRIBUTE_READONLY = 0x00000001,
FILE_ATTRIBUTE_HIDDEN = 0x00000002,
FILE_ATTRIBUTE_SYSTEM = 0x00000004,
FILE_ATTRIBUTE_DIRECTORY = 0x00000010,
FILE_ATTRIBUTE_ARCHIVE = 0x00000020,
FILE_ATTRIBUTE_DEVICE = 0x00000040,
FILE_ATTRIBUTE_NORMAL = 0x00000080,
FILE_ATTRIBUTE_TEMPORARY = 0x00000100,
FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200,
FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400,
FILE_ATTRIBUTE_COMPRESSED = 0x00000800,
FILE_ATTRIBUTE_OFFLINE = 0x00001000,
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000,
FILE_ATTRIBUTE_ENCRYPTED = 0x00004000,

// from winbase.h
FILE_FLAG_WRITE_THROUGH = 0x80000000,
FILE_FLAG_OVERLAPPED = 0x40000000,
FILE_FLAG_NO_BUFFERING = 0x20000000,
FILE_FLAG_RANDOM_ACCESS = 0x10000000,
FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000,
FILE_FLAG_DELETE_ON_CLOSE = 0x04000000,
FILE_FLAG_BACKUP_SEMANTICS = 0x02000000,
FILE_FLAG_POSIX_SEMANTICS = 0x01000000,
FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000,
FILE_FLAG_OPEN_NO_RECALL = 0x00100000,
FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000
}

[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr CreateFile(
string lpFileName,
FileAccess dwDesiredAccess,
FileShareMode dwShareMode,
IntPtr lpSecurityAttributes,
FileCreationDisposition dwCreationDisposition,
FileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);

#endregion CreateFile

#region CloseHandle

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseHandle(IntPtr hObject);

#endregion CloseHandle

#region GetOverlappedResult

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetOverlappedResult(
IntPtr hFile,
/* IntPtr */ ref System.Threading.NativeOverlapped lpOverlapped,
out uint nNumberOfBytesTransferred,
bool bWait);

#endregion GetOverlappedResult

#region WriteFile

[DllImport("kernel32.dll", SetLastError = true, EntryPoint = "WriteFile")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool WriteFile0(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)]
byte[] lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
NullClass lpOverlapped);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool WriteFile(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
[In] ref System.Threading.NativeOverlapped lpOverlapped);

[DllImport("kernel32.dll", SetLastError = true)]
internal static extern int WriteFileEx(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
int nNumberOfBytesToWrite,
[In] ref System.Threading.NativeOverlapped lpOverlapped,
[MarshalAs(UnmanagedType.FunctionPtr)] IOCompletionCallback callback
);

#endregion WriteFile

#region ReadFile

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ReadFile(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)] [Out] byte[] lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
[In] ref System.Threading.NativeOverlapped lpOverlapped);

[DllImport("kernel32.dll", SetLastError = true, EntryPoint = "ReadFile")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ReadFile0(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)] [Out] byte[] lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
NullClass lpOverlapped);

[DllImport("kernel32.dll", SetLastError = true)]
internal static extern int ReadFileEx(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
int nNumberOfBytesToRead,
[In] ref System.Threading.NativeOverlapped lpOverlapped,
[MarshalAs(UnmanagedType.FunctionPtr)] IOCompletionCallback callback);

#endregion ReadFile

}
}


//-------------------------------
// PrinterConnector.cs
//-------------------------------

#region License
/* ---------------------------------------------------------------------------
* Creative Commons License
* http://creativecommons.org/licenses/by/2.5/au/
*
* Attribution 2.5 Australia
*
* You are free:
*
* - to copy, distribute, display, and perform the work
* - to make derivative works
* - to make commercial use of the work
*
* Under the following conditions:
*
* Attribution: You must attribute the work in the manner specified by the
* author or licensor.
*
* For any reuse or distribution, you must make clear to others the license
* terms of this work. Any of these conditions can be waived if you get
* permission from the copyright holder. Your fair use and other rights
* are in no way affected by the above.
*
* This is a human-readable summary of the Legal Code (the full license).
* http://creativecommons.org/licenses/by/2.5/au/legalcode
* ------------------------------------------------------------------------ */
#endregion License

// $Header: /cvsroot/z-bar/msvs/zbar/Zebra.Printing/Connect.cs,v 1.7 2006/11/16 10:55:04 vinorodrigues Exp $

using System;
using System.Collections.Generic;
using System.Text;

namespace Zebra.Printing
{

public abstract class PrinterConnector
{

protected abstract void SetConnected(bool value);

protected abstract bool GetConnected();

public bool IsConnected
{
get { return GetConnected(); }
set { SetConnected(value); }
}

public static readonly int DefaultReadTimeout = 200;

private int readTimeout = DefaultReadTimeout;

public int ReadTimeout
{
get { return readTimeout; }
set { readTimeout = value; }
}

public static readonly int DefaultWriteTimeout = 200;

private int writeTimeout = DefaultWriteTimeout;

public int WriteTimeout
{
get { return writeTimeout; }
set { writeTimeout = value; }
}

/* public bool Connect()
{
SetConnected(true);
return GetConnected();
} */

/* public void Disconnect()
{
SetConnected(false);
} */

public int Send(byte[] buffer)
{
return Send(buffer, 0, buffer.Length);
}

public abstract bool BeginSend();

public abstract void EndSend();

public abstract int Send(byte[] buffer, int offset, int count);

public virtual bool CanRead()
{
return false;
}

///
/// Reads data from the incomming connection.
///

/// populated data buffer or null if empty/unsuccessful
/// Number of bytes read or -1 if unsuccessful
public abstract int Read(byte[] buffer, int offset, int count);

}

}



//-------------------------------
// SetupApi.cs
//-------------------------------

#region License
/* ---------------------------------------------------------------------------
* Creative Commons License
* http://creativecommons.org/licenses/by/2.5/au/
*
* Attribution 2.5 Australia
*
* You are free:
*
* - to copy, distribute, display, and perform the work
* - to make derivative works
* - to make commercial use of the work
*
* Under the following conditions:
*
* Attribution: You must attribute the work in the manner specified by the
* author or licensor.
*
* For any reuse or distribution, you must make clear to others the license
* terms of this work. Any of these conditions can be waived if you get
* permission from the copyright holder. Your fair use and other rights
* are in no way affected by the above.
*
* This is a human-readable summary of the Legal Code (the full license).
* http://creativecommons.org/licenses/by/2.5/au/legalcode
* ------------------------------------------------------------------------ */

/* ---------------------------------------------------------------------------
* Special Note
*
* A special mention and thanks to the contributions of several parties in
* blogging and publishing this complex API. Converting to C# was not easy!
*
* The "setupapi.h" file from the Microsoft DDK for Windows XP SP2
*
* Peter Skarpetis for this blog "GETTING A HANDLE ON USBPRINT.SYS"
* http://blog.peter.skarpetis.com
*
* The Code Project - http://www.codeproject.com
*
* P/Invoke .NET - http://www.pinvoke.net
*
* ------------------------------------------------------------------------ */
#endregion License

// $Header: /cvsroot/z-bar/msvs/zbar/Zebra.Printing/setupapi.cs,v 1.4 2006/12/28 10:54:21 vinorodrigues Exp $

#if WindowsCE || PocketPC
#define WINCE
#endif

#if WINCE
#error This module is not intended for Mobile platform
#endif

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace Zebra.Printing
{

internal class SetupApi
{

#region Consts

internal const UInt32 DIGCF_DEFAULT = 0x00000001; // only valid with DIGCF_DEVICEINTERFACE
internal const UInt32 DIGCF_PRESENT = 0x00000002;
internal const UInt32 DIGCF_ALLCLASSES = 0x00000004;
internal const UInt32 DIGCF_PROFILE = 0x00000008;
internal const UInt32 DIGCF_DEVICEINTERFACE = 0x00000010;

internal const UInt32 SPDRP_DEVICEDESC = 0x00000000; // DeviceDesc (R/W)
internal const UInt32 SPDRP_HARDWAREID = 0x00000001; // HardwareID (R/W)
internal const UInt32 SPDRP_COMPATIBLEIDS = 0x00000002; // CompatibleIDs (R/W)
internal const UInt32 SPDRP_UNUSED0 = 0x00000003; // unused
internal const UInt32 SPDRP_SERVICE = 0x00000004; // Service (R/W)
// internal const UInt32 SPDRP_UNUSED1 = 0x00000005; // unused
// internal const UInt32 SPDRP_UNUSED2 = 0x00000006; // unused
internal const UInt32 SPDRP_CLASS = 0x00000007; // Class (R--tied to ClassGUID)
internal const UInt32 SPDRP_CLASSGUID = 0x00000008; // ClassGUID (R/W)
internal const UInt32 SPDRP_DRIVER = 0x00000009; // Driver (R/W)
internal const UInt32 SPDRP_CONFIGFLAGS = 0x0000000A; // ConfigFlags (R/W)
internal const UInt32 SPDRP_MFG = 0x0000000B; // Mfg (R/W)
internal const UInt32 SPDRP_FRIENDLYNAME = 0x0000000C; // FriendlyName (R/W)
internal const UInt32 SPDRP_LOCATION_INFORMATION = 0x0000000D; // LocationInformation (R/W)
internal const UInt32 SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E; // PhysicalDeviceObjectName (R)
internal const UInt32 SPDRP_CAPABILITIES = 0x0000000F; // Capabilities (R)
internal const UInt32 SPDRP_UI_NUMBER = 0x00000010; // UiNumber (R)
internal const UInt32 SPDRP_UPPERFILTERS = 0x00000011; // UpperFilters (R/W)
internal const UInt32 SPDRP_LOWERFILTERS = 0x00000012; // LowerFilters (R/W)
internal const UInt32 SPDRP_BUSTYPEGUID = 0x00000013; // BusTypeGUID (R)
internal const UInt32 SPDRP_LEGACYBUSTYPE = 0x00000014; // LegacyBusType (R)
internal const UInt32 SPDRP_BUSNUMBER = 0x00000015; // BusNumber (R)
internal const UInt32 SPDRP_ENUMERATOR_NAME = 0x00000016; // Enumerator Name (R)
internal const UInt32 SPDRP_SECURITY = 0x00000017; // Security (R/W, binary form)
internal const UInt32 SPDRP_SECURITY_SDS = 0x00000018; // Security (W, SDS form)
internal const UInt32 SPDRP_DEVTYPE = 0x00000019; // Device Type (R/W)
internal const UInt32 SPDRP_EXCLUSIVE = 0x0000001A; // Device is exclusive-access (R/W)
internal const UInt32 SPDRP_CHARACTERISTICS = 0x0000001B; // Device Characteristics (R/W)
internal const UInt32 SPDRP_ADDRESS = 0x0000001C; // Device Address (R)
internal const UInt32 SPDRP_UI_NUMBER_DESC_FORMAT = 0x0000001D; // UiNumberDescFormat (R/W)
internal const UInt32 SPDRP_DEVICE_POWER_DATA = 0x0000001E; // Device Power Data (R)
internal const UInt32 SPDRP_REMOVAL_POLICY = 0x0000001F; // Removal Policy (R)
internal const UInt32 SPDRP_REMOVAL_POLICY_HW_DEFAULT = 0x00000020; // Hardware Removal Policy (R)
internal const UInt32 SPDRP_REMOVAL_POLICY_OVERRIDE = 0x00000021; // Removal Policy Override (RW)
internal const UInt32 SPDRP_INSTALL_STATE = 0x00000022; // Device Install State (R)
internal const UInt32 SPDRP_MAXIMUM_PROPERTY = 0x00000023; // Upper bound on ordinals

#endregion Consts

#region Structs

[StructLayout(LayoutKind.Sequential)]
internal struct SP_DEVINFO_DATA
{
///
/// Size of structure in bytes
///

public Int32 cbSize;
///
/// GUID of the device interface class
///

public Guid classGuid;
///
/// Handle to this device instance
///

public Int32 devInst;
///
/// Reserved; do not use.
///

public UIntPtr reserved;
};

[StructLayout(LayoutKind.Sequential)]
internal struct SP_DEVICE_INTERFACE_DATA
{
///
/// Size of the structure, in bytes
///

public Int32 cbSize;
///
/// GUID of the device interface class
///

public Guid interfaceClassGuid;
///
///
///

public UInt32 flags;
///
/// Reserved; do not use.
///

public UIntPtr reserved;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
public struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
public UInt32 cbSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)] // will never be more than 256 in length
public string devicePath;
}

public class NullClass
{
public NullClass()
{
throw new Exception("Cannot create instance of NullClass");
}
}

#endregion Structs

#region DLLImports

[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SetupDiGetClassDevs(
ref Guid ClassGuid,
[MarshalAs(UnmanagedType.LPTStr)]
String Enumerator,
IntPtr hwndParent,
UInt32 Flags);

[DllImport(@"setupapi.dll", CharSet=CharSet.Auto, SetLastError = true)] // from PInvoke.net
internal static extern UInt16 SetupDiDestroyDeviceInfoList( IntPtr hDevInfo );

[DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] // from PInvoke.net
internal static extern Boolean SetupDiEnumDeviceInterfaces(
IntPtr hDevInfo,
ref SP_DEVINFO_DATA devInfo,
ref Guid interfaceClassGuid,
UInt32 memberIndex,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData );

[DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern Boolean SetupDiEnumDeviceInterfaces(
IntPtr hDevInfo,
int zero_devInfo, // used for 0 (Zero)
ref Guid interfaceClassGuid,
UInt32 memberIndex,
ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData );

[DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true, EntryPoint = "SetupDiGetDeviceInterfaceDetail")]
internal static extern Boolean SetupDiGetDeviceInterfaceDetail0(
IntPtr hDevInfo,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData, // OPTIONAL
UInt32 deviceInterfaceDetailDataSize,
/* out UInt32 */ NullClass requiredSize, // OPTIONAL
ref SP_DEVINFO_DATA deviceInfoData); // OPTIONAL

[DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true, EntryPoint = "SetupDiGetDeviceInterfaceDetail")]
internal static extern Boolean SetupDiGetDeviceInterfaceDetail0(
IntPtr hDevInfo,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
NullClass deviceInterfaceDetailData, // OPTIONAL
UInt32 deviceInterfaceDetailDataSize,
out UInt32 requiredSize, // OPTIONAL
NullClass deviceInfoData); // OPTIONAL

/* [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern Boolean SetupDiGetDeviceInterfaceDetail(
IntPtr hDevInfo,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
Int32 zero_deviceInterfaceDetailData, // used for 0 (Zero)
UInt32 zero_deviceInterfaceDetailDataSize,
out UInt32 requiredSize,
Int32 zero_deviceInfoData); // used for 0 (Zero) */ // KEEP

[DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true, EntryPoint = "SetupDiGetDeviceRegistryProperty")]
internal static extern Boolean SetupDiGetDeviceRegistryProperty0(
IntPtr hDevInfo,
ref SP_DEVINFO_DATA deviceInfoData,
UInt32 property,
/* out IntPtr */ NullClass propertyRegDataType, // OPTIONAL
StringBuilder propertyBuffer,
UInt32 propertyBufferSize,
/* out IntPtr */ NullClass requiredSize); // OPTIONAL

[DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true, EntryPoint = "SetupDiGetDeviceRegistryProperty")] // overloaded for null refs
internal static extern Boolean SetupDiGetDeviceRegistryProperty0(
IntPtr hDevInfo,
ref SP_DEVINFO_DATA deviceInfoData,
UInt32 property,
out IntPtr propertyRegDataType, // OPTIONAL
NullClass propertyBuffer,
UInt32 propertyBufferSize, // set to 0 (Zero)
out UInt32 requiredSize); // OPTIONAL

#endregion DLLImports

}
}




//-------------------------------
// UsbPrinterconnector.cs
//-------------------------------

#region License
/* ---------------------------------------------------------------------------
* Creative Commons License
* http://creativecommons.org/licenses/by/2.5/au/
*
* Attribution 2.5 Australia
*
* You are free:
*
* - to copy, distribute, display, and perform the work
* - to make derivative works
* - to make commercial use of the work
*
* Under the following conditions:
*
* Attribution: You must attribute the work in the manner specified by the
* author or licensor.
*
* For any reuse or distribution, you must make clear to others the license
* terms of this work. Any of these conditions can be waived if you get
* permission from the copyright holder. Your fair use and other rights
* are in no way affected by the above.
*
* This is a human-readable summary of the Legal Code (the full license).
* http://creativecommons.org/licenses/by/2.5/au/legalcode
* ------------------------------------------------------------------------ */

/* ---------------------------------------------------------------------------
* Special Note
*
* A special mention and thanks to the contributions of several parties in
* blogging and publishing this complex API. Converting to C# was not easy!
*
* The "setupapi.h" file from the Microsoft DDK for Windows XP SP2
*
* Peter Skarpetis for this blog "GETTING A HANDLE ON USBPRINT.SYS"
* http://blog.peter.skarpetis.com
*
* The Code Project - http://www.codeproject.com
*
* P/Invoke .NET - http://www.pinvoke.net
*
* ------------------------------------------------------------------------ */
#endregion License

// $Header: /cvsroot/z-bar/msvs/zbar/Zebra.Printing/ConUsb.cs,v 1.7 2006/12/28 10:54:21 vinorodrigues Exp $

#if WindowsCE || PocketPC
#define WINCE
#endif

#if WINCE
#error This module is not intended for Mobile platform
#endif

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Collections.Specialized;
using System.IO;
using Microsoft.Win32;
using System.Threading;

namespace Zebra.Printing
{

///
/// Connector leveraging usbmon.dll/usbprint.sys.

/// Note: This cannot be used in more than one process at a time, so if the spooler is running you cannot use it.
///

public class UsbPrinterConnector : PrinterConnector
{

#region EnumDevices

static Guid GUID_DEVICEINTERFACE_USBPRINT = new Guid(
0x28d78fad, 0x5a12, 0x11D1,
0xae, 0x5b, 0x00, 0x00, 0xf8, 0x03, 0xa8, 0xc2);
// static IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);

public static NameValueCollection EnumDevices()
{
return EnumDevices(true);
}

public static NameValueCollection EnumDevices(bool presentOnly)
{
return EnumDevices(presentOnly, true);
}

public static NameValueCollection EnumDevices(bool presentOnly, bool zebraOnly)
{
return EnumDevices(presentOnly, zebraOnly, true);
}

public static NameValueCollection EnumDevices(bool PresentOnly, bool ZebraOnly, bool fullDetail)
{
NameValueCollection res = new NameValueCollection();
String name, path, desc, port;

Guid intfce;
IntPtr devs;
SetupApi.SP_DEVINFO_DATA devinfo = new SetupApi.SP_DEVINFO_DATA();
SetupApi.SP_DEVICE_INTERFACE_DATA devinterface = new SetupApi.SP_DEVICE_INTERFACE_DATA();
SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA interface_detail;
UInt32 devcount;
UInt32 size;

RegistryKey regKey, subKey;

intfce = GUID_DEVICEINTERFACE_USBPRINT;

UInt32 flags = SetupApi.DIGCF_DEVICEINTERFACE;
if (PresentOnly)
flags |= SetupApi.DIGCF_PRESENT;

devs = SetupApi.SetupDiGetClassDevs(ref intfce,
null,
IntPtr.Zero,
flags);
if (devs == (IntPtr)FileIO.INVALID_HANDLE_VALUE)
return null;

devcount = 0;
devinterface.cbSize = Marshal.SizeOf(typeof(SetupApi.SP_DEVICE_INTERFACE_DATA));

while (SetupApi.SetupDiEnumDeviceInterfaces(
devs,
0,
ref intfce,
devcount,
ref devinterface))
{
devcount++;

SetupApi.SetupDiGetDeviceInterfaceDetail0(
devs,
ref devinterface,
null,
0,
out size,
null);

if ((size > 0) &&
(size <= (Marshal.SizeOf(typeof(SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA))) - sizeof(UInt32)))
{

interface_detail = new SetupApi.SP_DEVICE_INTERFACE_DETAIL_DATA();
interface_detail.cbSize = (UInt32)(sizeof(UInt32) + sizeof(Char)); // Wow! This is a gotcha!

devinfo = new SetupApi.SP_DEVINFO_DATA();
devinfo.cbSize = Marshal.SizeOf(typeof(SetupApi.SP_DEVINFO_DATA));

if (SetupApi.SetupDiGetDeviceInterfaceDetail0(
devs,
ref devinterface,
ref interface_detail,
size,
null,
ref devinfo))
{
path = interface_detail.devicePath.ToString();
name = GetDeviceRegistryProperty(devs, ref devinfo, SetupApi.SPDRP_LOCATION_INFORMATION);
if (fullDetail)
{
desc = "";
port = "";

if (path.StartsWith("\\\\?\\"))
{
string key = "##?#" + path.Substring(4);

try
{
regKey = Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Control\\DeviceClasses\\" +
GUID_DEVICEINTERFACE_USBPRINT.ToString("B"));
try
{
subKey = regKey.OpenSubKey(key);
if (subKey != null)
{
subKey = subKey.OpenSubKey("#\\Device Parameters");
desc = subKey.GetValue("Port Description").ToString();
port = subKey.GetValue("Port Number").ToString();
subKey.Close();
}
}
finally
{
regKey.Close();
}
}
catch
{
// do nothing
}
}

if (ZebraOnly && (!desc.StartsWith("Zebra")))
continue;

res.Add(name, path);
res.Add(name, desc);
res.Add(name, port);
}
else
res.Add(name, path);
}
else
throw new Win32Exception(Marshal.GetLastWin32Error());
}

}
SetupApi.SetupDiDestroyDeviceInfoList(devs);

return res;
}

private static String GetDeviceRegistryProperty(IntPtr hDevInfo,
ref SetupApi.SP_DEVINFO_DATA deviceInfoData,
UInt32 property)
{
IntPtr dataType = IntPtr.Zero;
uint size;
StringBuilder buffer;

SetupApi.SetupDiGetDeviceRegistryProperty0(
hDevInfo,
ref deviceInfoData,
property,
out dataType,
null,
0,
out size);

if (size > 0)
{
buffer = new StringBuilder((int)size);

if (SetupApi.SetupDiGetDeviceRegistryProperty0(
hDevInfo,
ref deviceInfoData,
property,
null,
buffer,
size,
null))
{
return buffer.ToString();
}
else
throw new Win32Exception(Marshal.GetLastWin32Error());
}
else
return String.Empty;
}

#endregion EnumDevices

private string interfaceName;

private IntPtr usbHandle = IntPtr.Zero;

public static readonly uint ReadBufferSize = 512;

private byte[] readBuffer;

///
/// Constructor
///

///
public UsbPrinterConnector(string InterfaceName)
: base()
{
if (!InterfaceName.StartsWith("\\"))
{
NameValueCollection plist = EnumDevices(true, false, false);
if (plist.GetValues(InterfaceName) != null)
InterfaceName = plist.GetValues(InterfaceName)[0];
else
throw new Exception("Cannot locate USB device");
}
this.interfaceName = InterfaceName;
}

///
/// Destructor
///

~UsbPrinterConnector()
{
SetConnected(false);
}

protected override void SetConnected(bool value)
{
if (value)
{
if ((int)usbHandle > 0)
SetConnected(false);

/* C++ Decl.
usbHandle = CreateFile(
interfacename,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
*/

usbHandle = FileIO.CreateFile(
interfaceName,
FileIO.FileAccess.GENERIC_WRITE | FileIO.FileAccess.GENERIC_READ,
FileIO.FileShareMode.FILE_SHARE_READ,
IntPtr.Zero,
FileIO.FileCreationDisposition.OPEN_ALWAYS,
FileIO.FileAttributes.FILE_ATTRIBUTE_NORMAL |
FileIO.FileAttributes.FILE_FLAG_SEQUENTIAL_SCAN |
FileIO.FileAttributes.FILE_FLAG_OVERLAPPED,
IntPtr.Zero);
if ((int)usbHandle <= 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
else
if ((int)usbHandle > 0)
{
FileIO.CloseHandle(usbHandle);
usbHandle = IntPtr.Zero;
}
}

protected override bool GetConnected()
{
return ((int)usbHandle > 0);
}

public override bool BeginSend()
{
return GetConnected();
}

public override void EndSend()
{
// do nothing
}

public override int Send(byte[] buffer, int offset, int count)
{
// USB 1.1 WriteFile maximum block size is 4096
uint size;
byte[] bytes;

if (!GetConnected())
throw new Exception("Not connected");

if (count > 4096)
{
throw new NotImplementedException(); // TODO: Copy byte array loop
}
else
{
bytes = new byte[count];
Array.Copy(buffer, offset, bytes, 0, count);
ManualResetEvent wo = new ManualResetEvent(false);
NativeOverlapped ov = new NativeOverlapped();
// ov.OffsetLow = 0; ov.OffsetHigh = 0;
ov.EventHandle = wo.Handle;
if (!FileIO.WriteFile(usbHandle, bytes, (uint)count, out size, ref ov))
{
if (Marshal.GetLastWin32Error() == FileIO.ERROR_IO_PENDING)
wo.WaitOne(WriteTimeout, false);
else
throw new Win32Exception(Marshal.GetLastWin32Error());
}

FileIO.GetOverlappedResult(usbHandle, ref ov, out size, true);
return (int)size;
}
}

public override bool CanRead()
{
return true;
}

public override int Read(byte[] buffer, int offset, int count)
{
// USB 1.1 ReadFile in block chunks of 64 bytes
// USB 2.0 ReadFile in block chunks of 512 bytes
uint read;

if (readBuffer == null)
readBuffer = new byte[ReadBufferSize];

AutoResetEvent sg = new AutoResetEvent(false);
NativeOverlapped ov = new NativeOverlapped();
ov.OffsetLow = 0;
ov.OffsetHigh = 0;
ov.EventHandle = sg.Handle;

if (!FileIO.ReadFile(usbHandle, readBuffer, ReadBufferSize, out read, ref ov))
{
if (Marshal.GetLastWin32Error() == FileIO.ERROR_IO_PENDING)
sg.WaitOne(ReadTimeout, false);
else
throw new Win32Exception(Marshal.GetLastWin32Error());
}
FileIO.GetOverlappedResult(usbHandle, ref ov, out read, true);

Array.Copy(readBuffer, 0, buffer, offset, read);
return (int)read;
}

}

}


Wednesday, March 03, 2010

CCCalc

Conosco un molte persone che utilizzano una calcolatrice da tenere accanto al PC, o usano quella integrata nel telefono. Mi è sempre sembrato più furbo utilizzare direttamente il PC, ma non è sempre così immediato come la calcolatrice da tavolo o addirittura carta e penna.

La calcolatrice di windows è una sincera pena, tutti la conoscono e non sto nemmeno a parlarne.

Ho conosciuto invece un'eccellente calcolatore, poco noto, con un approccio nuovo e molto intuitivo riguardo all'interfaccia utente: CCCalc (http://cccalc.excelsior-usa.com/en/index.html).


Simula l'utilizzo di carta e penna, mettendo gli operandi "in colonna" come si farebbe su un foglio di carta. E' anche possibile modificare righe già scritte e vedere i risultati aggiornati. Per ora supporta solo le operazioni elementari: +, -, *, /, radice quadrata (shortcut: S) e %. Mancano altre funzioni scientifiche, ma sono meno usate dalla maggior parte degli utenti . Si impara subito ad usarlo ed ha la comodità di lasciare i risultati disponibili a video. In sostanza, è molto più semplice e comodo, per semplici calcoli, della calcolatrice di windows o di un foglio di calcolo come Calc/Excel. Ovviamente è gratuita.

Segnalo anche un'ottima calcolatrice scientifica, con capacità di disegno, conversioni, e valutazioni complesse: GraphCalc (http://www.graphcalc.com/), ormai non aggiornata da qualche anno, ma molto completa

Thursday, February 25, 2010

"Sandro Pertini - Presidente della Repubblica, 1978 - 1985. "Dietro ogni articolo della Carta Costituzionale stanno centinaia di giovani morti nella Resistenza, quindi la Repubblica è una conquista nostra e dobbiamo difenderla, costi quel che costi. Ma dobbiamo difenderla anche dalla corruzione. La corruzione è una nemica della Repubblica. I corrotti devono essere colpiti senza nessuna attenuante, senza nessuna pietà. E dare loro solidarietà, per ragioni di amicizia o di partito, significa diventare complici di questi corrotti ... Guai se qualcuno, per amicizia o solidarietà di partito, dovesse sostenere questi corrotti e difenderli... la legge sia implacabile, inflessibile contro i protagonisti di questi scandali, che danno un esempio veramente degradante al popolo italiano". Sarai sempre nei nostri cuori."

Il giorno dopo l'ennesimo scandalo (Fastweb-Telecom e la 'ndrangheta in Senato). Chi ha la forza oggi di dire queste parole?