Aller au contenu

C# Process Autocad invisible


Messages recommandés

Bonjour,

 

je suis en train de créer une application en c# qui va chercher des informations dans un dwg choisi par l'utilisateur.

A priori, il ne semble pas possible de récupérer les données d'un fichier dwg sans lancer Autocad (si quelqu'un a une astuce, je suis preneur !! ).

 

J'utilise donc ce code pour lancer le processus Autocad avec le plan choisi par l'utilisateur :

Process acadProcess = new Process();
acadProcess.StartInfo.Arguments = string.Format("/nologo /p \"{0}\"", profileName);
acadProcess.StartInfo.FileName = (@dialog.FileName);
acadProcess.Start();
acadProcess.WaitForInputIdle();
acApp = (AcadApplication)Marshal.GetActiveObject(progID);

 

Jusque là pas de problème !! Maintenant, pour que l'opération soit transparente pour l'utilisateur, j'aurai souhaité qu'Autocad, ne soit pas visible. J'ai donc essayé en rajoutant ces lignes :

acadProcess.StartInfo.UseShellExecute = false;
acadProcess.StartInfo.CreateNoWindow = true;
acadProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

 

Mais celà ne fonctionne pas :( . Siquelqu'un sait comment procéder, cela me serait d'une grand utilité :)

 

Merci d'avance

 

Goldorak

PIRO Charles

Developpeur Revit, RV/RA - Formateur Revit

PIRO CIE

Lien vers le commentaire
Partager sur d’autres sites

Salut,

 

Il me semble que tu fais fausse route. L'API .NET d'AutoCAD n'est accessible que depuis un processus AutoCAD (In-Process).

 

Je crois qu'il est plus préférable récupérer une instance d'AutoCAD en cours ou d'en créer une nouvelle en utilisant l'interface COM (voir ici).

 

Un petit exemple qui remplit un ListView dans un formulaire avec les blocs trouvé dans l'espace objet du fichier sélectionné.

Le code utilise le type dynamic (Framework 4.0) pour ne pas être dépendant des librairies COM AutoCAD.

 

        private void buttonOpen_Click(object sender, EventArgs e)
       {
           listViewBlocks.Items.Clear();
           if (!File.Exists(textBoxFile.Text))
           {
               MessageBox.Show(string.Format("Le fichier '{0}' est introuvable", textBoxFile.Text));
               return;
           }
           dynamic acadApp;
           try
           {
               acadApp = Marshal.GetActiveObject("AutoCAD.Application");
           }
           catch
           {
               try
               {
                   acadApp = Activator.CreateInstance(System.Type.GetTypeFromProgID("AutoCAD.Application"));
               }
               catch
               {
                   MessageBox.Show("Impossible d'ouvrir AutoCAD");
                   return;
               }
           }

           WaitForAcadIsQuiescent(acadApp);

           acadApp.Visible = false;

           Dictionary<string, int> blocks = new Dictionary<string, int>();
           dynamic acadDoc = acadApp.Documents.Open(textBoxFile.Text);

           WaitForAcadIsQuiescent(acadApp);

           foreach (dynamic ent in acadDoc.ModelSpace)
           {
               if (ent.ObjectName == "AcDbBlockReference")
               {
                   string name = ent.EffectiveName;
                   if (blocks.ContainsKey(name))
                       blocks[name]++;
                   else
                       blocks.Add(name, 1);
               }
           }
           acadDoc.Close(false);
           foreach (var pair in blocks)
           {
               listViewBlocks.Items.Add(new ListViewItem(new string[] { pair.Key, pair.Value.ToString() }));
           }
       }

       private void WaitForAcadIsQuiescent(dynamic acadApp)
       {
           while (true)
           {
               try
               {
                   dynamic state = acadApp.GetAcadState();
                   if (state.IsQuiescent)
                       break;
               }
               catch { }
           }
       }

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Petite question : tu utilise un type dynamic (Framework 4.0), est-ce compatible avec une version autocad 2010/2011 utilisant le framework 3.5 ?

 

Le problème n'est pas tant la version d'AutoCAD.

