Générer un document Microsoft Word (C#)Date de publication : 12/11/2004
Par
Jean-Alain Baeyens (autres articles)
Comment créer, modifier un document Word depuis une application C#
et ce y compris le transfert d'informations au format Rtf.
Remerciements
1. Introduction
2. Préparation
3. Connecter et déconnecter votre application à Word
4. Ajouter et sauver un document sur base d'un modèle particulier
5. Remplir des champs de formulaire
6. Transférer du texte formaté
7. Le code complet
Remerciements
Je remercie Piotrek (désolé, je ne connais que son pseudo) pour ses
précieuses informations , J-M RABILLOUD pour son tutoriel,
"Pilotage Microsoft OFFICE", qui m'a bien aidé, Thomas Lebrun et
sjrd (même remarque que pour Piotrek)
pour l'oeil attentif qu'ils ont bien voulu prêter à ce document ainsi
qu'à mon épouse que l'informatique n'amuse pas mais qui a
néanmoins relu ce document afin qu'il vous soit présenté dans les
meilleures conditions.
1. Introduction
Ce document se veut un exposé pratique mais non exhaustif des
techniques à mettre en oeuvre pour compléter un document Word
depuis un programme C# en pilotant directement Word.
2. Préparation
Avant de passer à la programmation proprement dite, il y a lieu
d'ajouter une référence à Word dans votre projet.
La communication entre votre application et Word se fera au moyen
de la technologie OLE Automation. Toutefois, ceci sera complètement pris
en charge par les dll que nous allons référencer.
Dans Visual Studio : pour ajouter cette référence, allez dans
Projet>Ajouter une référence>Onglet COM et sélectionnez
Microsoft Word xx.x Object Library.
Dans SharpDevelop : Dans votre projet, cliquez avec le bouton
droit sur Reference>Ajouter une référence, Onglet COM et
sélectionnez Microsoft Word xx.x Object Library.
Dans mon cas, la version était 11.0.
Les dll Interop.VBIDE.dll et Interop.Word.dll sont maintenant
ajoutées à votre projet.
3. Connecter et déconnecter votre application à Word
Microsoft.Office.Interop.Word.Application msWord = new Microsoft.Office.Interop.Word.Application();
msWord.Visible = false;
object missing = System.Reflection.Missing.Value;
....
msWord.Quit(ref missing, ref missing, ref missing); |
Ce code comme tout le code qui suivra est finalement très
simple. Vous pouvez toutefois voir 2 points particuliers.
- La définition de l'objet missing. Celui-ci sera
régulièrement utilisé pour remplacer les paramètres inutilisés.
- La présence de ref. Les méthodes définies dans
l'interface de Word s'attendent généralement à recevoir en
paramètre des références à des objets.
4. Ajouter et sauver un document sur base d'un modèle particulier
Nous allons maintenant créer un document sur base d'un modèle
précédemment défini dans Word et se nommant "Mon Template" et le
sauver sous le nom de "Mon nouveau document".
 |
Le template utilisé se trouve dans le répertoire des templates
de Word et non avec l'application. Il vous est toujours possible
de spécifier un chemin différent. De même, sans indication contraire
le document est sauvé dans le répertoire spécifié dans Word.
|
Microsoft.Office.Interop.Word.Document nvDoc ;
object templateName = @"Mon Template.dot" ;
nvDoc = msWord.Documents.Add(ref templateName, ref missing, ref missing,
ref missing) ;
...
object fileName = @"Mon nouveau document.doc" ;
nvDoc.SaveAs(ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing) ;
nvDoc.Close(ref missing, ref missing, ref missing) ; |
Si vous souhaitez pouvoir également réaliser des modifications
dans un document précédemment créé, nous pouvons adapter le code
comme suit:
object fileName = @"Mon nouveau document.doc" ;
Microsoft.Office.Interop.Word.Document nvDoc ;
if (System.IO.File.Exists((string)fileName))
{
nvDoc = msWord.Documents.Open(ref fileName, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing);
}
else
{
object templateName = @"Mon Template.dot" ;
nvDoc = msWord.Documents.Add(ref templateName, ref missing, ref missing,
ref missing) ;
}
...
nvDoc.SaveAs(ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing) ;
nvDoc.Close(ref missing, ref missing, ref missing) ; |
Même dans le cas d'une modification du fichier, nous continuons
à utiliser la méthode SaveAs.
5. Remplir des champs de formulaire
Pour ajouter automatiquement des informations à des endroits
bien précis dans votre document, vous pouvez utiliser des champs
de formulaire (FormFields). Si vous placez ces champs de
formulaire dans une section protégée avec un mot de passe
(protection en mode formulaire) et que vous décochez l'option
"Fill in" des différents champs, une fois le document généré,
l'utilisateur ne pourra pas modifier les données remplies
automatiquement. De même, par programme vous pouvez ouvrir le
document et mettre à jour les valeurs sans altérer le reste du
document. Toutefois, vous constaterez que lorsque le document
est ainsi protégé, un certain nombre de fonctionnalités sont
retirées à l'utilisateur.
object field = "Nom" ;
nvDoc.FormFields.get_Item(ref field).Result = "Mon nom" ;
field = "Prenom" ;
nvDoc.FormFields.get_Item(ref field).Result = "Mon prénom" ; |
 |
Le champ de formulaire doit exister sinon c'est le
plantage. C'est pourquoi il est conseillé de placer chaque
chargement de champ dans un try/catch. Une autre solution
consiste à utiliser la méthode "Exist" de la classe bookmarks.
En effet à chaque champ de formulaire est associé un signet.
Cette solution, bien que séduisante, est imparfaite car si vous
aurez toujours un signet associé à votre champ de formulaire,
le signet pourrait exister sans qu'il soit associé à un champ de
formulaire.
|
 |
Si vous n'êtes pas un adepte du try/catch et que vous voulez une
solution sans risque, vous pouvez charger tous les noms des
champs de formulaire dans une hashtable après l'ouverture du
document et ensuite vérifier la présence du nom dans la
hashtable avant de remplir le champ. Pour récupérer les noms,
il vous suffit d'utiliser la collection FormFields et la
propriété Name de chaque Formfield.
|
Une alternative à l'utilisation des champs de formulaire est
d'utiliser "Bookmark" et "Range". Mais dans ce cas, il sera
beaucoup plus difficile de mettre en oeuvre la modification d'un
document déjà généré (voir la technique utilisée dans
"Transférer du texte formaté").
Vous êtes maintenant capable de transférer du contenu dans votre
document mais il ne s'agit que de texte non formaté.
6. Transférer du texte formaté
Aucune méthode ou propriété des objets de Word ne permet de
transférer directement du texte au format rtf de votre
application à Word. Nous allons devoir faire intervenir un
élément supplémentaire, le clipboard.
Pour envoyer du contenu au clipboard, il suffit d'utiliser:
string monContenu = "Le texte que je transfère";
Clipboard.SetDataObject(monContenu, false) ; |
mais dans ce cas, le contenu est considéré comme du texte simple.
Nous allons devoir signaler au clipboard que le contenu est du
type rtf. Nous disposons pour cela de la classe DataObject.
string monContenu = @"{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl
{\f0\fswiss\fcharset0 Arial;}{\f1\fnil\fcharset0 Arial;}
{\f2\fmodern\fprq1\fcharset0 Courier;}}
{\colortbl ;\red0\green0\blue0;}
{\*\generator Msftedit 5.41.15.1503;}
\cf1\b\i\f2 Le texte que je transfère\cf0\b0\i0\f0}" ;
DataObject clipData = new DataObject(DataFormats.Rtf, monContenu) ;
Clipboard.SetDataObject(clipData, false) ; |
Le contenu est dans le clipboard. Il ne nous reste plus qu'à le
rapatrier dans notre document. Pour l'exemple, j'ai placé un
signet dans le modèle à l'endroit ou doit être inséré mon texte.
Il me suffit alors de faire:
field = "TexteRtf" ;
nvDoc.Bookmarks.get_Item(ref field).Range.Paste(); |
Vous pouvez de la même manière, intégrer des images, du texte
html et bien d'autres (Voir DataFormats).
Attention si votre signet se trouve dans une section protégée,
il sera nécessaire de déprotéger et de reprotéger le document.
field = "TexteRtf" ;
object pwd = "LeMotDePasse";
nvDoc.Unprotect(ref pwd);
nvDoc.Bookmarks.get_Item(ref field).Range.Paste();
object noReset = true;
nvDoc.Protect2002(Microsoft.Office.Interop.Word.WdProtectionType.wdAllowOnlyFormFields,
ref noReset, ref pwd); |
Malheureusement, seule la moitié de l'objectif est ainsi atteinte.
En effet, s'il s'agit d'un nouveau document, alors tout est pour
le mieux. Par contre, s'il s'agit d'un document préexistant,
vous constaterez que le texte ne remplace pas l'ancien texte
mais se place devant.
Les différentes techniques que j'ai essayées, soit ne
détruisaient pas le texte antérieur, soit détruisaient le signet.
En définitive, la solution est d'utiliser non pas un mais deux
signets. Le texte devant être placé entre les deux signets.
object pwd = "LeMotDePasse";
nvDoc.Unprotect(ref pwd);
field = "TexteRtf" ;
object fieldEnd = "FinTexteRtf";
object posStart = nvDoc.Bookmarks.get_Item(ref field).Start;
object posEnd = nvDoc.Bookmarks.get_Item(ref fieldEnd).End;
nvDoc.Range( ref posStart, ref posEnd).Select();
msWord.Selection.Paste();
nvDoc.Bookmarks.Add((string)fieldEnd, ref missing);
object noReset = true;
nvDoc.protect2002(Microsoft.Office.Interop.Word.WdProtectionType.wdAllowOnlyFormFields,
ref noReset, ref pwd); |
Il est nécessaire après la copie du texte de redéfinir le signet de
fin sinon il reste en début de chaîne et lors de la prochaine
modification, le texte existant ne sera pas correctement remplacé.
Remarquez que nous n'avons plus utilisé la méthode Paste de la
classe Range mais bien celle de la classe Selection. En effet, la
méthode paste ne déplace pas le curseur. Dès lors, il nous est
impossible de replacer correctement le signet. Par contre en passant
par la méthode Select, le curseur est correctement positionné en fin
de chaîne.
Notez également que la méthode paste s'applique sur Selection qui
est directement une propriété de l'objet msWord (type Application)
bien que cette sélection ait été réalisée sur l'object nvDoc
(type Document).
7. Le code complet
Microsoft.Office.Interop.Word.Application msWord = new Microsoft.Office.Interop.Word.Application();
msWord.Visible = false;
object missing = System.Reflection.Missing.Value;
object fileName = @"Mon nouveau document.doc" ;
Microsoft.Office.Interop.Word.Document nvDoc ;
if (System.IO.File.Exists((string)fileName))
{
nvDoc = msWord.Documents.Open(ref fileName, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing);
}
else
{
object templateName = @"Mon Template.dot" ;
nvDoc = msWord.Documents.Add(ref templateName, ref missing, ref missing, ref missing) ;
}
object field = "Nom" ;
nvDoc.FormFields.get_Item(ref field).Result = "Mon nom" ;
field = "Prenom" ;
nvDoc.FormFields.get_Item(ref field).Result = "Mon prénom" ;
string monContenu = @"{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl
{\f0\fswiss\fcharset0 Arial;}{\f1\fnil\fcharset0 Arial;}
{\f2\fmodern\fprq1\fcharset0 Courier;}}
{\colortbl ;\red0\green0\blue0;}
{\*\generator Msftedit 5.41.15.1503;}
\cf1\b\i\f2 Le texte que je transfère\cf0\b0\i0\f0}" ;
DataObject clipData = new DataObject(DataFormats.Rtf, monContenu) ;
Clipboard.SetDataObject(clipData, false) ;
object pwd = "LeMotDePasse";
nvDoc.Unprotect(ref pwd);
field = "TexteRtf" ;
object fieldEnd = "FinTexteRtf";
object posStart = nvDoc.Bookmarks.get_Item(ref field).Start;
object posEnd = nvDoc.Bookmarks.get_Item(ref fieldEnd).End;
nvDoc.Range( ref posStart, ref posEnd).Select();
msWord.Selection.Paste();
nvDoc.Bookmarks.Add((string)fieldEnd, ref missing);
object noReset = true;
nvDoc.Protect2002(Microsoft.Office.Interop.Word.WdProtectionType.wdAllowOnlyFormFields,
ref noReset, ref pwd);
nvDoc.SaveAs(ref fileName, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing) ;
nvDoc.Close(ref missing, ref missing, ref missing) ;
msWord.Quit(ref missing, ref missing, ref missing); |
 
Les sources présentées sur cette page sont libres de droits,
et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation
constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright ©
. Aucune reproduction,
même partielle, ne peut être faite de ce site et de l'ensemble de son contenu :
textes, documents, images, etc sans l'autorisation expresse de l'auteur.
Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
Cette page est déposée à la
SACD.
|