Technology Experience

.NET World

Programmazione, libri, snippet di codice, articoli tecnici

.NET World

[Keyzard 2] Ragionamenti, idee e concept art

Cinque anni fa, molto prima che arrivassi su UGIdotNET e molto prima che mi facessi conoscere attraverso il mio blog, scrissi Keyzard, un piccolo gioco educativo/didattico che riscosse un certo successo. Raggiunsi 6.000 download totali, e mi arrivarono un sacco di mail di ringraziamenti e di complimenti, perchè molti bambini (anche con problemi di salute) in tutte le parti d’Italia impararono ad usare la tastiera del loro PC. Si trattava di un piccolo gioco dove per vincere bisogna premere velocemente le lettere sulla tastiera: tutto questo per sconfiggere un fuorilegge nel vecchio Far West.

In questi giorni, rilassato e comodo a casa, mi son detto: perchè non scrivere Keyzard 2, sfruttando le tecnologie più moderne, rispetto a quelle che erano disponibili 5 anni fa?

Una sera, invece di andare a dormire, mi son messo davanti al PC e ci ho ragionato su.
Ecco quello che ho tirato fuori.

Ambientazione e idee di base
Prima regola: cambiare ambientazione. Invece del vecchio West, questa volta farò qualcosa di fantascientifico. L’idea di base – che deve assolutamente rimanere – è lo scopo didattico/educativo. Quindi, ecco lo scenario:

Nota tecnica : l’immagine qui sopra è realizzata in vettoriale con Expression Design, e le clipart sono state scaricate dal sito OpenClipart.

In pratica, voi belli beati vivete in una tranquilla casa di campagna, isolata e staccata dal resto del mondo. E’ notte, una bella notte stellata e nulla sembra indicare nulla di strano. Tutto ad un tratto, il cielo diventa verdastro ed improvvisamente sul cielo sopra casa vostra arrivo un UFO:

Non abbiate paura, gli alieni sono amichevoli: lo sono (quasi) sempre. 🙂 L’UFO tenterà di comunicare con voi attraverso le sette note musicali, rappresentate da sette colori diversi: li vedete sull’UFO qui sopra. A questo punto, comincia il bello.

L’UFO suona un gruppo di note, ad esempio tre. Il giocatore deve ripetere l’esatta sequenza di note, cliccando sui rettangoli colorati. Se la sequenza è corretta, l’UFO ripete la sequenza, aggiungendo però una nota e così via…fino ad un massimo…chessò…di 10, o 15 note. Questo è un dettaglio. Quando il giocatore arriva a ripetere la sequenza finale…

…dall’UFO principale si stacca una piccola navicella, che scende fino ad avvicinarsi al suolo. Appare un teletrasporto, che fa scendere un premio/ricompensa al giocatore – dettaglio che non ho ancora deciso. 🙂

A questo punto il gioco ricomincia daccapo, con una nuova sequenza, però magari un po’ più difficile: le note suonate sono più brevi (e quindi bisogna stare più attenti), oppure mentre al primo round il giocatore può chiedere all’UFO di ripetere, dal secondo round in poi non c’è più questa possibilità, e così via.

Questa modalità di gioco chiaramente aiuta a migliorare la memoria, ma mi stavo chiedendo se non fosse carino mantenere la vecchia modalità di gioco del primo Keyzard: l’UFO spara delle lettere e noi dobbiamo premerle sulla tastiera per bloccarle. Che ne dite?

Se c’è qualcuno che vuole darmi una mano, anche solo per darmi idee, o per quanto riguarda l’aspetto grafico, lo aspetto a braccia aperte!

Send to Kindle
.NET World

TFS ed il nome di eccezione più lungo del mondo…

…al punto che avrei voluto scriverlo nel titolo di questo post, ma rischiavo di sputtanare rovinare il tema di Subtext. 🙂

L’eccezione è Microsoft.TeamFoundation.WorkitemTracking.Client.WorkItemTypeDeniedOrNotExistException, e si scatena quando tentate di creare un nuovo WorkItem (di qualsiasi tipo) dal Team Explorer solo nel caso in cui:

  1. Avevate installato Visual Studio 2008 + Service Pack 1
  2. Successivamente avete installato il Team Explorer

