Microsoft Office Automation in C#

Interprocess communication (IPC) (ovvero la possibilità di far comunicare i processi in esecuzione tra loro) è sempre stato uno degli aspetti centrali nella progettazione delle applicazioni (e dei sistemi operativi). Se provassimo ad immaginare un mondo (un mondo "piccolo", un sistema operativo) in cui le applicazioni non potessero comunicare tra loro, ebbene in tale mondo non esisterebbero neanche le più comuni funzionalità che siamo tanto abituati ad utilizzare quali copia/incolla, drag&drop e così via; od ancora, non sarebbe nemmeno possibile collegarsi ad internet col nostro browser preferito e così via dicendo.
Probabilmente oggi nessuno vorrebbe un sistema operativo del genere.

Negli anni sono state sviluppate varie tecniche IPC sia in ambiente PC che UNIX, dal mappaggio della memoria, alla memoria condivisa (con l'uso di semafori per l'accesso alle risorse ) ai socket per comunicare con applicazioni remote e via dicendo.
Scambiare informazioni tra applicazioni scritte in linguaggi di programmazione differenti però comportava un lavoro di porting non indifferente; un'applicazione server scritta in C++ mal comunicava con un client scritto per esempio in Visual Basic per via di modelli di threading differenti o per il tipo intrinseco di dato condiviso (un array di chars in C++ non ha lo stesso significato di una string in Visual Basic) per non parlare delle differenti calling conventions etc.

Per limitare questo tipo di problemi è stato inventato IDL (Interface Definition Language), un linguaggio descrittivo universale col quale le applicazioni server (COM) dichiarano interfacce, proprietà, metodi e tipi di dati che andranno ad essere condivisi, in base ad uno standard compatibile con qualunque client capace di comprendere IDL (coè in pratica tutti i linguaggi di sviluppo).

Ad un certo punto Microsoft "toglie dal suo cilindro" OLE Automation (oggi Automation). Inventa cioè il modo per consentire alle applicazioni di manipolare "oggetti" di altre applicazioni, nonchè alle stesse di esporre i propri oggetti ai clients in ascolto non solo nel sistema operativo locale ma anche in sistemi remoti usando il modello COM.

Le applicazioni di Microsoft Office sono Automation Server, cioè espongono attraverso COM diverse loro funzionalità.
Ogni altra applicazione Automation Client può perciò, sempre via COM, comunicare con queste ed usare così oggetti e funzioni di Microsoft Office (ovvero di Word, Excel etc.).


Vediamo come impaginare in Microsoft Word una lettera, un' ipotetica richiesta di ferie (vacanze ? magari...) direttamente dalla nostra applicazione C#:

Creiamo un nuovo progetto C# Class Library in Visual Studio 2015.



Rinominiamo la classe che ci ha creato Visual Studio di default, per esempio CRunWord.





Aggiungiamo al progetto un Reference a Microsoft Word typelib.







Aggiungiamo un nuovo progetto Windows Form (per testare la nostra DLL)



Aggiungiamo un reference alla DLL



Ora possiamo implementare il client automation.

Il codice che scriverò è molto diretto e non credo servano particolari spiegazioni oltre ai commenti nel sorgente stesso.

Implementiamo la classe nella DLL

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


using WordApp = Microsoft.Office.Interop.Word;


namespace CRunWord
{
    public class CRunWord
    {
       public CRunWord() // costruttore predefinito
        {
            Mittente.cognome   = "";
            Mittente.nome      = "";
            Mittente.indirizzo = "";
            Mittente.citta     = "";
            Mittente.cap       = "";
            Mittente.tel       = "";
           
            ///////////////////////////////
            
            Destinatario.cognome   = "";
            Destinatario.nome      = "";
            Destinatario.indirizzo = "";
            Destinatario.citta     = "";
            Destinatario.cap       = "";
            Destinatario.tel       = "";
            Destinatario.titolo    = "";
            Destinatario.ufficio   = "";
           

            m_nGiorniFerie         = 0;
            m_strGiorni            = "";
        }
    

