Autodesk Community Tips- ADNオープン
Autodesk Community Tipsではちょっとしたコツ、やり方、ショートカット、アドバイスやヒントを共有しています。
ソート順:
Issue 任意のタイミングで、開いている図面に共通画層があるかどうかチェックして、画層がなかった際に追加したいと考えています。    ... private DocumentCollection docs = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager; public void Initialize() { docs.DocumentActivated += new DocumentCollectionEventHandler(OnDocumentActivated); } public void Terminate() { docs.DocumentActivated -= OnDocumentActivated; } public void OnDocumentActivated(object sender, DocumentCollectionEventArgs e) { if (e.Document != null) { Database db = e.Document.Database; Document doc = e.Document; doc.LockDocument(); using (Transaction tr = db.TransactionManager.StartTransaction()) { LayerTable? tbl = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable; string name = "Main"; if (!tbl.Has(name)) { LayerTableRecord rec = new LayerTableRecord(); rec.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(ColorMethod.ByAci, 3); rec.Name = name; tr.GetObject(db.LayerTableId, OpenMode.ForWrite); tbl.Add(rec); tr.AddNewlyCreatedDBObject(rec, true); } db.Clayer = tbl[name]; tr.Commit(); } } } ...   この際、ユーザーには上記の図面編集を意識させたくないため、図面に編集を加えなかったときには図面保存ダイアログの表示はさせたくありません。(イベントハンドラーで画層追加すると、図面タブで表示図面を切り替えたりすると、図面保存のダイアログが表示されるようです。)     新規図面が対象ではないので、図面テンプレート(.dwt)が使用出来ません。 何かいい方法はありますか?   Solution 図面の編集有無はシステム変数 DBMOD の値が 0 以外になっているか否かで判定されています。DBMOD は読み取り専用のシステム変数ですが、Document.PushDbmod メソッド と Document.PopDbmod メソッドを利用すると、両メソッド呼び出し間の処理を無効化して DBMOD の値を 0 に復元することが出来ます。   下記は、その使用例を示す C# コードです。   public void OnDocumentActivated(object sender, DocumentCollectionEventArgs e) { if (e.Document != null) { Database db = e.Document.Database; Document doc = e.Document; doc.LockDocument(); doc.PushDbmod(); using (Transaction tr = db.TransactionManager.StartTransaction()) { LayerTable? tbl = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable; string name = "Main"; if (!tbl.Has(name)) { LayerTableRecord rec = new LayerTableRecord(); rec.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(ColorMethod.ByAci, 3); rec.Name = name; tr.GetObject(db.LayerTableId, OpenMode.ForWrite); tbl.Add(rec); tr.AddNewlyCreatedDBObject(rec, true); } db.Clayer = tbl[name]; tr.Commit(); } doc.PopDbmod(); } }  
記事全体を表示
Issue 比較的時間のかかるカスタム コマンドがあります。内部でループ制御による反復処理をしていますが、ESC キー押下で処理をキャンセルさせる実装にすることは出来ますか?   Solution AutoCAD 2011 以降、HostApplicationServices.UserBreak メソッドで、物理的な ESC キーの押下を検出することが出来るようになっています。ESC キーが押下されると同メソッドが true を返すので、例外を発生させるなどして処理を中断することが可能です。   [CommandMethod("MyCommand", CommandFlags.Modal)] public static void MyCommand() { ProgressMeter pm = new ProgressMeter(); pm.Start("Long process"); pm.SetLimit(100); try { for (int i = 0; i < 1000; i++) { if (HostApplicationServices.Current.UserBreak()) throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.UserBreak, "ESCAPE pressed"); pm.MeterProgress(); System.Threading.Thread.Sleep(100); } } catch (Autodesk.AutoCAD.Runtime.Exception ex) { Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.Message); } finally { pm.Stop(); } }  
記事全体を表示
Issue Editor.GetNestedEntity(PromptNestedEntityOptions) メソッドを利用して作図空間のブロック参照内の要素オブジェクトを直接選択、取得することが出来ますが、取得した要素オブジェクトからブロック名を得ることは出来ますか?   Solution 選択した要素オブジェクトの DBObject.OwnerId プロパティで、同オブジェクトのコンテナ オブジェクト、この場合、ブロック定義(BlockTableRecord)オブジェクトを取得ことが出来ます。その後、SymbolTableRecord.Name プロパティからブロック名を得ることが出来ます。      Database db = HostApplicationServices.WorkingDatabase; Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; PromptNestedEntityOptions peo = new PromptNestedEntityOptions("\nブロック参照を選択:"); PromptEntityResult pent = ed.GetNestedEntity(peo); if (pent.Status != PromptStatus.OK) { return; } using (Transaction tr = db.TransactionManager.StartTransaction()) { Entity ent = (Entity)tr.GetObject(pent.ObjectId, OpenMode.ForRead); ed.WriteMessage("\nObject Type : " + ent.GetType().ToString()); BlockTableRecord blkDef = (BlockTableRecord)tr.GetObject(ent.OwnerId, OpenMode.ForRead); ed.WriteMessage("\nBlock Name : " + blkDef.Name); tr.Commit(); }
記事全体を表示
Issue REVCLOUD コマンド Object オプションを AutoCAD 上に入力して作成した雲マークには、「円弧の長さ」プロパティが表示されますが、同じ内容を AutoCAD .NET API から呼び出して作成した雲マークには、「円弧の長さ」プロパティが表示されません。     コマンドプロンプトで指定したコマンドは次の内容です。     一方、AutoCAD .NET API から呼び出しは、次のようになります。   Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; PromptEntityResult pent = ed.GetEntity("\nオブジェクトを選択:"); if (pent.Status == PromptStatus.OK) { ed.Command("REVCLOUD", "O", pent.ObjectId, "N"); }   この違いはなぜ生まれるのでしょうか? AutoCAD .NET API から作成した雲マークに同じように「円弧の長さ」プロパティを表示する方法はありますか?   Solution REVCLOUD コマンドは過去に数回機能強化されていて、 AutoCAD 2021で「円弧の長さ」プロパティが追加されています。AutoCAD は、アドインを含む古いスクリプトからの REVCLOUD コマンド呼び出しの互換性を維持する必要するため、コマンドの呼び出し元の環境に応じて、内部でコマンド バージョンを切り替える処理をしています。 今回の場合、ユーザーインターフェース(UI)から呼び出された REVCLOUD コマンドは内部コマンドバージョン 3 で実行されています。一方、アドインから同じコマンドを呼び出すと、内部コマンドバージョン 1 を使用して雲マークを作成します。この違いが、「円弧の長さ」プロパティの表示有無の結果を生んでいます。 アドインから REVCLOUD コマンドを呼び出す場合、次のようにコマンド呼び出しの直前に Editor.InitCommandVersion メソッドを用いて内部コマンドバージョンを切り替えることが出来ます。この処理で「円弧の長さ」プロパティを持つ内部コマンドバージョン 3 を実行することが出来ます。   Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; PromptEntityResult pent = ed.GetEntity("\nオブジェクトを選択:"); if (pent.Status == PromptStatus.OK) { Application.DocumentManager.MdiActiveDocument.Editor.InitCommandVersion(3); ed.Command("REVCLOUD", "O", pent.ObjectId, "N"); }
記事全体を表示
Issue AutoCAD のユーザー インターフェース上に開いている現在のアクティブな図面(MDI 子ウィンドウにフォーカスが当たっている表示中の図面)を Database.SaveAs(string, DwgVersion)  メソッドで保存しようとしても、図面ウィンドウ上の図面タイトルが指定した名前に変化しません。 SAVEAS コマンドと同等の挙動を実現したいのですが、どうすればいいでしょうか?     Solution Database.SaveAs メソッドには、次の3つのオーバロード メソッドが用意されています。 Database.SaveAs(string, Autodesk.AutoCAD.DatabaseServices.SecurityParameters) Database.SaveAs(string, DwgVersion) Method | Autodesk Database.SaveAs(string, [MarshalAs(UnmanagedType.U1)] bool, DwgVersion, Autodesk.AutoCAD.DatabaseServices.SecurityParameters) あいにく、いずれのオーバロード メソッドも SAVEAS コマンドに対応した動作を完全に実現するものではなく、同コマンドの実装の一部分を担う機能しか実装されていない状態です。   図面ウィンドウ上の図面タイトルが指定した名前を反映させる方法として Database.SaveAs(string, [MarshalAs(UnmanagedType.U1)] bool, DwgVersion, Autodesk.AutoCAD.DatabaseServices.SecurityParameters) のオーバーロード バージョンの第2パラメーターを true を指定する方法があります。ただし、この方法も SAVEAS コマンドと同等の動作をするものではありません。   完全に SAVEAS コマンドと同じ挙動を得るには、SAVEAS コマンドをそのまま呼び出す必要があります。   次の例は、Editor.Command メソッドで SAVEAS コマンドを呼び出すものです。   [CommandMethod("MyCommand1", CommandFlags.Modal)] public void MyCommand1() { Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; if (doc != null) { string path = @"C:\temp\Test.dwg"; int filedia = System.Convert.ToInt32(Application.GetSystemVariable("FILEDIA")); Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("FILEDIA", 0); if (System.IO.File.Exists(path)) { ed.WriteMessage("\n指定したフォルダに同じ名前の図面ファイルが既に存在しています"); string check_path = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("DWGPREFIX").ToString(); check_path = check_path + Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("DWGNAME").ToString(); if (path == check_path) { ed.WriteMessage("\n開いている同じ名前の図面ファイルで上書きします..."); ed.Command("SAVEAS", "2018", path); } else { ed.WriteMessage("\n開いている図面で上書きします..."); ed.Command("SAVEAS", "2018", path, "Y"); } } else { ed.WriteMessage("\n指定したフォルダに初めて指定した名前で図面ファイルを保存します..."); ed.Command("SAVEAS", "2018", path); } Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("FILEDIA", filedia); } }   通常の SAVEAS コマンドでは、保存先のパスとファイル名を指定する際にファイル ダイアログが表示されてしまうので、FILEDIA システム変数でその表示を抑止しています。また、保存先のパスに同じファイル名の図面が存在した場合、アクティブな現在の図面の状態によって上書き保存の可否を指定するプロンプト オプションが異なるため注意が必要です。
記事全体を表示
Issue モデル空間やペーパー空間(レイアウト)の作図領域の背景色は、[オプション] ダイアログの [表示] タブからアクセス出来る [作図ウィンドウの色] ダイアログから変更出来ますが、AutoCAD .NET API で同等の処理を実装することは出来ますか?     Solution あいにく、AutoCAD .NET API ネイティブにモデル空間やペーパー空間(レイアウト)の作図領域の背景色を変更する API が用意されていません。   代替として、COM Interop を使って PreferencesDisplay オブジェクト(ActiveX) の  GraphicsWinModelBackgrndColor プロパティ(モデル空間背景色)、 GraphicsWinLayoutBackgrndColor プロパティ(ペーパー空間背景色)を使用、背景色を取得、設定することが出来ます。   この場合、 GraphicsWinModelBackgrndColor プロパティ、 GraphicsWinLayoutBackgrndColor プロパティには AcCmColor オブジェクト が適用出来ないため、インデックスカラーやカラーブックの指定は出来ず、RGB 指定になってしまう点にご注意ください。   次の C# コードは、  GraphicsWinModelBackgrndColor プロパティ を使ってモデル空間の作図領域の背景色を変更するものです。   using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application; ... ... Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor; // ↓ if you face an error at 'var acadApp' below, try 'dynamic acadApp' var acadApp = (AcadApplication)AcadApp.AcadApplication; var modelBk = acadApp.Preferences.Display.GraphicsWinModelBackgrndColor; var color = ColorTranslator.FromOle((int)modelBk); ed.WriteMessage("\nCurrent Color = {0}", color.ToString()); acadApp.Preferences.Display.GraphicsWinModelBackgrndColor = (uint)ColorTranslator.ToOle(System.Drawing.Color.FromArgb(11, 22, 33)); modelBk = acadApp.Preferences.Display.GraphicsWinModelBackgrndColor; color = ColorTranslator.FromOle((int)modelBk); ed.WriteMessage("\nNew Color = {0}", color.ToString()); ...   なお、ObjectARX では、 acedGetCurrentColors() グローバル関数と acedSetCurrentColors() グローバル関数を使って、AcColorSettings 構造体の dwGfxModelBkColor 値、dwGfxLayoutBkColor 値で背景色の取得/設定をおこなうことが出来ます。
記事全体を表示
Issue VPORTS[ビューポート管理] コマンドで作成したモデル空間ビューポート内の表示をすべて再作図したいのですが、.NET API で REGENALL[全再作図] コマンドと同じような実装をすることは可能でしょうか?     Solution AutoCAD .NET API の Editor.Regen メソッドには、表示中のすべてのモデル空間ビューポートの再作図を指定するパラメーターがありません。このため、すべてのモデル空間ビューポートを走査して、ビューポートを識別する ViewportTableRecord.Number プロパティの値を CVPORT システム変数に指定、アクティブなビューポートをを切り替えて Editor.Regen メソッドを呼び出す必要があります。   [CommandMethod("MyCommand", CommandFlags.Modal)] public void MyCommand() { Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; var curVPort = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("CVPORT"); using (Transaction tr = db.TransactionManager.StartTransaction()) { ViewportTable vpTable = (ViewportTable)tr.GetObject(db.ViewportTableId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead); if (vpTable != null) { ed.WriteMessage(Constants.vbLf + "Model Space Viewports : "); foreach (ObjectId vpId in vpTable) { ViewportTableRecord vptr = (ViewportTableRecord)tr.GetObject(vpId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite); Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("CVPORT", vptr.Number); ed.WriteMessage(vptr.Number.ToString()); ed.Regen(); } } tr.Commit(); } Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("CVPORT", curVPort); }    もちろん、プロジェクトの参照設定に Autodesk.AutoCAD.Interop.Common.dll と Autodesk.AutoCAD.Interop.dll の 2つのアセンブリを追加して、COM Interop(COM 相互運用機能)で ActiveX オートメーション(COM API)を利用、 acAllViewports パラメーターを指定して Regen メソッドを呼び出すことも可能です。   [CommandMethod("MyCommand", CommandFlags.Modal)] public void MyCommand() // This method can have any name { Autodesk.AutoCAD.Interop.AcadApplication COM_App = (Autodesk.AutoCAD.Interop.AcadApplication)Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication; COM_App.ActiveDocument.Regen(Autodesk.AutoCAD.Interop.Common.AcRegenType.acAllViewports); }   
記事全体を表示
現象 Inventor 2025以前のバージョンでは、Inventor 起動時に対応するバージョンのInventor Apprentice Serverのレジストリ登録が行われていました。 一方で、Inventor 2026起動時には、Inventor Apprentice Server 2026のレジストリ登録が行われない。 このため、異なるバージョンのInventorがインストールされている混在環境においては、以下の様な状態となります。   手順 ・Inventor 2025をインストール ・Inventor 2026およびInventor Apprentice Server 2026をインストール ・Inventor 2025を起動。⇒同時に Apprentice Server 2025のレジストリ登録が行われる。 ・Inventor 2025を終了 ・Inventor 2026を起動。 ⇒ Apprentice Server 2026のレジストリ登録は行われないため、レジストリ登録はApprentice Server 2025のままとなる。   診断 Inventor 2025 以前ではInventor Pro のインストーラに Apprentice Server のコピーが含まれており、Inventor Pro のインストール時に併せてインストールがされおり、Inventor起動時に同梱されてるApprentice Serverの情報でレジストリ登録を更新しておりました。   一方、Inventor 2026 以降ではInventor Pro のインストール時に Apprentice Server がインストールされなくなりました(より正確には、Regfee版のApprentice Server がインストールされますが、このRegfree版のApperentice ServerはInventor以外のアプリケーションからは利用できません)。また、Inventor起動時に同時に行っていた、同梱されているApprentice Serverでレジストリ登録情報の更新を行う処理も行われなくなりました。   このため以前のリリースから Inventor 2026 に切り替えてもApprentice Serverのレジストリ登録は更新されません。 解決策 Inventor 2026以降では、スタンドアロン版のApprentice Serverをインストールして、利用するようにしてください。 Inventor 2026以降で以前バージョンのApprentice Server から切り替えるには、スタンドアロン版のApprentice Serverインストールディレクトリ配下で以下のコマンドラインを実行してください。   ApprenticeRegSvr.exe /install  
記事全体を表示
Issue グループやブロック化していない状態の特定オブジェクトを移動や回転する際に、 イベント処理を使用せずに、アプリ内で関係のあるオブジェクトを同じように移動や回転する方法はありますか?   Solution 特定のオブジェクト タイプ(クラス)の移動や回転、縮尺変更など編集は、TransformOverrule オーバールール(Overrule)プロトコルを使用して、既定の振る舞いを変更することが可能です。ただし、イベント ハンドラーでのオブジェクト編集で同一イベントが発生してしまい、無限ループに陥らないような配慮が必要です。   次の C# コードは、MOVE コマンドや ROTATE コマンド、SCALE コマンドで円弧オブジェクト(Arc)を選択すると、青色(インデックスカラー色:5)の線分オブジェクト(Line)に同じマトリックス変換を実施するものです。   public class TransformByOverrule : TransformOverrule { public override void TransformBy(Entity ent, Matrix3d mat) { Database db = HostApplicationServices.WorkingDatabase; Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor; ed.WriteMessage("\nTransformBy.TransformBy Overrule - matrix {0}", mat.ToString()); base.TransformBy(ent, mat); TypedValue[] typeval = new TypedValue[2]; typeval.SetValue(new TypedValue(62, 5), 0); typeval.SetValue(new TypedValue(0, "LINE"), 1); SelectionFilter filter = new SelectionFilter(typeval); PromptSelectionResult psr = ed.SelectAll(filter); ed.WriteMessage("\nGetSelection = {0}", psr.Status.ToString()); if (psr.Status == PromptStatus.OK) { using (Transaction tr = db.TransactionManager.StartTransaction()) { SelectionSet sset = psr.Value; foreach (ObjectId objId in sset.GetObjectIds()) { ed.WriteMessage("\nObjectTd:" + objId.ToString()); Entity slave = (Entity)tr.GetObject(objId, OpenMode.ForWrite); slave.TransformBy(mat); } tr.Commit(); } } } } static TransformByOverrule _toverrule = null; [CommandMethod("MyCommand")] static public void MyCommand() { Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor; if (_toverrule == null) { _toverrule = new TransformByOverrule(); ObjectOverrule.AddOverrule(RXObject.GetClass(typeof(Arc)), _toverrule, true); ObjectOverrule.Overruling = true; ed.WriteMessage("\nBegin modifying ARC overrule"); } else { ObjectOverrule.RemoveOverrule(RXObject.GetClass(typeof(Arc)), _toverrule); _toverrule.Dispose(); _toverrule = null; ed.WriteMessage("\nEnd modifying ARC overrule"); } }        
記事全体を表示
Issue 選択したオブジェクトが自動調整配列複写の要素かどうか判定して、自動調整配列複写であった場合に分解する実装するには、どのようなコードを記述すればいいでしょうか?       Solution 自動調整配列複写の対象となっているオブジェクト一式は、匿名ブロック(Anonymous Block)として自動調整フレームワークで管理、維持されています。   自動調整配列複写の判定には、AcDbAssocArrayActionBody::isAssociativeArray() メンバー関数を利用することが出来ます。同様に、分解には AcDbAssocArrayActionBody::explode() メンバー関数 を利用することが出来ます。   次のコードは、選択したオブジェクトが自動調整配列複写の構成要素だった場合に、トップレベルの調整配列複写を分解する例です。   ads_name ename; ads_point pt; int stat = acedEntSel(_T("\nオブジェクトを選択 : "), ename, pt); if (stat != RTNORM) return; AcDbEntity* pEnt; AcDbObjectId objId; acdbGetObjectId(objId, ename); Acad::ErrorStatus err = acdbOpenAcDbEntity(pEnt, objId, AcDb::kForRead); if (err != Acad::eOk) return; if (AcDbAssocArrayActionBody::isAssociativeArray(pEnt)) { acutPrintf(_T("\n自動調整配列です")); AcDbObjectId actId = AcDbAssocArrayActionBody::getControllingActionBody(pEnt, NULL); AcDbAssocArrayActionBody* pAryAct = NULL; err = acdbOpenAcDbObject((AcDbObject*&)pAryAct, actId, AcDb::kForWrite); if (err != Acad::eOk) { pEnt->close(); return; } if (AcDbAssocArrayPathParameters::cast(pAryAct->parameters())) acutPrintf(_T("\n - パス")); if (AcDbAssocArrayPolarParameters::cast(pAryAct->parameters())) acutPrintf(_T("\n - 円形状")); if (AcDbAssocArrayRectangularParameters::cast(pAryAct->parameters())) acutPrintf(_T("\n - 矩形状")); AcDbObjectIdArray newIds; pAryAct->explode(pEnt, newIds); pAryAct->close(); } else acutPrintf(_T("\n自動調整配列ではありません")); pEnt->close(); return;   EXPLODE コマンドで自動調整配列複写を分解する場合には、次のようなコードで AcDbAssocArrayActionBody::explode()  メンバー関数を代替することが出来ます。いずれの場合も、自動調整フレームワークが構成要素オブジェクトを保持しているため、すべてのオブジェクトを指定する必要はありません。   ads_name sset; acedSSAdd(NULL, NULL, sset); acedSSAdd(ename, sset, sset); acedCommandS(RTSTR, _T("EXPLODE"), RTPICKS, sset);      
記事全体を表示
Issue 選択したオブジェクトが自動調整配列複写の要素かどうか判定して、自動調整配列複写であった場合に分解する実装するには、どのようなコードを記述すればいいでしょうか?     Solution 自動調整配列複写の対象となっているオブジェクト一式は、匿名ブロック(Anonymous Block)として自動調整フレームワークで管理、維持されています。   自動調整配列複写の判定には、AssocArray.IsAssociativeArray メソッドを利用することが出来ます。 同様に、分解には AssocArray.Explode メソッドを利用することが出来ます。   次のコードは、選択したオブジェクトが自動調整配列複写の構成要素だった場合に、トップレベルの調整配列複写を分解する C# 例です。   Database db = HostApplicationServices.WorkingDatabase; Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; PromptEntityResult pent = ed.GetEntity("\nオブジェクトを選択:"); if (pent.Status != PromptStatus.OK) { return; } using (Transaction tr = db.TransactionManager.StartTransaction()) { if (AssocArray.IsAssociativeArray(pent.ObjectId)) { ed.WriteMessage("\n自動調整配列です"); AssocArray ary = AssocArray.GetAssociativeArray(pent.ObjectId); var param = ary.GetParameters(); if (param as AssocArrayPathParameters != null) ed.WriteMessage("\n - パス"); if (param as AssocArrayPolarParameters != null) ed.WriteMessage("\n - 円形状"); if (param as AssocArrayRectangularParameters != null) ed.WriteMessage("\n - 矩形状"); AssocArray.Explode(pent.ObjectId); } else ed.WriteMessage("\n自動調整配列ではありません"); tr.Commit(); }   EXPLODE コマンドで自動調整配列複写を分解する場合には、次のようなコードで AssocArray.Explode メソッドを代替することが出来ます。いずれの場合も、自動調整フレームワークが構成要素オブジェクトを保持しているため、すべてのオブジェクトを指定する必要はありません。   var sset = SelectionSet.FromObjectIds(new ObjectId[] { pent.ObjectId }); ed.Command("EXPLODE", sset);    
記事全体を表示
AutoCAD .NET APIリファレンスに記載の様に、PromptSelectionOptions.SingleOnlyは、AutoCAD ObjectARXでのacedSSGet()での”:S”モードの設定に相当します。また、 PromptSelectionOptions.SinglePickInSpaceは、":A"モードに相当します。   ObjectARXでのacedSSGetでは、”:S"モードは、単一のエンティティの選択が許容される状態となりますが、窓選択については有効な状態のままとなります。   また、”:A"モードについては、aecdSSGetのリファレンスでは「This mode option causes acedSSGet() to perform single pick selection in space on entities that implement a subselection filter.」との説明がありますが、これは例えばテーブルの様な、エンティティ内にサブエンティティがあるようなエンティティにおいて、テーブルのセル内の文字のクリックを、テーブル自身の選択とするオプション設定となります。
記事全体を表示
現象 AutoCAD 2025のAccoreconsole.exe でSystem.Data.OleDbを参照するプラグインのカスタムコマンドを実行すると、Accoreconsole.exeが異常終了するAutoCAD 2025のAccoreconsole.exe でSystem.Data.OleDbを参照するプラグインのカスタムコマンドを実行すると、Accoreconsole.exeが異常終了してしまいます。   なお、プラグインはAutoCAD 2025に合わせて.net 8を利用するように移植済みです。 また、System.Data.OleDbはVisual Studio のNugetパッケージマネージャから 9.0.2をプロジェクトにインストールして使用しています。 診断 AutoCAD インストールフォルダ配下のSystem.Data.OleDb.dllのバージョンと、プラグインプロジェクトのNugetでインストールしているSystem.Data.OleDb.dllのバージョンの差異に起因してAccoreconsole.exeが異常終了している状況です。   AutoCAD 2024以前は、.NET FrameworkのAppDomain機能を用いてプラグインは分離された実行空間にロード・実行されていました。AutoCADが利用するアセンブリとは異なるバージョンのアセンブリをプラグインが参照している場合でも問題なく実行することが出来ておりました。 一方で、AutoCAD 2025では、従来の.NET Frameworkから、.NET Core(.NET 8)にサポートプラットフォームが変更されましたが、この.NET CoreではAppDomain機能がサポートされておらず、すべてのプラグインとその参照アセンブリは同じ実行空間にロードされます。このため、AutoCADとプラグイン、または異なるプラグイン間でバージョンの異なる同じアセンブリを参照している場合、競合が発生して異常終了等の予期せぬ事態が発生することがあります(参照アセンブリによっては異常終了せず動作する場合もあります)。   解決策 System.Data.OleDbに特化した解決方法としては、プラグインが参照するSystem.Data.OleDbのライブラリをAutoCADのインストールフォルダ配下の者とすることで、問題を解消することが可能です。 以下、手順となります。 1.VisualStudio のプロジェクトからSystem.Data.OleDbのNugetパッケージを削除する 2.代わりに、VisualStudio のプロジェクトの参照設定で、AutoCADのインストールフォルダ(acad.exeおよびaccoreconsole.exeがあるフォルダ)配下のSystem.Data.OleDb.dllを参照ファイルに追加をする。   また、System.Data.OleDbに特化しない一般的な解決方法としては、.NET Coreが提供するAssemblyLoadContext機能を用いて、カスタム処理を異なる空間で実行することにより、参照するアセンブリのバージョン違いによる干渉を防ぐ方法となります。 AssemblyLoadContext機能については、Microsoft社の提供するマテリアル「System.Runtime.Loader.AssemblyLoadContext について」をご参照ください。
記事全体を表示
質問 InventorのVBA環境で、VBAの「ツール」-「参照設定」から利用するライブラリの参照設定が行えます。 VBAを実行するクライアント端末が複数あり、各端末でライラリファイルの参照設定をすることが手間なので、ライブラリの参照設定を出力して配布することは可能でしょうか? 回答 Inventorの設定ファイルには、VBAでの参照設定を編集する機能はありません。また、InventorのAPI にも直接的に参照設定を編集する機能はありません。   一方で、InventorのAPIで、Microsoft社が提供するVBA開発環境のVBProjectオブジェクトを取得するAPIが公開されているため、VBProjectオブジェクトのReferences.AddFromFile()メソッド等を利用することで、プログラムコードから参照設定を行うことが可能です。   以下は、"Adbe Acrobat 10 Type Library”への参照を追加する場合のサンプルコードとなります。 Dim app As Application Set app = ThisApplication Dim VBProject As Object Set VBProject = app.VBAProjects.Item(1).VBProject Const RefFile As String = "<path to acrobat.tlb file>" VBProject.References.AddFromFile RefFile
記事全体を表示
質問 Vaultクライアントで、プロジェクトエクスプローラ($)配下の、あるフォルダに対してローカル作業フォルダを規定値から別のフォルダに変更するを設定しました。 その後、Vault APIで対象のフォルダのローカル作業フォルダのパスを取得すると、変更したフォルダパスではなく、規定値のフォルダパスが取得されている状況です。 Vault クライアントで変更したフォルダパスを取得する方法はありますか。 回答  Vaultのローカル作業フォルダの設定を規定値から変更した場合、変更した設定は以下のファイルに保存されます(*****部は、実行環境により変化します)。   C:\Users\<Windows ログインユーザ>\AppData\Roaming\Autodesk\VaultCommon\Servers\Services_Security_******\<接続先サーバ名>\Vaults\<ボルト名>\Objects\WorkingFolders.xml     ファイルパスに<Windowsログインユーザ>、<接続先サーバ名>、<ボルト名>が含まれているため、カスタムアプリケーションからVaultに接続する際に、これらのどれかが異なる場合には、異なるローカル作業フォルダの設定が読み込まれます(ファイルが存在しない場合は、既定のパスとなります)。   ローカル作業フォルダの設定を規定値から変更したVaultクライアントアプリケーションと、APIを実行しているアプリケーションで、この値のどれかが異なっている場合Vault クライアントで変更したフォルダパスを取得することが出来ません。これらの値を合わせたうえで、変更後のフォルダパスが取得できるかを確認してください。
記事全体を表示
現象 Inventorを、VBAや.NET FrameworkのCreateObject()等のCOM API経由で起動後、カスタマイズプログラムからQuit()を実行せずに、GUIで終了(xボタン押下当)した場合、バックグラウンドプロセスとしてInventorが残ってしまう。   診断 外部プロセスから、VBAや.NET Framework等のCreateObject()等を用いて外部アプリケーションを起動した場合、対象のアプリケーションはQuit()メソッドにより終了をさせる必要があります。Quit()を実行せずアプリケーションGUI側から終了した場合バックグラウンドにプロセスが残存してしまいます。 この挙動はInventorのみならずExcel等でも同様で、COMオブジェクトを公開するアプリケーションに共通の挙動となります。   解決策 CreateObject()により取得したアプリケーションオブジェクトをQuit()メソッドで終了せず利用したい場合は、CreateObject()ではなくProcess.Start()等によりプロセスを起動し、GetObject()等を用いて起動中のアプリケーションのCOMオブジェクトを取得することで回避が可能です。   「APIでInventorを起動する際にバージョン指定する方法」にProcess.Start()を用いてInventorを起動し起動したInventorアプリケーションのCOMオブジェクトを取得する方法のサンプルコードがありますので、ご参照ください。  
記事全体を表示
Issue AutoCAD .NET API でフォルダ内の DWG ファイルを順に開いて処理していますが、サイズの大きい図面があると相対的に処理時間が長くなってしまいます。高速化するアイデアはありますか?   Solution   AutoCAD 上に図面を開いて表示する際、描画に多く時間がかかってしまいます。 もし、ユーザインターフェース上に図面を表示する必要がないのであれば、Database.ReadDwgFile メソッドを使って、メモリ上に図面を展開する方法を採用することで、描画にかかかる時間を省いて処理全体を高速化させることが出来ます。   次のコードは、フォルダを指定後にフォルダ内の .dwg ファイルを順に Database.ReadDwgFile メソッドでメモリ展開し、モデル空間のオブジェクト タイプを表示するものです。 [CommandMethod("MyCommand", CommandFlags.Modal)] public void MyCommand() { Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; using (FolderBrowserDialog fd = new FolderBrowserDialog()) { if (fd.ShowDialog() == DialogResult.OK) { string folder = fd.SelectedPath; System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(folder); IEnumerable<System.IO.FileInfo> files = di.EnumerateFiles("*.dwg", System.IO.SearchOption.AllDirectories); if (files == null) return; ed.WriteMessage("\n\t{0}", folder); foreach (System.IO.FileInfo f in files) { string file = f.FullName; ed.WriteMessage("\n - {0}", file); try { using (Database db = new Database(false, true)) { db.ReadDwgFile(file, FileOpenMode.OpenForReadAndAllShare, false, null); using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTableRecord btr = (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead); foreach (ObjectId id in btr) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead); ed.WriteMessage("\n - {0}", ent.GetType().ToString()); } tr.Commit(); } } } catch (System.Exception ex) { ed.WriteMessage(ex.ToString()); } } } } }   なお、Database.ReadDwgFile メソッドの使用時には、次の点に注意が必要です。   Database.ReadDwgFile メソッドで読み込む Database インスタンスを new ステートメントで用意する必要があります。この際、最低限必要なシンボルテーブルとオーナーシップを持つ Database 構造は、読み込む DWG ファイルに定義されているため、コンストラクタには Database.Database([MarshalAs(UnmanagedType.U1)] bool, [MarshalAs(UnmanagedType.U1)] bool)  オーバーロードを使用して、第1パラメーターの値を false にして、読み込む DWG ファイルの Database 構造との競合を抑止する必要があります。 AutoCAD のユーザインターフェースに表示された Database インスタンスは、同図面を表示している MDI 子ウィンドウを閉じると、AutoCAD が Database 領域をメモリから削除します。ただし、Database.ReadDwgFile メソッドでメモリ上に展開した Database インスタンスの領域は、展開したアドイン アプリがメモリーから削除しなければなりません。削除には上、記コードのように using ステートメントを利用してスコープ内の処理後に削除させるか、using ステートメントでスコープ指定せずに Dispose メソッドを明示的に呼び出すことも出来ます。 Database.ReadDwgFile メソッドで読み込んだ Database インスタンス内の DBText オブジェクトや AttributeReference オブジェクトの位置合わせを変更する場合、Database インスタンスを HostApplicationServices.WorkingDatabase プロパティで設定していないと予期しないズレが発生する場合があります。これは、DBText クラス実装が、位置合わせ時に現在の図面データベース(Database)を参照している関係で発生してしまう現象です。Database インスタンスを HostApplicationServices.WorkingDatabase プロパティで設定して処理した場合、処理後にオリジナル(ユーザーインターフェースに開いている図面の Database インスタンスを HostApplicationServices.WorkingDatabase プロパティで再設定する必要があります。
記事全体を表示
長期にわたる Autodesk App Store 運営の知見を反映するかたちで、Windows 版 AutoCAD 2026 でパッケージ バンドルを利用した自動ローダーに重要な変更が加えられています。アドイン アプリ運用時のセキュリティを向上させるのが目的です。   従来のパッケージの検出では次の 3 か所のフォルダを利用することが出来ました。   一般的なインストール フォルダ Windows: %PROGRAMFILES%¥Autodesk¥ApplicationPlugins Mac OS: /Applications/Autodesk/ApplicationAddins すべてのユーザ プロファイル フォルダ Windows: %PROGRAMDATA%¥Autodesk¥ApplicationPlugins Mac OS: 該当なし ユーザ プロファイル フォルダ Windows: %APPDATA%¥Autodesk¥ApplicationPlugins Mac OS: ~/Library/Application Support/Autodesk/ApplicationAddins Windows 版 AutoCAD 2026 では、%ProgramData%\Autodesk\ApplicationPlugins(通常はC:\ProgramData\Autodesk\ApplicationPlugins)フォルダに配置したパッケージ バンドルからのアドイン アプリの自動ロードを抑止します。   このため、従来、%ProgramData%\Autodesk\ApplicationPlugins フォルダを利用していたアドイン アプリは、%PROGRAMFILES%¥Autodesk¥ApplicationPlugins フォルダ、または、%APPDATA%¥Autodesk¥ApplicationPlugins フォルダにパッケージ バンドルの配置を変更する必要があります。   %ProgramData%\Autodesk\ApplicationPlugins フォルダを利用する利点は、Windows 上のすべてのユーザー環境下で、AutoCAD にアドインを識別・ロードさせることが出来る点にありましたが、逆にすべてのユーザが書き込み可能な権限を持つことになり、潜在的なセキュリティの脆弱性を生む可能性があります。   一方、%PROGRAMFILES%¥Autodesk¥ApplicationPlugins フォルダ、または、%APPDATA%¥Autodesk¥ApplicationPlugins フォルダへの書き込みには管理者権限を必要とするため、この点で安全なインストールを保証することが出来ます。   %ProgramData%\Autodesk\ApplicationPlugins フォルダを利用する必要がある場合には、システム レジストリの  \HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\R25.1\ACAD-9101\Applications\AcadAutoLoader に DWORD 値 1 を持つ LoadFromProgramData キーを追加することで、従来の動作を復元することも出来ます。ただし、前述のセキュリティ上の観点から非推奨となります。   一度、LoadFromProgramData キーを作成して AutoCAD がパッケージを識別すると、キーの値を 0 にしたり、キー自体を削除しても、パッケージを検出するようになりますのでご注意ください。   特に、デジタル署名されていないアドイン ファイルに対して、初回ロード時に [常にロードする] を選択してしまうと、無条件にパッケージ バンドル内のアドイン アプリをロードするようになってしまいます。     初期状態の動作に戻すには、AutoCAD 2026 の再インストールが必要になります。
記事全体を表示
Issue AutoCAD .NET API でアプリケーションのフォーカス イベントを処理することは出来ますか?   Solution AutoCAD の Application ウィンドウ レベルでは、COM API の Application.AppActivate イベントと Application.AppDeactivate イベントを COM Interop でお使いいただくことが出来ます。 ご参考:COM ベースのイベントを登録する(.NET)   Autodesk.AutoCAD.Interop.AcadApplication? acAppCom = null; [CommandMethod("AddCOMEvent")] public void AddCOMEvent() { acAppCom = (Autodesk.AutoCAD.Interop.AcadApplication)Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication; acAppCom.AppActivate += new _DAcadApplicationEvents_AppActivateEventHandler(appComAppActivate); acAppCom.AppDeactivate += new _DAcadApplicationEvents_AppDeactivateEventHandler(appComAppDeactivate); } [CommandMethod("RemoveCOMEvent")] public void RemoveCOMEvent() { if (acAppCom != null) { acAppCom.AppActivate -= new _DAcadApplicationEvents_AppActivateEventHandler(appComAppActivate); acAppCom.AppDeactivate -= new _DAcadApplicationEvents_AppDeactivateEventHandler(appComAppDeactivate); acAppCom = null; } } public void appComAppActivate() { Autodesk.AutoCAD.ApplicationServices.Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; ed.WriteMessage("\n*** AppActivate ***\n"); } public void appComAppDeactivate() { Autodesk.AutoCAD.ApplicationServices.Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; ed.WriteMessage("\n*** AppDeactivate ***\n"); }  
記事全体を表示
Issue バルーン番号の番号部分を属性定義(タグ名 Index)したブロック定義(ブロック名 MyBlock)があります。     このブロック定義の挿入時にバルーン番号を加算しながら重複のないバルーン番号を持つブロック参照を配置することは可能でしょうか?   Solution 新たな MyBlock ブロック参照の挿入時に、モデル空間に配置されたすべての MyBlock を走査して Index タグ名を持つ属性値(文字列)を取得、最大値となり値をバルーン番号に設定することで実現することが出来るはずです。   次のサンプルは、MyBlock ブロック定義後に同処理を実装する VBA マクロの例です。属性値の妥当性チェックの処理はしていませんが、インデックス番号を保持するタグ名 Index を持つ属性には、半角整数の文字列が設定されているものとしています。IndexOnBlockRef プロシージャを実行してみてください。   ' 挿入時に属性値(インデックス番号)を順番に割り当てるメイン プロシージャ Public Sub IndexOnBlockRef() Dim strBlkName strBlkName = "MyBlock" CreateBlockDef (strBlkName) Dim insPt(0 To 2) As Double insPt(0) = 0: insPt(1) = 0: insPt(2) = 0 Dim retPt As Variant Dim index As Integer Dim blockRefObj As AcadBlockReference On Error Resume Next Do Err.Clear retPt = ThisDrawing.Utility.GetPoint(, vbCrLf & "ブロックの挿入点を指示 : ") If Err Then Exit Do End If Set blockRefObj = ThisDrawing.ModelSpace.InsertBlock(retPt, strBlkName, 1#, 1#, 1#, 0) index = FindMaxIndexAttribute() Call SetIndexAttribute(blockRefObj, index + 1) Loop End Sub ' 属性定義(タグ名 Index)を含むブロック定義 MyBlock を定義する関数 Public Function CreateBlockDef(strBlkName As String) Dim blockObj As AcadBlock Dim insPt(0 To 2) As Double insPt(0) = 0: insPt(1) = 0: insPt(2) = 0 On Error Resume Next Set blockObj = ThisDrawing.Blocks.Item(strBlkName) If Err Then Set blockObj = ThisDrawing.Blocks.Add(insPt, strBlkName) Dim circleObj As AcadCircle Set circleObj = blockObj.AddCircle(insPt, 100#) Dim attributeObj As AcadAttribute Set attributeObj = blockObj.AddAttribute(100#, acAttributeModePreset, "インデックス?", insPt, "Index", "0") attributeObj.Alignment = acAlignmentMiddleCenter End If End Function ' 与えられたブロック参照のタグ名 Index の属性値(整数)を返す関数 Public Function GetIndexAttribute(blockRefObj) As Integer Dim varAttributes As Variant varAttributes = blockRefObj.GetAttributes Dim strAttribute As String strAttribute = "-1" For Each blockAttr In varAttributes If blockAttr.TagString = "Index" Then strAttribute = blockAttr.TextString Exit For End If Next GetIndexAttribute = CInt(strAttribute) End Function ' モデル空間に配置されたすべての MyBlock ブロック参照を走査して割り当てられた最大の Index の属性値(整数)を返す関数う Public Function FindMaxIndexAttribute() As Integer Dim sset As AcadSelectionSet On Error Resume Next Set sset = ThisDrawing.SelectionSets.Item("ssblocks") If Not Err Then sset.Delete End If Set sset = ThisDrawing.SelectionSets.Add("ssblocks") Dim FilterType(1) As Integer Dim FilterData(1) As Variant FilterType(0) = 0 FilterData(0) = "Insert" FilterType(1) = 2 FilterData(1) = "MyBlock" sset.Select acSelectionSetAll, , , FilterType, FilterData Dim index As Integer index = -1 Dim maxIndex As Integer maxIndex = -1 If sset.Count > 0 Then Dim entityObj As AcadEntity For Each entityObj In sset Dim blockRefObj As AcadBlockReference Set blockRefObj = entityObj index = GetIndexAttribute(blockRefObj) If maxIndex < index Then maxIndex = index End If Next End If FindMaxIndexAttribute = maxIndex End Function ' 与えられたブロック参照1のタグ名 Index の属性値(整数)を設定する関数 Public Function SetIndexAttribute(blockRefObj, index) Dim varAttributes As Variant varAttributes = blockRefObj.GetAttributes For Each blockAttr In varAttributes If blockAttr.TagString = "Index" Then blockAttr.TextString = CStr(index) Exit For End If Next End Function     既に挿入配置済のブロック参照 My Block に新たにインデクス番号の属性値を割り当てる場合には、前述のコードに次の AssignIndexToBlockRef プロシージャを追加・実行することでブロック参照を順に選択して値を更新することも出来ます。   ' 配置済のブロック参照に指定値から属性値(インデックス番号)を順番に割り当てるメイン プロシージャ Public Sub AssignIndexToBlockRef() Dim strBlkName strBlkName = "MyBlock" Dim startIndex As Integer startIndex = FindMaxIndexAttribute() On Error Resume Next Err.Clear Dim returnInt As Integer ThisDrawing.Utility.InitializeUserInput (4) ' disallow negative returnInt = ThisDrawing.Utility.GetInteger(vbCrLf & "割り当てるインデクス開始値を入力<" & CStr(startIndex + 1) & "> : ") If Err = 0 Then If returnInt <= startIndex Then MsgBox ("指定した値と同じ、または、大きいインデックス値を持つブロック参照が既に存在します" & vbCrLf & _ "既に配置済のブロック参照とインデックス値が重複してしまう可能性があります") Exit Sub End If startIndex = returnInt - 1 End If Dim returnObj As AcadObject Dim basePnt As Variant Do Err.Clear ThisDrawing.Utility.GetEntity returnObj, basePnt, "ブロック参照を選択:" If Err = 0 Then If returnObj.EntityName = "AcDbBlockReference" Then Dim blockRefObj As AcadBlockReference Set blockRefObj = returnObj If blockRefObj.Name = strBlkName Then startIndex = startIndex + 1 Call SetIndexAttribute(blockRefObj, startIndex) End If End If Else Exit Do End If Loop End Sub    
記事全体を表示