Durante l’installazione del Team Explorer, il Service Pack 1 di Visual Studio va a farsi benedire. la soluzione è molto semplice: è sufficiente reinstallare l’SP1 di Visual Studio per riavere tutto funzionante senza problemi. Non parlo a vanvera, mi è successo oggi pomeriggio, è bastata un’attenta googlata (non è che si trovi molto in giro) e ho trovato come sistemare la cosa…perciò…potete fidarvi!

Send to Kindle
.NET World

Acquistare Microsoft Expression Blend

Negli ultimi due mesi mi sono occupato, insieme a mio fratello, dello sviluppo di un’applicazione WPF per un nostro (suo) cliente diretto. Abbiamo (ha) deciso di sfruttare la tecnologia WPF perchè l’applicazione doveva essere piuttosto…come dire…appariscente, facile da usare, graficamente interessante, e così via.

Scrivere lo XAML dall’editor di Visual Studio, dopo un po’ che lo si conosce, è piuttosto semplice. Devo dire che il modo di pensare alle interfacce di WPF mi piace moltissimo, perchè costringe lo sviluppatore a pensare gerarchicamente alla struttura logica della finestra che deve apparire all’utente finale. Lo costringe, è vero, ma in modo naturale. Prima si pensa ai pannelli più “esterni”, poi via via si entra sempre più nel dettaglio.

Ma prima o poi usare Blend è davvero indispensabile. Trovo davvero assurdo che un prodotto come Blend non sia incluso nella subscription MSDN Professional. Per favore, vi prego, toglietemi l’editor XAML da Visual Studio, ma datemi Blend. Per favore, non mettete gli altri prodotti della serie Expression (Web, Design, Encoder, etc.), ma ficcateci dentro Blend. Aumentate di 200 Euro il prezzo di MSDN Professional, ma metteteci dentro Blend. Comunque sia, le cose stanno così: se avete una subscription MSDN Professional, tra tutti i download non avete Blend, Microsoft ha deciso così e dobbiamo prenderne atto.

Quindi…quanto costa e devo si acquista Blend?

Su Gorilla.it il prezzo di Expression Blend 2 DVD English è di Euro 523,23 + Iva 20%.
Stesso presso per la versione in lingua italiana.
L’upgrade dalla versione 1.0 costa Euro 103,96 + Iva 20%.

Ieri ho scoperto l’esistenza della Expression Professional Subscription (EPS), una suite che comprende quanto segue:

  • Expression Studio 3
  • Visual Studio 2008 Standard
  • Office 2007 Standard
  • Office Visio Standard
  • Windows XP
  • Windows Vista Business Edition

Il costo su Gorilla.it è di Euro 1.068,98 + Iva 20%.

Ho due critiche da fare su questo prodotto.

  1. Non si sovrappone completamente ad una subscription MSDN, questo è ovvio. Ma chi ha già una licenza MSDN, come me, non capisce bene il motivo per cui dovrebbe acquistare EPS: include software che ha già adesso attraverso MSDN (ad eccezione di Office). A me servirebbe avere soltanto Expression Blend!
  2. Al di là di questo, non capisco bene la motivazione per cui è stato incluso Office. Per chi è pensata questa EPS, qual’è il target?

Ma il punto è un altro. La cosa interessante (e secondo me che non si dice mai) di MSDN è che contiene software di cui si ha bisogno saltuariamente, ma che comunque si ha a disposizione al momento giusto. Immaginatevi: tutti noi lavoriamo con Visual Studio 2008, Office 2007, Sharepoint 2007…insomma, i software alla loro ultima release disponibile sul mercato. Pronti alla scenetta. Siete in ufficio, squilla il cellulare, vi chiama un cliente che vi chiede di realizzare…chessò…un database Access che fa questo e quello. E vostro malgrado, il database deve essere fatto con Microsoft Access 2000. MSDN vi salva il cxxo: non è che dovete andare in un negozio ad acquistare una versione Access 2000 apposta per quei 10-15 giorni di lavoro. Semplicemente grazie ad MSDN avete una licenza e potete utilizzarla.