      public tag_Mittente Mittente;
      public tag_Destinatario Destinatario;
    

      public struct tag_Mittente
        {
     
         public string cognome,
                       nome,
                       indirizzo,
                       citta,
                       cap,
                       tel;
        }
       
     
      public struct tag_Destinatario
        {
         
         public  string cognome,
                   nome,
                   indirizzo,
                   citta,
                   cap,
                   tel,
                   titolo,
                   ufficio;
        }
        


        private int m_nGiorniFerie;
        public int SetNumGiorniFerie
        {
            get { return m_nGiorniFerie; }
            set { m_nGiorniFerie = value;}
        }
      

      
        private string m_strGiorni;
        public string SetStrGiorniFerie
        {
            get { return m_strGiorni; }
            set { m_strGiorni = value;}
        }
        


        //WordApp 
        private WordApp.Application wapp = null;



        public void SendDataToAutomationServer()
        {
            wapp = new WordApp.Application() { Visible = true };
            object missing = System.Reflection.Missing.Value;
            WordApp.Document doc = new WordApp.Document();
            wapp.Options.Overtype = false;
           
            doc.Paragraphs.Alignment = WordApp.WdParagraphAlignment.wdAlignParagraphRight;
            doc.Content.SetRange(0, 0);
            WordApp.Paragraph phf = doc.Content.Paragraphs.Add(Type.Missing);
            doc.Paragraphs.SpaceAfter = 0;
            doc.Paragraphs.SpaceBefore = 0;
            //Dati del destinatario
            phf.Range.Bold = 1;
            phf.Alignment = WordApp.WdParagraphAlignment.wdAlignParagraphRight;
            phf.Range.Paragraphs.SpaceBefore = 0;
            phf.Range.Paragraphs.SpaceAfter = 0;
            phf.Range.Text += Destinatario.titolo;     //"Eg. Sig. Direttore";
            phf.Range.Text += Destinatario.ufficio;    //"Riga descrizione ufficio";
            // phf.Range.Bold = 0;
            phf.Range.Text += Destinatario.indirizzo;      //"Riga indirizzo ufficio";
            phf.Range.Text += Destinatario.cap + " " + Destinatario.citta ;  //"Riga città ufficio";
            phf.Range.InsertParagraphAfter();
            phf.Alignment = WordApp.WdParagraphAlignment.wdAlignParagraphLeft;
         
            
            
            //Dati del mittente
            phf.Range.Text = "Mittente:" + Environment.NewLine;
         
            phf.Range.Paragraphs.SpaceBefore = 0;
            phf.Range.Paragraphs.SpaceAfter = 0;
            //  phf = doc.Content.Paragraphs.Add(Type.Missing);
            phf.Range.Bold = 0;
            phf.Range.Text = Mittente.cognome + " " + Mittente.nome;   //"Riga del nome e cognome";
           //  phf.Range.InsertParagraphAfter();
            phf.Range.Text += Mittente.indirizzo;  //"Riga dell'indirizzo";
            // phf.Range.InsertParagraphAfter();
            phf.Range.Text += Mittente.cap + " "  + Mittente.citta;//"Riga della città";
            phf.Range.InsertParagraphAfter();
          
            //Spazio per l'oggetto 
            // phf = doc.Content.Paragraphs.Add(Type.Missing);
            //phf.Range.Bold = 1;
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Range.Bold = 1;
            phf.Alignment = WordApp.WdParagraphAlignment.wdAlignParagraphLeft;
            phf.Range.Text = "OGGETTO: DOMANDA FERIE ORDINARIE GIORNI: " + m_strGiorni;
            //phf.Range.Bold = 1;
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Alignment = WordApp.WdParagraphAlignment.wdAlignParagraphLeft;
            phf.Range.Bold = 0;
            phf.Range.Text = "     Si richiede al Sig. Direttore dell' Ufficio in indirizzo la fruizione di n. " + m_nGiorniFerie.ToString() + " gg. di ferie di cui in oggetto";
            phf.Range.Text += "secondo il seguente calendario: " + m_strGiorni + ".";
            phf.Range.Text += "\n\n";
            phf.Range.Text += "Si coglie l'occasione per porgere distinti saluti.";
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Alignment = WordApp.WdParagraphAlignment.wdAlignParagraphLeft;
            phf.Range.Text = Mittente.citta + ",  " + DateTime.Now.ToShortDateString();
            phf.Range.InsertParagraphAfter();
            phf.Alignment = WordApp.WdParagraphAlignment.wdAlignParagraphRight;
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Range.InsertParagraphAfter();
            phf.Range.Text = "_______________________________________";
            phf.Range.Text += "(firma)";
           
        }
        



