
InventorのAPIを用いたカスタマイズ処理からInventorのコマンドを実行することは出来ないか?というお問い合わせが時折あります。APIが公開されていないが、コマンドでは提供されている機能を実装したいなどの場合に回避としてコマンドを実行したい場合や、処理を自身で開発する必要がない等、様々な動機があるかと思われます。
そこで今回は、InventorのコマンドをAPIから実行する方法について解説をしたいと思います。
APIからコマンドを実行する方法
結論から申し上げますと、InventorのコマンドをAPIから実行することは可能です。例として以下は「スケッチライン」コマンドを実行するVBAのサンプルコードとなります。
InventorのAPIでは、Inventorのコマンド(デフォルトのコマンドやアドインで作成したコマンド)は全て、ControlDefinition オブジェクトとして表されております。コマンドを実行したい場合、コマンドに対応するControlDefinition オブジェクトを取得し、取得したControlDefinition オブジェクトのExecute()メソッドを実行するだけです。
Public Sub RunLineCommand()
' Get the CommandManager object.
Dim oCommandMgr As CommandManager
Set oCommandMgr = ThisApplication.CommandManager
' Get control definition for the line command.
Dim oControlDef As ControlDefinition
Set oControlDef = oCommandMgr.ControlDefinitions.Item( _
"SketchLineCmd")
' Execute the command.
Call oControlDef.Execute
End Sub
コマンド名の取得方法
サンプルコードを見ていただくと、CommandManagerオブジェクトからControlDefinitionオブジェクトを取得する際にコマンド名を指定しています。すべてのControlDefinitionは、自身を識別するための一意の名前(=コマンド名)を持っています。では、APIから実行したいコマンドのコマンド名は、どのようにして特定すればよいでしょうか?
コマンド名の特定方法は大きく2つあります。一つ目は以下の様なVBAコードを実行する方法です。以下のVBAコードを実行するとC:\tempフォルダ配下に、CommandNames.txtというファイルを出力します。ファイル内にはコードの実行時にInventor内に登録されているすべてのコマンド名とその説明が出力されます。
Sub PrintCommandNames()
' Get the CommandManager object.
Dim oCommandMgr As CommandManager
Set oCommandMgr = ThisApplication.CommandManager
' Get the collection of control definitions.
Dim oControlDefs As ControlDefinitions
Set oControlDefs = oCommandMgr.ControlDefinitions
' Open the file and print out a header line.
Dim oControlDef As ControlDefinition
Open "C:\temp\CommandNames.txt" For Output As #1
Print #1, Tab(10); "Command Name"; Tab(75); _
"Description"; vbNewLine
' Iterate through the controls and write out the name.
For Each oControlDef In oControlDefs
Print #1, oControlDef.InternalName; Tab(55); _
oControlDef.DescriptionText
Next
' Close the file.
Close #1
End Sub
もう一つの方法は、Inventor SDKのDeveloperToolに付属のEventWatcherを利用する方法です。EventWatcherは、Inventor のSDKフォルダ配下(通常C:\Users\Public\Documents\Autodesk\Inventor 20XX\SDK)にあるdevelopertools.msiをインストールすると、C:\Users\Public\Documents\Autodesk\Inventor 20XX\SDK\DeveloperTools\Tools フォルダ配下に展開されます。このEventWatcherは起動中のInventorに接続し、Inventorエディタのイベントを監視し、どんなイベントが発生しているかを見ることが出来るツールとなります。
EventWatcherを用いると、以下の様な手順でコマンド名を確認することが出来ます。
1.Inventorを起動し、対象のコマンドが実行できる状態とする
2.C:\Users\Public\Documents\Autodesk\Inventor 2009\SDK\DeveloperTools\Tools\EventWatcher\bin\Release配下にあるEventWatcher.exeを起動する。
3.起動したEventWatcherで、UserInputEvents.OnActivateCommandにチェックボックスを入れてイベントの監視を開始します。このイベントはコマンドの開始時に発行されるイベントとなります。
4.Inventor上で、対象のコマンドを実行します。コマンドを実行すると、EventWatcherの画面上にコマンド名が出力されるはずです。
もし、コマンド名が表示されない場合はEventWatcherがInventorに正しく接続できていない可能性があります。UserInputEvents.OnActivateCommand以外のイベントを監視対象(チェックボックスを入れる)として、Inventorを操作し他のイベントが取得できているかを確認してみてください。もし他のイベントも取得できていない場合はInventorおよびEventWatcherを再起動してもう一度実行してみてください。
もし、他のイベントは取得できていて、それでも対象のコマンドのUserInputEvents.OnActivateCommandだけが取得できていないような状況の場合、対象の処理がコマンドではなく、後述するコマンドの機能である可能性が高い状況です。残念ながらこの場合には、APIから実行することが出来ないものと思われます。
コマンド実行後のパラメータのユーザ入力について
この方法を用いることで、APIからコマンドを実行し処理を自動化することが出来るのでは?と感じられた方もいらっしゃるかと思いますが、実はこの方法には制限があります。例として「押し出し」コマンドの様なコマンドを、APIから実行した場合どのようになるかを考えてみたいと思います。
ご承知の様に、InventorのGUIで押し出しコマンドを実行するとダイアログが表示され、このダイアログでは押し出し対象のジオメトリや押し出し方向、押し出す距離 等のパラメータを指定することで押し出しフィーチャーを作成することが出来ます。では、これらのダイアログの入力をAPIから指定することが出来るのでしょうか?残念ながら答えは、否でありこれらのパラメータをAPIから指定することは出来ません。
また別の場合には、「押し出し」フィーチャーの編集として押し出しの方向を変える処理(押し出しのダイアログ上では押し出し方向を指定するアイコンをクリックする)をAPIから実行したい場合があるかもしれません。ではこの押し出しの方向の指定は、前述のコマンド名の取得で対応するコマンドを取得できるでしょうか?残念ながらこちらも答えは、否で、押し出し方向をAPIから指定することは出来ません。
実は、InventorのAPIの観点から見ると「押し出し」コマンド実行時に表示されるダイアログ内の入力パラメータの指定は「押し出し」コマンド自身の機能として実装されている物であり、コマンドの扱いではありません。Inventor APIのControlDefinitionオブジェクトは、ControlDefinitionオブジェクトに対応するコマンドを実行することは出来ますが、各コマンド内の機能を実行することは出来ません。
コマンドへの入力指定について
先ほど、コマンドの機能として指定しているパラメータ等についてはAPIから指定することが出来ない と申し上げましたが、例外的に指定できる場合あります。
そのうちの一つ名が、処理対象の入力エンティティの指定です。もし対象のコマンド側が対応している場合、APIでのコマンド実行前に対象のエンティティを選択しておいてからコマンドを実行することで、選択中のエンティティを対象にコマンドを実行することが出来る場合があります。
以下は、寸法を整列するコマンドを実行するVBAのサンプルコードなります。コマンド実行前に対象のエンティティをSelectSetに追加して選択状態とし、選択されたエンティティを対象にコマンドを実行しております。
Public Sub ArrangeDimensions()
' Get the active document, assuming it is a drawing.
Dim oDrawDoc As DrawingDocument
Set oDrawDoc = ThisApplication.ActiveDocument
' Get the collection of dimensions on the active sheet.
Dim oDimensions As DrawingDimensions
Set oDimensions = oDrawDoc.ActiveSheet.DrawingDimensions
' Get a reference to the select set and clear it.
Dim oSelectSet As SelectSet
Set oSelectSet = oDrawDoc.SelectSet
oSelectSet.Clear
' Add each dimension to the select set to select them.
Dim oDrawDim As DrawingDimension
For Each oDrawDim In oDimensions
oSelectSet.Select oDrawDim
Next
' Get the CommandManager object.
Dim oCommandMgr As CommandManager
Set oCommandMgr = ThisApplication.CommandManager
' Get control definition for the arrange dimensions command.
Dim oControlDef As ControlDefinition
Set oControlDef = oCommandMgr.ControlDefinitions.Item( _
"DrawingArrangeDimensionsCmd")
' Execute the command.
Call oControlDef.Execute
End Sub
ただし、コマンドによってはこの方法でも上手くいかない場合があることにご留意ください。例えばフィレットコマンドなどにおいては事前選択されたエンティティがあっても、対象のエンティティを追加することが出来るようになっているため、たとえ事前選択のエンティティを用意しておいたとしてもダイアログが表示されてしまいます。
もう一つの例外はファイル名の指定です。コマンドの中には入力としてファイル名を受け付けるコマンドがあります。こういったコマンドの中にはファイル名プリセットしておくことによりファイル名の指定をスキップすることのできるコマンドが存在します。ただしこの方法もコマンド側の実装によるため、ファイル名を事前に指定した場合においてもダイアログを表示するコマンドもあります。なお、ファイル名の事前指定には、CommandManagerのPostPrivateEvent を利用します。以下は、コンポーネント配置を実行するVBAのサンプルコードとなります。CommandManagerのPostPrivateEventで指定したファイルが利用されるため、ファイルの指定ダイアログでのファイル選択をスキップすることが出来ます。
Public Sub PlacePart()
' Get the command manager.
Dim oCommandMgr As CommandManager
Set oCommandMgr = ThisApplication.CommandManager
' Post the filename.
Call oCommandMgr.PostPrivateEvent(kFileNameEvent, _
"C:\temp\Part1.ipt")
' Get control definition for the place component command.
Dim oControlDef As ControlDefinition
Set oControlDef = oCommandMgr.ControlDefinitions.Item( _
"AssemblyPlaceComponentCmd")
' Execute the command.
Call oControlDef.Execute
End Sub
APIからのコマンドの同期実行・非同期実行について
ここまでにご案内しておりますControlDefinition オブジェクトのExecute()メソッドは、コマンドを実行するとコマンドの終了を待たずに、処理が即座にプログラムに戻ります(非同期処理)。カスタマイズの内容によってはコマンドの終了を待ち合わせてから処理を行いたい場合などがあるかと思いますが、この場合はControlDefinition オブジェクトのExecute2()メソッドに、引数にTrueを指定して実行することにより、起動したコマンドの終了を待ち合わせることが可能となります。
※本記事は、「Running Commands Using the API」から、転写・意訳・補足したものです。
By Takehiro Kato

Leave a Reply