Questo è il discorso che oggi io vorrei fare per Blend. Io non so quanto ne avrò bisogno in futuro, non so se sarà un investimento utile oppure no. Io ne ho bisogno per 2 mesi, e poi chissà! Se Blend fosse incluso in MSDN, non avrei questo tipo di problema. Semplicemente sarebbe incluso nella suite, e potrei installarmelo senza problemi per il tempo che mi serve. Invece così non posso, e come dicevo non posso nemmeno preventivare/calcolare se davvero mi servirà dopo, e quanto. Di fronte a questa incognita, non faccio alcun acquisto.

Concludo precisando che i prezzi che ho indicato non sono ufficiali, non arrivano da fonti Microsoft, ma da una semplice ricerca sul listino on-line di Gorilla, che è il fornitore da cui acquisto normalmente MSDN da circa una decina d’anni.

Send to Kindle
.NET World

AVG blocca Team Foundation Server

Da qualche settimana mi sono ricostruito un TFS locale per me, tutto privato. Esso gira in una virtual-machine creata sotto VPC. Il mio PC fisico dispone di 4GBytes di RAM, e vi posso assicurare che assegnarne anche uno solo ad una macchina virtuale basta ed avanza. Sembrava che tutto girasse perfettamente: tutti gli utenti ed i permessi configurati correttamente, tutti i servizi con i permessi giusti, e così via.

Dal mio Team Explorer (TE), sul PC fisico, però, non c’era verso di raggiungere TFS nella macchina virtuale. Gira, gira, googla, googla, avevo pensato a tutto tranne che fosse AVG la causa del problema. A quanto pare, il modulo Web Shield di AVG scansiona tutto ciò che passa per le porte 80, 8080 e 3128. I web-services di TFS passano per la porta 8080, e quindi il vostro TE non riesce a connettersi.

Per risolvere il problema, è sufficiente andare in Strumenti –> Impostazioni Avanzate –> Web Shield –> Protezione Web. O disattivate il modulo Web Shield, oppure inserite l’url da considerare sicuro. Nel mio caso l’url è http://virtualtfs:8080.

Send to Kindle
.NET World

Da una embedded resource a IEnumerable<T> con Linq

Data la classe ContactFieldImport così implementata:

   1: public class ContactFieldImport
   2: {
   3:     public string Property { get; internal set; }
   4:     public string Field { get; internal set; }
   5:  
   6:     public ContactFieldImport() { }
   7:  
   8:     public ContactFieldImport(string property, string field)
   9:     {
  10:         Property = property;
  11:         Field = field;
  12:     }
  13: }

vogliamo creare una struttura IEnumerable<ContactFieldImport> popolata con una embedded resource definita nell’assembly locale.

Questa risorsa è un normale file di testo e contiene quanto segue:

FullName;Denominazione|
ManagerName;Titolare|
HomeAddress;Indirizzo|
HomeAddressPostalCode;CAP|
HomeAddressCity;Città|
HomeAddressState;Provincia|
Email1Address;Mail|
Body;Note|
CompanyName;RagioneSocialeFiscale|
BusinessAddress;IndirizzoFiscale|
BusinessAddressPostalCode;CapFiscale|
BusinessAddressCity;CittàFiscale|
BusinessAddressState;ProvinciaFiscale|
GovernmentIDNumber;PartitaIva|
OtherAddressCity;LuogoNascita|
OtherAddressCountry;Cittadinanza|
OrganizationalIDNumber;Matricola|

Ogni riga contiene una coppia Property/Field. Ho usato il pipe ‘|’ come separatore per le linee, e un ‘;’ per separare i due campi.

Possiamo farlo con Linq? Certo, con una piccola funzione come questa:

   1: private static void setupMappings()
   2: {
   3:     string mappingsFile = CoreServices.GetResourceContents("VivendoByte.MyProject.Core.ContactMapping.txt");
   4:     string[] lines = mappingsFile.Split('|');
   5:  
   6:     mappings = from l in lines
   7:                where (l.Length > 0)
   8:                let splitted = l.Split(';')
   9:                    select new ContactFieldImport
  10:                    {
  11:                        Property = splitted[0],
  12:                        Field = splitted[1]
  13:                    };
  14: }

