Insérer un bloc depuis un DWG en AutoLISP

Un tutoriel pas à pas pour écrire votre code AutoLISP : insérez un bloc depuis un fichier DWG externe dans AutoCAD, sans jamais ouvrir le fichier source à l'écran

Allan Ransau
Allan RansauFondateur de RANSAU SYSTEME — Ingénieur & Développeur
26 juillet 20266 min de lecture
Image de couverture pour l'article Insérer un bloc depuis un DWG en AutoLISP

Développement

Automatisation

#autolisp

#tutoriel-autolisp

#objectdbx

#autocad

#dwg

#vla-copyobjects

#vlax-release-object

#automatisation-cao

#schema-unifilaire

Vous voulez insérer un bloc stocké dans un fichier DWG externe — une bibliothèque de blocs partagée, par exemple — sans ouvrir ce fichier dans AutoCAD. La commande OPEN ne sait pas le faire : elle attache le fichier à l'éditeur visible, fait clignoter l'écran et pollue votre session avec un dessin dont vous ne vouliez qu'un seul bloc. Et un vla-insertblock appelé directement sur le fichier externe n'est pas mieux : il insère tout le dessin comme un bloc imbriqué, qu'il faut ensuite exploser puis nettoyer.

La bonne solution s'appelle ObjectDBX. Dans ce tutoriel, vous allez écrire pas à pas une fonction AutoLISP qui :

  • ouvre le DWG externe en arrière-plan, sans jamais toucher l'éditeur ;
  • copie uniquement la définition du bloc voulu vers le dessin actif ;
  • insère le bloc au point demandé, avec un nettoyage COM garanti.

À la fin, vous disposerez d'une commande de test prête à lancer sur vos propres fichiers.

Prérequis

Avant de commencer, assurez-vous d'avoir :

  • AutoCAD complet — ObjectDBX n'existe pas sur AutoCAD LT ;
  • un DWG "bibliothèque" contenant au moins un bloc nommé, placé dans un dossier du chemin de recherche d'AutoCAD (onglet OPTIONS > Fichiers) ;
  • un éditeur de texte pour créer un fichier .lsp (le VLIDE intégré suffit).

Créez un fichier vide nommé insert-dbx.lsp : vous y collerez chaque fonction du tutoriel. Les fonctions COM (vla-..., vlax-...) exigent que l'ActiveX soit chargé, ajoutez donc cette ligne en tête du fichier :

lisp
(vl-load-com)

Étape 1 : créer l'instance ObjectDBX

ObjectDBX instancie une base de données annexe (side database) totalement invisible, dans laquelle on peut charger un DWG sans l'afficher. C'est l'ouverture "headless" que OPEN ne sait pas faire.

Ajoutez la fonction suivante à insert-dbx.lsp :

