VBA AutoCAD : annuler la commande en cours

Si vous pilotez AutoCAD depuis un autre processus via l'API COM, votre code ne peut s'exécuter que si AutoCAD est disponible, c'est à dire qu'il n'y a pas une commande en cours d'exécution. C'est pour cela que l'API COM fournit une méthode GetAcadState sur l'objet Application qui permet de vérifier si AutoCAD est disponible de cette façon :

Dim state As AcadState
Set state = acadApp.GetAcadState()
If Not state.IsQuiescent Then
  MsgBox "AutoCAD n'est pas disponible."
  Exit Sub
End If

Le mieux dans ce cas, c'est de demander à l'utilisateur de stopper lui-même la commande en cours dans AutoCAD.

Si vous voulez annuler automatiquement la commande, il faut simuler deux appuis sur la touche Echap. On a besoin de 2 Echap car il peut y avoir une commande transparente en cours, en plus d'une autre commande.

Le moyen le plus simple pour simuler des appuis sur une touche en VBA/VB, c'est d'utiliser la fonction SendKeys. Le seul problème c'est que SendKeys envoie ces frappes clavier à l'application qui a le focus. Il faut donc amener la fenêtre au premier plan. Pour cela, on peut utiliser la fonction SetForegroundWindow de l'API Windows :

Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long

[..]

Dim state As AcadState
Set state = acadApp.GetAcadState()
If Not state.IsQuiescent Then
  SetForegroundWindow acadApp.HWND32
  SendKeys "{ESC}", True
End If

Bon malheureusement, ça ne marche pas que pour une commande. J'ai beau doubler le ESC, pour une raison que j'ignore, il n'y en a qu'un seul qui est pris en compte.

J'ai aussi essayé d'envoyer le Echap via SendMessage et PostMessage, mais ça ne marche pas.

Le temps me manque pour aujourd'hui, je reviendrai là dessus donc un peu plus tard...

Mise à jour du 13/01/2014 : j'ai essayé à nouveau aujourd'hui, même le SendKeys ne fonctionne pas à tous les coups. Et j'ai essayé de reproduire la séquence de messages WM_KEYDOWN et WM_KEYUP via PostMessage, ça ne marche pas non plus...

Le code utilisé :

Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" _
  (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
  ByVal lParam As Long) As Long

Const WM_KEYDOWN = &H100
Const WM_KEYUP = &H101

Public Sub CancelActiveCommand()
    Dim acadApp As AcadApplication
    Set acadApp = GetObject(, "AutoCAD.Application")
    PostMessage acadApp.HWND32, WM_KEYDOWN, &H1B, &H10001
    PostMessage acadApp.HWND32, WM_KEYUP, &H1B, &HC0010001
End Sub

J'utilise l'handle de la fenêtre principale d'AutoCAD. Normalement, le message doit être distribué à la ligne de commande. J'ai essayé également avec le handle de cette dernière, je n'ai pas eu plus de succès. Certainement un problème de focus ou d'activation de fenêtre.

Mise à jour 2 du 13/01/2014 : d'après sa documentation, SendKeys a un problème de timing. J'ai réussi à envoyer 2 Echap consécutifs en pausant entre les 2 appels comme ceci :

SendKeys "{ESC}", True
Application.Wait Time + TimeSerial(0, 0, 1)
SendKeys "{ESC}", True

Comme ça, ça fonctionne. Si une commande transparente est en cours en plus d'une commande standard, les 2 commandes sont annulées et l'exécution de la macro peut se poursuivre immédiatement.

Cependant je déconseille cette approche. Premièrement parce qu'elle s'appuie sur une temporisation (on ne sait pas exactement combien il faut laisser de temps entre les 2 appels à SendKeys, même si avec une seconde, ça devrait être suffisant) et deuxièmement rien ne garantit que les 2 Echap vont permettre de stopper la commande en cours (si une ou plusieurs boite de dialogue sont affichées, les deux Echap n'auront probablement pas l'effet escompté).

En plus de cela, annuler une commande brutalement sans demander l'avis de l'utilisateur peut entraîner une perte de données. Il faut donc mieux selon moi afficher un message expliquant le problème et laisser l'utilisateur agir en conséquence.

Etiquettes:

Ajouter un commentaire