        //Close Automation Server
        public void CloseServer()
        {
            try
            {
               
                wapp.Application.Quit(Type.Missing);
            }
            catch
            {
            }
        }
    }
}

            



Implementiamo l'applicazione di test:

Nell'applicazione di prova i campi di testo sono inseriti dall'utente, ma immaginiamo che invece provengano da un database:




using System;
using System.Windows.Forms;


namespace TestRunWord
{
    public partial class Form1 : Form
    {
        CRunWord.CRunWord RunWord;
       

        public Form1()
        {
            InitializeComponent();
            RunWord = new CRunWord.CRunWord();
            
        }
       

       private void button3_Click(object sender, EventArgs e)
        {
            RunWord = null;
            Application.Exit();
        }
      

       private void button1_Click(object sender, EventArgs e)
        {
            
            RunWord.Mittente.cognome       = textBox1.Text;
            RunWord.Mittente.nome          = textBox2.Text;
            RunWord.Mittente.indirizzo     = textBox4.Text;
            RunWord.Mittente.citta         = textBox3.Text;
            RunWord.Mittente.cap           = textBox6.Text;
            RunWord.Mittente.tel           = textBox5.Text;
           

            RunWord.Destinatario.cognome   = textBox12.Text;
            RunWord.Destinatario.nome      = textBox11.Text;
            RunWord.Destinatario.indirizzo = textBox10.Text;
            RunWord.Destinatario.citta     = textBox9.Text;
            RunWord.Destinatario.cap       = textBox8.Text;
            RunWord.Destinatario.tel       = textBox7.Text;
            RunWord.Destinatario.titolo    = textBox14.Text;
            RunWord.Destinatario.ufficio   = textBox13.Text;
           

            RunWord.SetNumGiorniFerie = 365;
            RunWord.SetStrGiorniFerie = "dal 1° gennaio al 31 dicembre";
            

            RunWord.SendDataToAutomationServer();
            
        }
       

        private void button2_Click(object sender, EventArgs e)
        {
            RunWord.CloseServer();
        }
    }
}




Questo è il risultato che avremo facendo click sul bottone RunWord:




E questa è la lettera impaginata da Word per nostro conto:






Processing request, please wait...


download Office Automation Tutorial ver. 1.0.0  exe 

HASH codes:

  • MD5 : 55 89 26 3b f4 fc c6 8c 71 27 23 90 f2 62 23 b5
  • SHA1 : b8 2c bc 7b 14 fa 18 ed 86 32 84 36 ef 60 f0 15 b9 6c af 1a
  • SHA256 : e4 8b 08 77 d2 45 9d c5 bb 38 f8 35 d3 21 49 37 89 bd 8b b3 d2 3b 1d f7 bc 1d eb b1 d2 7b 07 92





Giuseppe Pischedda, novembre 2016.


Se il post ti è piaciuto puoi fare una donazione all'autore, l'importo è a tua libera scelta.

Grazie