La riga (3) restituisce tramite un metodo statico il contenuto della risorsa illustrata prima. Splitto le righe usando come separatore il carattere pipe ‘|’ (riga 4). Questa operazione di splitting restituisce un array di stringhe che – lo ricordiamo – è un oggetto interrogabile con Linq. Le righe 6-13 compongono una query Linq applicata su un string[]: filtro solamente le righe il cui .Length > 0, poi splitto e metto il risultato in un oggetto splitted. Per ogni riga restituisco un oggetto ContactFieldImport che va a popolare l’oggetto mappings dichiarato come IEnumerable<ContactFieldImport>.

Send to Kindle
.NET World

Qualche ragionamento su System.Reflection ed Interop con Outlook

In queste sere mi sto divertendo, se così si può dire, con la creazione di un plug-in per Microsoft Outlook 2007. Lo scopo è quello di importare nel folder Contacts di Outlook un’archivio di anagrafica, suddiviso in diverse categorie. Per farla breve vi faccio vedere solo due tabelle che illustrano il contenuto dell’anagrafica di cui sto parlando.

La tabella Tipi contiene la definizione delle categorie. Il campo “Tipo” contiene il nome della categoria (Cantanti, Gruppi, Discoteche, Pub, Feste in Piazza, etc.). Il campo “Lettera” contiene un singolo carattere (C, G, D, P, F, etc.) che indica con quale lettera è identificata una certa categoria; tale campo serve per andare in JOIN sulla tabella Anagrafica. In questo modo ogni record di Anagrafica appartiene ad una ed una sola categoria della tabella Tipi. Le relazioni mostrate nell’immagine qui sopra credo siano abbastanza chiare. Non accetto critiche sul database: l’ho ereditato io 10 anni fa su Access 2.0 e oggi gira in produzione su Access 2003 dopo tutti questi anni. Mi dovrei vergognare per questo? Forse sì, forse no, ma così è e così me lo prendo. 🙂

Comunque, lo scopo è quello di elaborare ogni record di Anagrafica e di creare un’istanza di Microsoft.Office.Interop.Outlook.ContactItem, popolandone tutte le proprietà pubbliche, e poi di salvarlo dentro Outlook 2007. Ecco uno stralcio di C# per dare l’idea:

1 foreach (MyDataSet.AnagraficaRow row in dataset.Anagrafica.Rows) 2 { 3 if (ContactAdding != null) ContactAdding(this, new ContactEventArgs(string.Empty)); 4 Outlook.ContactItem item = ContactServices.CreateContact(row); 5 6 if (item != null) 7 { 8 item.Save(); 9 if (ContactAdded != null) ContactAdded(this, new ContactEventArgs(item.FullName)); 10 } 11 }

Dato che si tratta di un prototipo mi sono semplificato la vita con un DataSet tipizzato. Ciclo su tutte le righe presenti nella DataTable. Per ogni riga sollevo due eventi ContactAdding e ContactAdded (ContactAdding e ContactAdded sono due public event, ContactEventArgs è una classe derivata da EventArgs). Ma il succo è la chiamata al metodo statico CreateContact, metodo che prende in input un’istanza di AnagraficaRow e restituisce un’istanza di ContactItem.

Tecnicamente parlando, possiamo implementare questo metodo in tanti modi diversi. Io ne ho pensati ed implementati due:

  1. assegno una ad una le proprietà pubbliche di ContactItem valorizzandole con i campi esposti da AnagraficaRow
  2. uso Reflection per fare qualcosa di più ingegnoso e gestibile nel prossimo futuro

Per il punto (1) il codice dovrebbe essere una cosa simile a questa:

1 ContactItem item = (ContactItem)folder.Items.Add(OlItemType.olContactItem); 2 if (!row.IsDenominazioneNull()) item.FullName = row.Denominazione; 3 if (!row.IsTitolareNull()) item.ManagerName = row.Titolare; 4 ... 5 ...

Alla riga (1) creo un’istanza di ContactItem, poi valorizzo le proprietà FullName, ManagerName e così via, per le decine di campi di cui necessitate (le mie sono 18). Noioso e davvero poco manutenibile.