On peut très bien avoir AutoCAD 2010 ou 2011 (qui installent le Framework 3.5) et avoir installé le Framework 4.0 par ailleurs. Dans ce cas, le type dynamic est utilisable.

 

Pour ma part, je préfère toujours cibler le Framework correspondant à la version d'AutoCAD visée.

donc, dans le cas de A2010/2011, le Framework 3.5.

 

L'utilisation du type dynamic permet d'écrire un code plus lisible (le même aux types près que si on on utilisait le typage fort en référençant les biblothèques COM). Mais on peut très bien faire quelque chose d'équivalent en utilisant la liaison tardive avec Reflection.

 

L'inconvénient de la liaison précoce (typage fort) c'est qu'il faut référencer les biliothèques COM de la version d'AutoCAD ciblée. L'avantage, c'est que l'intellisense de Visual Studio nous aide pour les méthodes et propriétés des objets.

La méthode que j'utilise ets de finaliser le code en liaison précoce, puis de supprimer les références à l'interface COM d'AutoCAD et de remplacer les types COM par dynamic (FW 4.0) ou object (FW 3.5).

 

Exemple de code d'une application console pour ouvrir un fichier dans une instance d'AutoCAD (ici 2011) en liaison précoce (il faut référencer les bibliothèques Autodesk.AutoCAD.Interop et Autodesk.AutoCAD.Interop.Common de la version ciblée)

 

using System;
using System.IO;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;

namespace EarlyBinding
{
   class Program
   {
       static void Main()
       {
           Console.WriteLine("Entrez le chemin du fichier à ouvrir : ");
           string filename = Console.ReadLine();
           if (!File.Exists(filename))
           {
               Console.WriteLine("Impossible de trouver le fichier spécifié");
           }
           else
           {
               Console.WriteLine("Patientez...");
               AcadApplication acadApp = null;
               try
               {
                   acadApp = (AcadApplication)Marshal.GetActiveObject("AutoCAD.Application.18.1");
               }
               catch
               {
                   try
                   {
                       acadApp = (AcadApplication)Activator.CreateInstance(System.Type.GetTypeFromProgID("AutoCAD.Application.18.1"));
                   }
                   catch
                   {
                       Console.WriteLine("Impossible de trouver ou de créer une instance d'AutoCAD");
                   }
               }
               if (acadApp != null)
               {
                   WaitForAcadIsQuiescent(acadApp);
                   AcadDocument acDoc = acadApp.Documents.Open(filename);
                   WaitForAcadIsQuiescent(acadApp);
                   AcadModelSpace mspace = acDoc.ModelSpace;
                   Console.WriteLine("{0} entités dans l'espace objet.", mspace.Count);
               }
           }
           Console.ReadLine();
       }

       static void WaitForAcadIsQuiescent(AcadApplication acadApp)
       {
           while (true)
           {
               try
               {
                   AcadState state = acadApp.GetAcadState();
                   if (state.IsQuiescent)
                       break;
               }
               catch { }
           }
       }
   }
}

 

La même chose en utilisant le type dynamic, ici on n'est plus lié à une version d'AutoCAD mais il faut que le Framework 4.0 soit installé.

 

using System;
using System.IO;
using System.Runtime.InteropServices;

namespace Dynamic
{
   class Program
   {
       static void Main(string[] args)
       {
           Console.WriteLine("Entrez le chemin du fichier à ouvrir : ");
           string filename = Console.ReadLine();
           if (!File.Exists(filename))
           {
               Console.WriteLine("Impossible de trouver le fichier spécifié");
           }
           else
           {
               Console.WriteLine("Patientez...");
               dynamic acadApp = null;
               try
               {
                   acadApp = Marshal.GetActiveObject("AutoCAD.Application");
               }
               catch
               {
                   try
                   {
                       acadApp = Activator.CreateInstance(System.Type.GetTypeFromProgID("AutoCAD.Application"));
                   }
                   catch
                   {
                       Console.WriteLine("Impossible de trouver ou de créer une instance d'AutoCAD");
                   }
               }
               if (acadApp != null)
               {
                   WaitForAcadIsQuiescent(acadApp);
                   dynamic acDoc = acadApp.Documents.Open(filename);
                   WaitForAcadIsQuiescent(acadApp);
                   dynamic mspace = acDoc.ModelSpace;
                   Console.WriteLine("{0} entités dans l'espace objet.", mspace.Count);
               }
           }
           Console.ReadLine();
       }