lisp
;; Crée une instance ObjectDBX headless.
;; Retourne : [vla] objet DBX, ou nil en cas d'échec
(defun RNS:dbx-create (/ acad dbx ver candidates id)
  (setq acad (vl-catch-all-apply 'vlax-get-acad-object nil))
  (if (vl-catch-all-error-p acad)
    (progn
      (princ "\n[ERROR] RNS:dbx-create: vlax-get-acad-object failed.")
      (exit))
  )
  ;; Version majeure ACADVER, ex "24", "25", "26"
  (setq ver (itoa (atoi (getvar "ACADVER"))))
  (setq candidates
    (list "ObjectDBX.AxDbDocument"
          (strcat "ObjectDBX.AxDbDocument." ver)
          "ObjectDBX.AxDbDocument.26"
          "ObjectDBX.AxDbDocument.25"
          "ObjectDBX.AxDbDocument.24"
          "ObjectDBX.AxDbDocument.23"
          "ObjectDBX.AxDbDocument.22")
    dbx nil
  )
  (while (and candidates (null dbx))
    (setq id         (car candidates)
          candidates (cdr candidates)
          dbx        (vl-catch-all-apply 'vla-getinterfaceobject (list acad id)))
    (if (vl-catch-all-error-p dbx) (setq dbx nil))
  )
  (if (null dbx)
    (princ "\n[ERROR] RNS:dbx-create: Could not create ObjectDBX instance.")
    dbx)
)

Deux choses à comprendre dans ce code :

  1. Le ProgID ObjectDBX.AxDbDocument dépend de la version d'AutoCAD installée (.26, .25...). La fonction déduit le bon suffixe de (getvar "ACADVER"), puis balaie une liste de candidats : elle fonctionne ainsi sur n'importe quel poste sans configuration manuelle.
  2. Chaque appel COM est enveloppé dans vl-catch-all-apply. Sans cela, un échec ObjectDBX interromprait le script sans aucun message exploitable.

Vérifiez : chargez le fichier avec APPLOAD, puis tapez (RNS:dbx-create) sur la ligne de commande. AutoCAD doit répondre quelque chose comme #<VLA-OBJECT IAxDbDocument ...>.

Étape 2 : charger le DWG externe dans l'instance

L'instance DBX est vide pour l'instant. La fonction suivante y charge votre fichier bibliothèque — c'est l'ouverture invisible proprement dite.

Ajoutez-la à votre fichier :

lisp
;; Charge un DWG externe dans une instance DBX existante.
;; dbx : [vla] objet créé par RNS:dbx-create — blk-file : [str] chemin résolu
(defun RNS:dbx-open (dbx blk-file / result)
  (setq result (vl-catch-all-apply 'vla-open (list dbx blk-file)))
  (if (vl-catch-all-error-p result)
    (progn
      (princ (strcat "\n[ERROR] RNS:dbx-open : Could not open \"" blk-file "\""))
      nil)
    dbx)
)

Vérifiez : rechargez le fichier, puis testez avec votre propre DWG :

lisp
(setq dbx (RNS:dbx-create))
(RNS:dbx-open dbx (findfile "ma-bibliotheque.dwg"))
(vlax-release-object dbx)

Si le chemin est valide, le deuxième appel retourne l'objet DBX au lieu de nil — et rien ne s'ouvre à l'écran.

Note : la dernière ligne du test n'est pas optionnelle. dbx est un objet COM créé hors du cycle de vie documentaire d'AutoCAD : il ne sera jamais libéré automatiquement. Non relâché, il fuit en mémoire et peut verrouiller le fichier source. Retenez le réflexe dès maintenant, il structure l'Étape 4.

Étape 3 : trouver et copier la définition du bloc

Le DWG est chargé en arrière-plan ; inutile d'en récupérer autre chose que le bloc visé. C'est tout l'intérêt face à vla-insertblock, qui ramène le fichier entier.

Ajoutez ces deux fonctions :

lisp
;; Trouve une définition de bloc nommée dans une base DBX ouverte.
(defun RNS:dbx-find-block (dbx block-name / src-blocks src-blk-def)
  (setq src-blocks  (vla-get-blocks dbx))
  (setq src-blk-def (vl-catch-all-apply 'vla-item (list src-blocks block-name)))
  (if (vl-catch-all-error-p src-blk-def)
    (progn
      (princ (strcat "\n[ERROR] RNS:dbx-find-block : Block \"" block-name "\" not found"))
      nil)
    src-blk-def)
)
 
;; Copie une définition de bloc unique depuis DBX vers le dessin actif.
(defun RNS:dbx-copy-block (dbx src-blk-def / active-doc dest-blocks obj-array result)
  (setq active-doc (vla-get-activedocument (vlax-get-acad-object))
        dest-blocks (vla-get-blocks active-doc))
  (setq obj-array (vlax-make-safearray vlax-vbObject '(0 . 0)))
  (vlax-safearray-put-element obj-array 0 src-blk-def)
  (setq result (vl-catch-all-apply 'vla-copyobjects (list dbx obj-array dest-blocks)))
  (if (vl-catch-all-error-p result)
    (progn
      (princ "\n[ERROR] RNS:dbx-copy-block : Failed to copy block definition")
      nil)
    T)
)

RNS:dbx-find-block cherche la définition par son nom dans la collection Blocks de la base annexe. RNS:dbx-copy-block construit ensuite un tableau COM (safearray) d'un seul élément — le bloc trouvé — et appelle vla-copyobjects pour le dupliquer vers le dessin actif. Aucune instance imbriquée, aucun passage par explode/delete.

Étape 4 : assembler la fonction d'insertion

Il reste à enchaîner les trois briques, avec deux garde-fous : ne pas rouvrir le DWG si le bloc est déjà présent localement, et libérer l'objet COM quoi qu'il arrive.

Ajoutez la fonction principale :

lisp
(defun RNS:insert-block-with-name
    (space block-filename block-name ins-point
     / blk-file dbx-obj src-blk-def pt result local-blocks local-exists copied)
  (setq blk-file (findfile block-filename))
  (setq local-blocks (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))))
 
  ;; Optimisation : si la définition existe déjà localement, on saute ObjectDBX
  (setq local-exists
    (not (vl-catch-all-error-p
           (vl-catch-all-apply 'vla-item (list local-blocks (strcase block-name))))))
 
  (if (not local-exists)
    ;; Pipeline ObjectDBX — dbx-obj est relâché dans le nettoyage garanti
    ;; ci-dessous, que les étapes précédentes réussissent ou échouent
    (if (setq dbx-obj (RNS:dbx-create))
      (progn
        (if (RNS:dbx-open dbx-obj blk-file)
          (if (setq src-blk-def (RNS:dbx-find-block dbx-obj block-name))
            (setq copied (RNS:dbx-copy-block dbx-obj src-blk-def))
          )
        )
        (vlax-release-object dbx-obj) ;; nettoyage garanti
      )
    )
  )
 
  ;; Insertion : si le bloc était déjà local, ou si la copie DBX a réussi
  (if (or local-exists copied)
    (progn
      (setq pt (vlax-3d-point ins-point))
      (setq result (vl-catch-all-apply 'vla-insertblock (list space pt block-name 1.0 1.0 1.0 0.0)))
      (if (vl-catch-all-error-p result)
        (princ (strcat "\n[ERROR] Failed to insert \"" block-name "\""))
        result
      )
    )
    (princ (strcat "\n[ERROR] Aborted, block \"" block-name "\" could not be loaded"))
  )
)

(Version allégée à des fins de lecture — validations d'entrée complètes disponibles dans la bibliothèque source.)

Suivez le déroulé :

  1. local-exists interroge d'abord la collection Blocks du dessin actif. Si le bloc y figure déjà, les Étapes 1 à 3 sont purement ignorées — ouvrir un DWG externe a un coût, autant ne le payer qu'une fois.
  2. Sinon, le pipeline ObjectDBX s'exécute : création, ouverture, recherche, copie. Le (vlax-release-object dbx-obj) est placé hors de tout bloc conditionnel : il s'exécute que la copie ait réussi ou échoué.
  3. Enfin, vla-insertblock place la définition — désormais locale — au point demandé.

Étape 5 : tester

Ajoutez une commande de test en fin de fichier, en adaptant le nom du DWG et celui du bloc à votre bibliothèque :

lisp
(defun RNS:test-insert (/ doc space)
  (setq doc   (vla-get-activedocument (vlax-get-acad-object))
        space (vla-get-modelspace doc))
  (RNS:insert-block-with-name space "ma-bibliotheque.dwg" "MON-BLOC" '(0.0 0.0 0.0))
  (princ)
)

Vérifiez : rechargez le fichier avec APPLOAD, puis tapez test-insert. Le bloc apparaît à l'origine du dessin, sans qu'aucune fenêtre ne se soit ouverte. Relancez la commande une seconde fois : l'insertion est instantanée, car la définition est désormais locale — c'est le contrôle local-exists qui joue. Vous pouvez maintenant insérer un bloc depuis un DWG externe en AutoLISP des centaines de fois dans une boucle, sans jamais rouvrir le fichier source.

Pour aller plus loin

Au-delà d'ObjectDBX, retenez surtout l'idée : tout ce qui est répétitif dans AutoCAD peut presque toujours être automatisé. Insérer des blocs, renseigner des attributs, générer des schémas complets — une routine LISP bien construite transforme des heures de manipulations manuelles en une seule commande, fiable et reproductible.

C'est exactement notre métier chez RANSAU SYSTEME. Ce pipeline, nous l'avons industrialisé pour ITEC Engineering sur une bibliothèque de blocs partagée de schéma unifilaire : découvrez le cas d'usage.

Vous avez une question sur ce tutoriel ? Une tâche de dessin répétitive que vous aimeriez automatiser ? Écrivez-nous : nous pouvons vous aider à concevoir et développer vos routines LISP et vos outils d'automatisation CAO, du script ponctuel à l'application métier complète.

Ce blog vous a été utile ?

Partagez cet article avec votre réseau

En bref

Ce tutoriel AutoLISP montre en cinq étapes comment insérer un bloc depuis un DWG externe sans jamais l'ouvrir dans AutoCAD : créer une instance ObjectDBX headless avec vla-getinterfaceobject, charger le fichier en arrière-plan avec vla-open, copier uniquement la définition du bloc voulu avec vla-copyobjects, assembler le tout dans une fonction avec contrôle du cache local et libération COM inconditionnelle (vlax-release-object), puis valider avec une commande de test RNS:test-insert. Chaque étape fournit le code complet et un point de vérification.

Ce qu'il faut retenir

  • Tutoriel en cinq étapes avec code complet : instance ObjectDBX headless, chargement du DWG en arrière-plan, copie ciblée de la définition du bloc, fonction d'insertion avec cache local, commande de test RNS:test-insert.
  • ObjectDBX crée une base de données annexe (side database) invisible pour charger un DWG externe sans jamais l'ouvrir dans l'éditeur AutoCAD — ce que la commande OPEN ne sait pas faire.
  • vla-copyobjects copie une seule définition de bloc vers le dessin actif ; vlax-release-object doit être appelé de façon inconditionnelle pour éviter les fuites COM.