Il punto 2 è più interessante, perchè tramite Reflection possiamo creare dinamicamente un’istanza di ContactItem. Creiamo una classe ContactFieldImport così implementata:

   1: public class ContactFieldImport
   2: {
   3:     public string Property { get; private set; }
   4:     public string Field { get; private set; }
   5:  
   6:     public ContactFieldImport(string property, string field)
   7:     {
   8:         Property = property;
   9:         Field = field;
  10:     }
  11: }

Ogni istanza di ContactFieldImport rappresenta una coppia di Property/Field. Possiamo così definire una List<ContactFieldImport>:

   1: List<ContactFieldImport> props = new List<ContactFieldImport>();
   2: props.Add(new ContactFieldImport("FullName", "Denominazione"));
   3: props.Add(new ContactFieldImport("ManagerName", "Titolare"));
   4: props.Add(new ContactFieldImport("HomeAddress", "Indirizzo"));
   5: props.Add(new ContactFieldImport("HomeAddressPostalCode", "CAP"));

Ogni coppia definisce come popolare un oggetto ContactItem. Prendo il valore del campo (Field) e con esso valorizzo la proprietà pubblica (Property) di ContactItem. A questo punto il gioco è semplice.

   1: foreach (ContactFieldImport cfi in props)
   2: {
   3:     PropertyInfo pi = typeof(_ContactItem).GetProperty(cfi.Property);
   4:  
   5:     if (pi != null && pi.CanWrite && !string.IsNullOrEmpty(row[cfi.Field].ToString()))
   6:     {
   7:         pi.SetValue(item, row[cfi.Field], null);
   8:     }
   9: }

Itero su tutti gli elementi contenuti nella lista props. Per ciascuno degli elementi, ottengo un riferimento alla PropertyInfo puntata da cfi.Property. Se la PropertyInfo è valida, può essere scritta (CanWrite == true) e se l’AnagraficaRow corrente è una stringa valida, allora imposto la proprietà dell’istanza di ContactItem (riga 7).

Dal punto di vista prestazionale, il ciclo for…each qui sopra è molto più veloce rispetto al primo metodo, quello che cioè che settava le proprietà pubbliche di ContactItem una ad una, senza una sorta di automatismo. Non so darvi con esattezza l’ordine di grandezza, ma ho provato ad importare con tutti e due i metodi qualcosa come 1.400 anagrafiche e tramite Reflection le cose erano molto migliori (< 1 minuto).

Il risultato finale visto in Outlook 2007 è il seguente:

Dentro Contatti ho creato un folder Winshow Planning (nome del progetto), all’interno del quale ho creato tre subfolders (Agenti, Artisti e Luoghi). In ciascuno dei tre ho finalmente creato tanti ulteriori subfolders (presi dal database). Ogni folder contiene i contatti assegnati ad ogni categoria.

‘Sto post è davvero troppo lungo e prolisso. Se avete domande, sono qua a disposizione. 😉

Send to Kindle
.NET World

Dubbi, ragionamenti e quiz sull’Interop di Outlook 2007

1 ContactItem item = (ContactItem)folder.Items.Add(OlItemType.olContactItem); 2 MemberInfo[] mi1 = typeof(ContactItem).GetMembers(); 3 MemberInfo[] mi2 = item.GetType().GetMembers(); 4 5 Console.WriteLine(mi1.Length); 6 Console.WriteLine(mi2.Length); 7 8 // m1.Length = 0 9 // m2.Length = 7

L’istanza item è di tipo ContactItem. Se chiamo GetMembers() sul GetType() di questa istanza ottengo un’array di mi1.Length.

Se chiamo GetMembers() sul typeof(ContactItem) ottengo un’array di mi2.Length.

Il primo array contiene 0 elementi. Il secondo array contiene 7 elementi. Difatti, indagando più a fondo:

// item.GetType() --> {Name = "__ComObject" FullName = "System.__ComObject"} // typeof(ContactItem) --> {Name = "ContactItem" FullName = "Microsoft.Office.Interop.Outlook.ContactItem"}

Qualcuno sa perchè? Vi è già capitato? Avete percorso la mia stessa strada con risultati diversi?

Send to Kindle
.NET World

L’importanza di ereditare dall’applicazione giusta