       static void WaitForAcadIsQuiescent(dynamic acadApp)
       {
           while (true)
           {
               try
               {
                   dynamic state = acadApp.GetAcadState();
                   if (state.IsQuiescent)
                       break;
               }
               catch { }
           }
       }
   }
}

 

La même chose en utilisant la liaison tardive et Reflection. Comme avec le type dynamic, on n'est plus lié à une version d'AutoCAD. L'inconvénient de cette méthode, c'est la lourdeur du code pour appeler une propriété ou une méthode :

obj.GetType().InvokeMember(...)

Pour palier à ça on peut utiliser des méthodes d'extensions qui rendent le code un peu plus digeste.

 

using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;

namespace LateBinding
{
   class Program
   {
       static void Main(string[] args)
       {
           Console.WriteLine("Entrez le chemin du fichier à ouvrir : ");
           string filename = Console.ReadLine();
           if (!File.Exists(filename))
           {
               Console.WriteLine("Impossible de trouver le fichier spécifié");
           }
           else
           {
               Console.WriteLine("Patientez...");
               object acadApp = null;
               try
               {
                   acadApp = Marshal.GetActiveObject("AutoCAD.Application.18");
               }
               catch
               {
                   try
                   {
                       acadApp = Activator.CreateInstance(System.Type.GetTypeFromProgID("AutoCAD.Application.18"));
                   }
                   catch
                   {
                       Console.WriteLine("Impossible de trouver ou de créer une instance d'AutoCAD");
                   }
               }
               if (acadApp != null)
               {
                   WaitForAcadIsQuiescent(acadApp);
                   object acDoc = acadApp.Get("Documents").Invoke("Open", filename);
                   WaitForAcadIsQuiescent(acadApp);
                   object mspace = acDoc.Get("ModelSpace");
                   Console.WriteLine("{0} entités dans l'espace objet.", mspace.Get("Count"));
               }
           }
           Console.ReadLine();
       }

       static void WaitForAcadIsQuiescent(object acadApp)
       {
           while (true)
           {
               try
               {
                   object state = acadApp.Invoke("GetAcadState");
                   if ((bool)state.Get("IsQuiescent"))
                       break;
               }
               catch { }
           }
       }
   }

   static class Extension
   {
       public static object Get(this object obj, string propName)
       {
           return obj.GetType().InvokeMember(propName, BindingFlags.GetProperty, null, obj, new object[0]);
       }

       public static void Set(this object obj, string propName, object value)
       {
           obj.GetType().InvokeMember(propName, BindingFlags.SetProperty, null, obj, new object[1] { value });
       }

       public static object Invoke(this object obj, string methName, params object[] parameters)
       {
           return obj.GetType().InvokeMember(methName, BindingFlags.InvokeMethod, null, obj, parameters);
       }
   }
}

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Merci beaucoup pour ces 3 exemples.

Concernant l'application (simple exercice d'apprentissage !!!) je pense que le type dynamic est le plus adapté car on est pas lié à une version d'Autocad et la syntaxe reste "simple".

Seul inconvénient, le manque d'intellisense (ce qui est logique), il faut donc très bien connaitre ce que l'on cherche !! Cela demande un peu d'entrainement.

Je commence avec les exemple de l'aide Autodesk et des articles de Kean Walmsley.

 

Je pense que j'aurai bientôt de nouvelle questions !!! :P

PIRO Charles

Developpeur Revit, RV/RA - Formateur Revit

PIRO CIE

Lien vers le commentaire
Partager sur d’autres sites

Tu peux procéder comme je l'indiquais plus haut.

Tu développes ton code en référençant les bibliothèques Autodesk.AutoCAD.Interop et Autodesk.AutoCAD.Interop.Common correspondant à la version d'AutoCAD que tu utilises pour déboguer, ainsi tu as l'intellisense pendant la phase de développement.

