Autodesk Inventor API Hacking (Rubberduckを使いたい)

# 0. はじめに
[Freeradical](https://www.freeradical.jp)の中の人、[yamarah](https://qiita.com/yamarah)です。
[Rubberduck](https://rubberduckvba.com/)良いですよね。VBAで作業するなら是非とも使いたいツールですが、InventorのVBAではうまく動作しません。
今回はいつもと趣向を変えて、RubberduckをInventorに対応させる方法について検討します。

# 1. そのままbuildする
まずは[本家のgithub](https://github.com/rubberduck-vba/Rubberduck/)からソースを入手します。
buildには、VisualStudio2019が必要でした。私の能力では、2022ではエラーを解消しきれませんでした。
また、`RubberduckTests\Inspections\ConstantNotUsedInspectionTests.cs`が文字エンコードの問題でerrorになったので、UTF-8で保存しなおす必要がありました。しかし、本当にUTF-8で保存しなおして良いのかは疑わしいです。テストのcodeのようなので、深追いせずこれで良しとします。
これらの問題は、日本語の開発環境が原因のように思われます。万全を期すなら、英語環境を構築してbuildすると良いと思います。
buildが成功すると、Installerが作られるのではなくWindowsのレジストリに登録されます。つまりはinstall後の状態になるようです。ですので、配布バイナリーをinstall済みでしたら、build前にuninstallしておくことをお勧めします。
# 2. Errorを追いかける
ちなみに、2019年ごろに試したときは、InventorのVBAには全く反応しなかったのですが、現在のバージョン(2.5.2.5906)だと配布バイナリーでも、とりあえずはInventorのVBAを認識ます。
しかし、Rubberduckの解析をリフレッシュすると、Resolver ErrorとなりRefactorを始めとする多くの機能が動作しません。
## Errorの原因を確認する
debuggerで追いかけると、RubberduckがInventorのAPIを舐めて内部辞書を作成する際に、`Circle`という名のclass(C#的にはstruct?)に遭遇すると例外送出 → Resolver Errorとなっていました。
構文解析のlibraryから例外送出されているので、直接の原因までたどり着けませんでしたが、Inventorがどうこうではなく、`Circle`という単語に反応しているようです。
試しに、vanillaのVBAで以下のcodeを試してみます。
``` VBA
Sub test()
  dim Circle as Object
End Sub
```
このcodeが既にVBAで構文エラー扱いになります。どうやら、`Circle`が何か特別扱いを受けているようです。
## `Circle`の扱い
そんな馬鹿な、という感じですが、ググって次の記事を発見しました。
[undocumented vba special keywords - Circle and Scale](https://stackoverflow.com/questions/22986017)
どうも起源はQuick Basicにまで遡るようで、その頃のkeywordが現代にまで受け継がれているのが原因のようです。`Line`などは、なぜO.K.になったのでしょうか・・・
# 3. 対策
先に書いた通り、Rubberduckが参照している全てのdllの名前を舐めて内部辞書を作るようなので、その際に`Color`を登録しようとしたら一律スキップするようにしました。
```C#:TypeAnnotationPass.cs
public void Execute(IReadOnlyCollection<QualifiedModuleName> modules)
{
    var toDetermineAsTypeDeclaration = _declarationFinder
                                        .FindDeclarationsWithNonBaseAsType()
                                        .Where(decl => decl.AsTypeDeclaration == null 
                                                || modules.Contains(decl.QualifiedName.QualifiedModuleName));
    foreach (var declaration in toDetermineAsTypeDeclaration)
    {
+       if (declaration.CustomFolder == "Inventor" && 
+           declaration.AsTypeName == "Circle")
+       {
+           continue;
+       }
        AnnotateType(declaration);
    }
}
```
対処療法なので、本当にスキップして良いのか、副作用が無いのか分からないですが、今のところは問題なく動作しています。

# 4. ついでに
`Rubberduck.VBEditor.VBA\SafeComWrappers\Application`に`AutoCADApp.cs`など、アプリケーションごとのfileがあったので、見よう見まねでInventor用を作成しました。
```C#:InventorApp.cs
using Rubberduck.VBEditor.SafeComWrappers.Abstract;

// ReSharper disable once CheckNamespace - Special dispensation due to conflicting file vs namespace priorities
namespace Rubberduck.VBEditor.SafeComWrappers.VBA
{
    public class InventorApp : HostApplicationBase<Inventor.Application>
    {
        public InventorApp(IVBE vbe) : base(vbe, "Inventor", true) { }
    }
}
```
また、これを参照すべく、`Rubberduck.VBEditor.VBA\SafeComWrappers\VB\VBE.cs`を修正しました。修正内容は割愛します。
この登録に何の作用があるのか分からないですが、`AutoCAD`や`SolidWorks`も登録しているので、同じようにしておきました。

# 99. 親の記事に戻る
[Autodesk Inventor API Hacking (概略)](https://qiita.com/yamarah/items/cee08eb8f2b7aecbda83)