Quando abbiamo imparato a programmare secondo la metodologia OOP, tutti, chi prima e chi dopo, abbiamo imparato che se ad esempio volessimo creare un nuovo controllo conviene ereditare da quello che più gli assomiglia ed implementare solo la parte richiesta. Quindi, se avessimo bisogno di una TextBox specializzata per lavorare con url, potremmo creare una classe UrlTextBox:

public class UrlTextBox : System.Windows.Forms.TextBox { }

E ancora, se avessimo bisogno di una Label particolare, mi potremmo creare uno UserControl che erediti da System.Windows.Forms.Label. E così via.

Una cosa di cui sento parlare poco negli ambienti virtuali che frequento è la possibilità di applicare lo stesso tipo di approccio anche con intere applicazioni, a patto che queste ‘intere applicazioni’ siano abbastanza amichevoli – passatemi il termine – per permettere a qualcun’altro di interagire con loro. Spesso noi programmatori abbiamo la tendenza a non pensare neanche ad una soluzione di questo tipo. Vogliamo partire completamente da zero nello sviluppo, più che altro per così sappiamo che avremo il pieno controllo di tutti gli strati applicativi.

Ora, lasciate che vi illustri uno scenario. Supponiamo di dover scrivere un’applicazione che fondamentalmente debba gestire un calendario. L’anagrafica è composta da artisti e locali. Il calendario conterrà appuntamenti, dove si esprime il fatto che un certo artista andrà in un certo locale in un certo periodo della giornata per cantare e ballare ed incassare tot euro. L’appuntamento avrà caratteristiche particolari: il compenso dell’artista, la sua provvisorietà o meno, l’agente, note varie, etc. etc. L’applicazione dovrà fornire all’utente una vista semestrale del calendario, artista per artista e locale per locale. L’applicazione dovrà avere un modulo di fatturazione, molti diversi tipi di report, e molto altro ancora.

Ma l’applicazione di cui sto parlando è fondamentalmente un calendario, al quale vengono applicate determinate restrizioni in alcuni casi. Quindi, mi stavo chiedendo, invece di scrivere tutto da zero, perchè non sfruttare ciò che già c’è. Perchè non partire da un’applicazione esistente, e restringere ciò che va ristretto, ed estendere ciò che va esteso? Perchè non scrivere una cosa del tipo…

public class MyApplication : Outlook { }

e lavorarci su con strumenti come Visual Studio Tools for Office ? Non è che si fa proprio così, ma è solo per rendere l’idea. Creare ribbon e toolbar, integrare plug-in capaci di fare tutto il necessario, capaci di incorporare al loro interno componenti realizzati con framework complessi come Windows Presentation Foundation.

Non è che le cose diventino pù semplici, magari fosse così, è solo che viene spostata la nostra attenzione, dal momento che l’applicazione host ci dà già alcuni servizi aggratis.

Meditate gente, meditate.

Send to Kindle
.NET World

Dipendenze indesiderate in progetto per Compact Framework che utilizzi P/Invoke

Questa mattina vi voglio rendere partecipi di un problema che ho riscontrato durante la creazione di un setup project per smart device, soprattutto se il progetto richiede l’utilizzo di P/Invoke. Questo problema causa la comparsa di una dipendenza verso l’assembly mscorlib.dll del .NET Framework 2.0, e di conseguenza la creazione di un pacchetto di installazione (CAB) un po’ più grande del dovuto.

Andiamo con ordine. Supponiamo di avere una solution composta da due progetti separati:

  1. una normale Device Application per PPC/WM (che chiameremo TestForDeploy)
  2. un Smart Device CAB Project che si occupa di installare l’applicazione al punto 1 (che chiameremo Deploy)

Il template dell’applicazione generato da Visual Studio (sia 2005 che 2008) crea un’applicazione perfettamente funzionante. C’è solo una Windows Form che lui chiama Form1. Di conseguenza, le dipendenze richieste da entrambi i progetti sono puliti e sono il minimo indispensabile.

Ho volutamente espansi i nodi References e Detected Dependencies per mostrare l’elenco degli assembly richiesti dall’uno e dall’altro progetto.

Ora supponiamo che la nostra applicazione TestForDeploy debba utilizzare una COM Library scritta in C++. Per farlo dobbiamo far uso di una tecnologia chiamata P/Invoke: in pratica di tratta di creare una classe wrapper che mappa tutte le funzioni esposte dalla libreria natina. Questa classe wrapper viene creata on-demand da Visual Studio nel momento in cui la aggiungiamo ai riferimenti. Otteniamo lo stesso risultato utilizzando il tool da linea di comando tlbimp.exe, che crea un’assembly .NET partendo da una .dll in native code.

Ora, supponiamo di avere una libreria in D:Temp e che essa si chiami ComLibrary.dll.

Nel momento in cui la aggiungiamo alle References richieste da TestForDeploy, cambiano un bel po’ di cose, come si vede dallo screenshot qui sotto:

Ho tracciato delle linee rosse per nascondere la libreria, il cui nome rileva informazioni che preferisco non divulgare.

Osservate le Detected Dependencies rilevate dal progetto di setup: esso contiene l’assembly mscorlib due volte. Uno è l’mscorlib.dll del Compact Framework, mentre l’altro è l’mscorlib.DLL del .NET Framework per Desktop. Il resto dei files è corretto: viene inclusa la libreria in native code e viene incluso l’assembly che contiene la classe wrapper.

Se mantenessimo le cose così come sono, il file .CAB installerebbe su PPC/WM anche l’assembly mscorlib.DLL del .NET Framework. Onestamente, non so dire cosa accade: so solo che il .CAB raddoppia le sue dimensioni (da circa 3Mb passa a 6Mb – proprio a causa di quella dipendenza in più).

Di chi è la colpa? Googlando ho trovato diverse informazioni sui forum di Microsoft. Sui post si legge che la creazione della classe wrapper (e quindi l’uso più o meno esplicito di tlbimp.exe) prevede la dipendenza da mscorlib.DLL. Quindi sembra essere un problema di questo tool. Ho provato a lanciarlo da linea di comando per vederne i parametri (l’avevo studiato per qualche esame di certificazione, ma chi se lo ricordava più??). Esiste un parametro /reference che serve per indicare uno o più assembly che tlbimp.exe deve utilizzare per risolvere la definizione dei tipi, ma non è servito a nulla.

L’unico possibile workaround è quello di escludere quel mscorlib.DLL dal progetto di setup. Come? Semplicemente cliccandoci sopra col destro e selezionando Exclude dal menù contestuale, come si vede qua sotto:

Purtroppo l’informazione su quali files escludere non è persistita da nessuna parte da Visual Studio. Ciò significa che la volta successiva in cui aprirete l’IDE vi ritroverete nuovamente quel file incluso, e non c’è verso di fargli capire che non lo si vuole installare.

La feature di Detected Dependencies è propria dell’IDE di Visual Studio. Perchè dico questo? Perchè se avete rimosso il file come vi ho fatto vedere e utilizzare il tool msbuild.exe per rigenerare il file .CAB per la vostra installazione, quel file a tutti gli effetti sparisce dal vostro CAB.

Dovete solo ricordarvi di toglierlo ogni volta, prima di rigenerare il CAB. Ritengo comunque che se il problema fosse gestito a monte, all’interno della classe wrapper per intenderci, sarebbe molto meglio.

Send to Kindle
.NET World

Debuggare il .NET Framework: quanti l’han fatto?

Oggi pomeriggio, parlando davanti alla macchinetta del caffè con due colleghi, ho ricordato loro che con Visual Studio 2008 è possibile vedere e debuggare i sorgenti del .NET Framework.

Scrissi un post il 19 Gennaio di quest’anno dove dicevo questa cosa, probabilmente appena scaricato Visual Studio 2008 dal mio abbonamento MSDN.

Dopo molti mesi mi chiedo: quanti hanno davvero avuto questa necessità? Credo una piccolissima parte. Certo, ci saranno esperti e guru in tutto il mondo che grazie a questa feature hanno scoperto bug o capito determinati comportamenti behind-the-scenes del .NET Framework, ma credo proprio che al 99% degli sviluppatori non abbia fatto nè caldo nè freddo.

Però dire che Microsoft ha dato questa impronta open-source ha un suo fascino, no?

Send to Kindle