Une fois ton programme abouti (si tant est qu'un programme puisse être abouti), tu supprimes ces références et tu remplaces tous les types COM (qui ne sont plus reconnus par Visual Sudio) par 'dynamic'.

Attention avec les enumérations, avant de supprimer les référence, il faut connaitre l'entier qui correspond à la valeur de l'énumération (dans Visual Studio, double clic sur la valeur de l'énumération et F12).

 

Exemple, typage fort :

AcadDocument acDoc = acadApp.ActiveDocument;
acDoc.Regen(AcRegenType.acActiveViewport);

Typage dynamique :

dynamic acDoc = acadApp.ActiveDocument;
acDoc.Regen(0);

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

La méthode que j'utilise ets de finaliser le code en liaison précoce, puis de supprimer les références à l'interface COM d'AutoCAD et de remplacer les types COM par dynamic (FW 4.0) ou object (FW 3.5).

 

Effectivement tu me l'indiquais plus haut !!! :unsure:

 

Merci pour la méthode. :)

PIRO Charles

Developpeur Revit, RV/RA - Formateur Revit

PIRO CIE

Lien vers le commentaire
Partager sur d’autres sites

  • 2 semaines après...

Nouvelle petite question ! Si je créer une instance, lors de la fermeture d'autocad (acadDoc.Close();), Autocad se ferme bien mais dans le gestionnaire de tache, il y a toujours un processus AutoCAD.exe de présent.

 

Comment couper ce processus ?

 

Pour les autres logiciels, j'utilise l'interop et je coupe la liaison via Marchal.FinalRealiseObject. Cela fonctionne si autocad est déjà lancé au moment de l’exécution de mon application mais pas lors de lorsqu'il y a création de l'instance.

PIRO Charles

Developpeur Revit, RV/RA - Formateur Revit

PIRO CIE

Lien vers le commentaire
Partager sur d’autres sites

Salut,

 

Pour fermer proprement AutoCAD,


     
  1. je ferme le document avec acDoc.Close() en passant true pour enregistrer les modifications ou false pour ne pas enregistrer
  2. je ferme AutoCAD : acadApp.Quit()

 

Tu peux utiliser une variable de type bool pour savoir si un processus existait déjà (auquel cas on ne le ferme pas) ou s'il a fallu en créer un (auquel cas, on le ferme.

 

using System;
using System.IO;
using System.Runtime.InteropServices;

namespace Dynamic
{
   class Program
   {
       static void Main(string[] args)
       {
           Console.WriteLine("Entrez le chemin du fichier à ouvrir : ");
           string filename = Console.ReadLine();
           if (!File.Exists(filename))
           {
               Console.WriteLine("Impossible de trouver le fichier spécifié");
           }
           else
           {
               Console.WriteLine("Patientez...");
               dynamic acadApp = null;
               bool created = false;
               try
               {
                   acadApp = Marshal.GetActiveObject("AutoCAD.Application");
               }
               catch
               {
                   try
                   {
                       acadApp = Activator.CreateInstance(System.Type.GetTypeFromProgID("AutoCAD.Application"));
                       created = true;
                   }
                   catch
                   {
                       Console.WriteLine("Impossible de trouver ou de créer une instance d'AutoCAD");
                   }
               }
               if (acadApp != null)
               {
                   WaitForAcadIsQuiescent(acadApp);
                   dynamic acDoc = acadApp.Documents.Open(filename);
                   WaitForAcadIsQuiescent(acadApp);
                   dynamic mspace = acDoc.ModelSpace;
                   Console.WriteLine("{0} entités dans l'espace objet.", mspace.Count);
                   if (created)
                   {
                       acDoc.Close(false); // Fermer le document sans sauvegarder
                       acadApp.Quit(); // Fermer AutoCAD (arrête le processus)
                       Console.WriteLine("AutoCAD fermé");
                   }
               }
           }
           Console.ReadLine();
       }

       static void WaitForAcadIsQuiescent(dynamic acadApp)
       {
           while (true)
           {
               try
               {
                   dynamic state = acadApp.GetAcadState();
                   if (state.IsQuiescent)
                       break;
               }
               catch { }
           }
       }
   }
}

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité