| | | Gut zu wissen: Hilfreiche Tipps und Tricks aus der Praxis prägnant, und auf den Punkt gebracht für Autodesk Produkte |
Autor
|
Thema: AutoCad per .Net clever fernsteuern (5052 mal gelesen)
|
Boortsneggor Mitglied Ingenieur
Beiträge: 49 Registriert: 27.12.2011 Win7 Prof, Visual Studio 2010/2012, ObjectARX 2008/2012/2013, ACAD 2008/2012/2013
|
erstellt am: 26. Aug. 2012 13:13 <-- editieren / zitieren --> Unities abgeben:
Einen schönen guten Tag, da ich in diesem Forum schon viel Hilfe in Sachen AutoCAD-Entwicklung bekommen habe, möchte ich heute mal ein paar interessante Erfahrungen an euch weiter geben. Die .Net-Schnittstelle (managed) von AutoCAD ist ziemlich mächtig und vor allem auch sehr schnell, da die Bibliotheken direkt im Speicher von AutoCad geladen werden. Möchte man nun eine Standalone-Anwendung entwickeln, welche vollen Zugriff auf AutoCad hat, so ist man auf COM angewiesen. Dies ist in der Regel um ein vielfaches langsamer. Es gibt aber auch die Möglichkeit, beides zu kombinieren und somit die Vorteile beider Varianten zu nutzen. Wir bauen eine Klassenbibliothek, die sämtliche Funktionen im Bezug auf den Zugriff auf AutoCAD und dessen Datenbank beinhaltet (in-process), und laden bzw. steuern diese aus einem unabhängigen Programm über die COM-Schnittstelle (out-of-process). Hier mal eine kleine Anleitung, wie Ihr eine derartige Lösung zum Laufen bekommt. 1.Erstellen einer Klassenbibliothek Zuerst muss eine neue Klassenbibliothek erstellt werden, welche wir für COM verfügbar machen müssen: Code:
using System.Runtime.InteropServices; using Autodesk.AutoCAD.Runtime; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; using System.EnterpriseServices; using System;namespace AcadInterface { [Guid("69FCC82A-1C96-40D2-B68F-2D7251B94447")] public interface IAcadInterface { [DispId(1)] bool SmartMethode(); } [ProgId("AcadInterface.Commands"), Guid("DEA7B308-03E1-456C-ACDF-48A2F6B368BD"), ClassInterface(ClassInterfaceType.None)] public class Commands : ServicedComponent, IAcadInterface {
private Database _db = HostApplicationServices.WorkingDatabase; private Document _doc = Application.DocumentManager.MdiActiveDocument; [CommandMethod("TESTCOM")] static public void MyCommand() {
_doc.Editor.WriteMessage("\nInterface ist geladen!"); } public bool SmartMethode() { bool result = false; DocumentLock loc = _doc.LockDocument();
using (loc) { //irgendein Zugriff auf die Datenbank des aktuellen Dokumentes } return result; } } }
Die GUIDs für das Interface und die Klasse könnt Ihr unter Extras/GUID in Visual Studio automatisch generieren lassen. Die Vererbung von ServicedComponent vereinfacht den Zugriff auf unser in-process-interface über COM. Damit ist die interne Schnittstelle schon fertig. Wichtig ist noch, dass vor dem ersten Kompilieren unter Assemblyinformationen das Häckchen bei "Assembly COM-sichtbar machen" gesetzt ist. Andernfalls schlägt die Registrierung anschließend fehl. 2.Registrierung des in-process-interfaces Nach dem ihr die Klassenbibliothek kompiliert habt, müsst ihr sie registrieren, damit sie für den Zugriff über COM verfügbar gemacht wird. Dies kann mit dem Windows-Programm regsam.exe realisiert werden. Hier ist es hilfreich, sich eine kleine batch-Datei anzulegen, welche dann in dem Verzeichnis der zu registrierenden dll ausgeführt wird. Diese beinhaltet bei mir folgende Zeilen: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe /codebase GaboCadConverterIP.dll Der Pfad steht für die 64bit-Variante des .Net 4.0 - Frameworks. Wenn ihr unter 32bit arbeitet müsstet ihr die regsam.exe im Ordner C:\Windows\Microsoft.NET\Framework\v4.0.30319 nehmen. Genauso verhält es sich mit den anderen Versionen des .Net-Frameworks. Jedoch habe ich es bisher nur mit 4.0 und Acad 2012 getestet. Die Option "/codebase" hinterlegt bei der Registrierung zusätzlich den Pfad der dll. Hier kommt bei der Registrierung auch eine Warnung, die ihr aber getrost ignorieren könnt. Wichtig ist noch, dass ihr vor er Registrierung die AcMgd.dll und die AcDbMgd.dll aus dem /inc-Ordner der Objectarx-Version kopiert. Diese dlls werden bei der Registrierung benötigt. 3.Automatische Registrierung nach Kompilieren Jetzt müsst ihr euer in-process-interface-Projekt so konfigurieren, dass die dll beim Kompilieren registriert wird. Bei 32bit geht das ganz einfach, in dem ihr ein Häkchen bei "Für COM-Interop registrieren" in den Projekteinstellungen/Erstellen setzt. Bei 64bit klappt diese Variante nicht, da in Visual Studio 2010 nur die 32bit-Version von regsam hinterlegt ist. Hier müsst ihr euch selbst mit einem Post-Build-Eintrag behelfen. Dieser kopiert nach dem Kompilieren die AcMgd.dll und die AcDbMgd.dll in den Release-Ordner, registriert die kompilierte dll und löscht die beiden zusätzlichen dlls wieder. Dafür könnt ihr folgenden Zeilen einfach in das Feld "Befehlszeile für Postbuildereignis:" kopieren: copy "c:\ObjectARX 2012\inc\acmgd.dll" "$(TargetDir)" copy "c:\ObjectARX 2012\inc\acdbmgd.dll" "$(TargetDir)" "c:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe" "$(TargetPath)" /tlb:"$(TargetDir)\AcadInterface.tlb" Hier die Option "/tlb" nicht vergessen, die die Typ Library für das Assembly erzeugt. Ohne diese Option hatte ich immer den COM-Fehler: "E_NOINTERFACE". Nach dem Hinzufügen des Post-Build-Eintrages könnt ihr nun neu kompilieren und solltet unter "Ausgabe" unten angezeigt bekommen, dass alles ordentlich registriert wurde. Überprüfen könnt ihr das auch mit dem Programm "OLE-COM Object Viewer" welches unter den Tools von Visual Studion zu finden ist. Damit ist das in-process-interface einsatzbereit. 4.Out-of-process-Komponente Für das Aufrufende Programm könnt ihr ein neues Projekt erstellen, dies kann zum Beispiel eine Windows.Forms sein oder auch eine WPF-Anwendung, wie in meinem Fall: Code:
using System.Windows; using Microsoft.Win32; using System; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Runtime.InteropServices;using Autodesk.AutoCAD.Interop; using System.Runtime.InteropServices; using Autodesk.AutoCAD.Interop.Common; using AcadInterface; //das in-process-interface // The IMessageFilter is needed to avoid problems with rejected calls of com operations // For more information on IMessageFilter: // http://msdn.microsoft.com/en-us/library/ms693740(VS.85).aspx namespace AcadOPinterface { [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000016-0000-0000-C000-000000000046")] public interface IMessageFilter { [PreserveSig] int HandleInComingCall( int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo); [PreserveSig] int RetryRejectedCall( IntPtr hTaskCallee, int dwTickCount, int dwRejectType); [PreserveSig] int MessagePending( IntPtr hTaskCallee, int dwTickCount, int dwPendingType); } /// <summary> /// Interaktionslogik für MainWindow.xaml /// </summary> public partial class MainWindow : Window, IMessageFilter { [DllImport("ole32.dll")] static extern int CoRegisterMessageFilter(IMessageFilter lpMessageFilter, out IMessageFilter lplpMessageFilter); const string acadProgID = "AutoCAD.Application.18"; //Instanzname von AutoCAD 2012 const string interfaceProgID = "AcadInterface.Commands"; //Instanzname der in-process-interface-Klasse private AcadApplication _acApp; private IAcadInterface _iPinterface; public MainWindow() { InitializeComponent(); IMessageFilter oldFilter; CoRegisterMessageFilter(this, out oldFilter); _acApp = null; _iPinterface = null; } //methode which is called by clicking the open button private void btStart_Click(object sender, RoutedEventArgs e) { try { _acApp = (AcadApplication)Marshal.GetActiveObject(acadProgID); _acApp.Visible = true; } catch { try { Type acType = Type.GetTypeFromProgID(acadProgID); _acApp = (AcadApplication)Activator.CreateInstance(acType, true); _acApp.Visible = true; } catch { MessageBox.Show("AutoCad 2012 konnte nicht gestartet werden!"); } Finally { //dieser eventhandler ist wichtig, damit ihr die lokale Variable _acApp wieder auf null setzen könnt _acApp.BeginQuit += new _DAcadApplicationEvents_BeginQuitEventHandler(ACAD_BeginQuit); } if(_acApp != null){ _iPinterface = (IAcadInterface)_acApp.GetInterfaceObject(interfaceProgID); bool res = _iPinterface.SmartMethode(); } } } //methode which was called by quitting acad public void ACAD_BeginQuit(ref bool cancel) { _acApp.BeginQuit -= new _DAcadApplicationEvents_BeginQuitEventHandler(ACAD_BeginQuit); //jedes mal wenn AutoCad geschlossen wird, muss die lokale Variable auf null gesetzt werden ansonsten //kann kommt es beim erneuten Start von ACAD aus der Anwendung heraus zum Fehler _acApp = null; } #region IMessageFilter Members int IMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo) { return 0; // SERVERCALL_ISHANDLED } int IMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType) { return 1000; // Retry in a second } int IMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType) { return 1; // PENDINGMSG_WAITNOPROCESS } #endregion } }
Das Interface IMessageFilter ist zwingend notwendig, damit die Kommunikation zwischen ACAD und der Anwendung reibungsfrei und stabil funktioniert. Andernfalls kommt es ständig zu E_CALL_REJECTED-Fehlern, weil Nachrichten gar nicht oder nur verzögert durchkommen. Vielen Dank an der Stelle an Kean Walmsley (http://through-the-interface.typepad.com/through_the_interface/2010/02/handling-com-calls-rejected-by-autocad-from-an-external-net-application.html ) . Nun könnt ihr kompilieren. Beim Klick auf den Button "Start" sollte sich nun eine Instanz von AutoCad öffnen, euer in-process-interface laden und die Methode "SmartMethode()" ausführen. Ob das interface im Autocar geladen wurde könnt ihr mit dem "TESTCOM"-Befehl überprüfen. Ich hoffe, mit dieser kleinen Anleitung dem einen oder anderen von euch ein paar mühsame Recherche-Stunden im Netz zu ersparen. Ich selbst habe auf diese Weise eine Anwendung entwickelt, welche eine Stapelverarbeitung vieler Dateien mit recht vielen Zugriffe auf die Datenbank einer einzelnen Zeichnung in sehr akzeptabler Zeit umsetzt. Ich wünsche euch viel Spaß beim Testen, und stehe euch bei Fragen und Anregungen gern zur Verfügung! Einen schönen Rest-Sonntag noch! ------------------ Robert Menger Gabo Engineering GmbH Entwicklung
[Diese Nachricht wurde von Boortsneggor am 26. Aug. 2012 editiert.] [Diese Nachricht wurde von Boortsneggor am 26. Aug. 2012 editiert.] [Diese Nachricht wurde von Boortsneggor am 26. Aug. 2012 editiert.] [Diese Nachricht wurde von Boortsneggor am 26. Aug. 2012 editiert.] [Diese Nachricht wurde von Boortsneggor am 26. Aug. 2012 editiert.] Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Andreas Widmann Mitglied ATHENA Support/Training
Beiträge: 218 Registriert: 24.08.2005
|
erstellt am: 06. Feb. 2013 08:30 <-- editieren / zitieren --> Unities abgeben: Nur für Boortsneggor
Hallo CAD-Gemeinde, Erstmal riesen Dank an Boortsneggor dass du deine Erfahrung mit uns hier teilst. ABER: ich brauche dringend eure Hilfe!!! Ich habe versucht den CODE von Boortsneggor in VB.Net zu übersetzen aber irgendwas klappt nicht so richtig bei mir. Lade ich die DLL in AutoCAD und gebe den Befehl "Rapid_E" ein, funktioniert alles prima und es werden die passenden Infos ausgegeben. Verbinde ich jedoch mit der Standalone zu ACAD und lasse von der Standalone "Rapid_E" ausführen, rennt er in dieser Zeile in einen Fehler:
Code: Dim acBlkTblRec As BlockTableRecord = CType(acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForWrite), BlockTableRecord)
Nebenbei bemerkt, die Funktion "TestCOM" lässt sich einwandfrei von der Standalone ausführen.Zuerst die In-Prozess Komponente mit der für COM sichtbar gemachten Schnittstelle:
Code: Imports System Imports Autodesk.AutoCAD.Runtime Imports System.Runtime.InteropServices Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD.Geometry Imports Autodesk.AutoCAD.EditorInput Imports System.Diagnostics Imports System.IO Imports System.Windows Imports System.EnterpriseServicesNamespace Rapid_E_AcadInterface <Guid("17909FF0-FC7A-4E6F-AE3E-3F88E8D39441")> Public Interface IACADInterface <DispIdAttribute(1)> _ Sub Rapid_E() <DispIdAttribute(2)> _ Sub testcom() End Interface <ProgId("Rapid_E.Rapid_E_AcadInterface"), Guid("430FDBC9-F7F5-4F9F-864B-11F1A83D49C9"), ClassInterface(ClassInterfaceType.None)> Public Class Rapid_E_AcadInterface Inherits ServicedComponent Implements IACADInterface <CommandMethod("TESTCOM")> Public Sub testcom() Implements IACADInterface.testcom Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\nInterface ist geladen") End Sub Public myprofile As RapidProfile <CommandMethod("Rapid_E")> Public Sub Rapid_E() Implements IACADInterface.Rapid_E 'Meine In-Prozess-Anwendung bestehend aus zwei Objektklassen die eine Auswahl im ACAD abrufen und diese weiterverarbeiten 'In End Sub End Class End Namespace
Und hier meine Standalone EXE:
Code: Imports Autodesk.AutoCAD.Interop Imports System.Runtime.InteropServices Imports Rapid_E.Rapid_E_AcadInterfaceImports System.Reflection Imports System <ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIDispatch), Guid("8DE23EAB-C14C-458A-A780-06A64E477227")> Public Interface IMessageFilter <PreserveSig()> Function HandleInComingCall(ByVal dwCallType As Int64, ByVal HTaskCaller As IntPtr, ByVal dwTickCount As Int64, ByVal lpInterfaceInfo As IntPtr) As Int64 <PreserveSig()> Function MessagePending(ByVal hTaskCallee As IntPtr, ByVal dwTickCount As Int64, ByVal dwPendingType As Int64) As Int64 <PreserveSig()> Function RetryRejectedCall(ByVal hTaskCallee As IntPtr, ByVal dwTickCount As Int64, ByVal dwRejectType As Int64) As Int64 End Interface Public Class Form1 Implements IMessageFilter Const interfaceProgID = "Rapid_E.Rapid_E_AcadInterface" Dim acapp As Autodesk.AutoCAD.Interop.AcadApplication = Nothing Dim iPinterface As IACADInterface = Nothing <DllImport("ole32.dll")> Public Shared Function CoRegisterMessageFilter(Optional ByVal lpMessageFilter As IMessageFilter = Nothing, Optional ByRef lplpMessageFilter As IMessageFilter = Nothing) As Integer End Function #Region "IMessageFilter Members" Public Function HandleInComingCall(ByVal dwCallType As Int64, ByVal HTaskCaller As System.IntPtr, ByVal dwTickCount As Int64, ByVal lpInterfaceInfo As System.IntPtr) As Int64 Implements IMessageFilter.HandleInComingCall MsgBox("incoming") 'Nur zu Testzwecken Return 0 'SERVERCALL_ISHANDLED End Function Public Function MessagePending(ByVal hTaskCallee As System.IntPtr, ByVal dwTickCount As Int64, ByVal dwPendingType As Int64) As Int64 Implements IMessageFilter.MessagePending MsgBox("pending") 'Nur zu Testzwecken Return 1 'PENDINGMSG_WAITNOPROCESS End Function Public Function RetryRejectedCall(ByVal hTaskCallee As System.IntPtr, ByVal dwTickCount As Int64, ByVal dwRejectType As Int64) As Int64 Implements IMessageFilter.RetryRejectedCall MsgBox("recected") 'Nur zu Testzwecken Return 1000 'Retry in a second End Function #End Region Public Sub New() ' Dieser Aufruf ist für den Designer erforderlich. InitializeComponent() ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu. Dim oldFilter As IMessageFilter = Nothing CoRegisterMessageFilter(Me, oldFilter) End Sub
Ich bin um jede Hilfe Dankbar!!! ------------------ Gruß Andreas ------------------------------------------------------------------------------------------------------------------------------------ Die Antwort ist 42! Die Antwort ist 42! Die Antwort ist 42! ...wenn ich nur die Frage wüsste... Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Andreas Widmann Mitglied ATHENA Support/Training
Beiträge: 218 Registriert: 24.08.2005 Windows 10 Autocad 2015 - 2018 Athena 2015 - 2017 Aufsatz
|
erstellt am: 13. Feb. 2013 09:42 <-- editieren / zitieren --> Unities abgeben: Nur für Boortsneggor
Um das Thema noch etwas aufleben zu lassen, auch diese Variante verursacht einen Fehler:
Code: Dim acBlkTblRec As BlockTableRecord = CType(acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForRead), BlockTableRecord) acBlkTblRec.UpgradeOpen()
Warum darf ich den BlockTableRecord, über Interface aufgerufen, nicht zum schreiben öffnen? ------------------ Gruß Andreas ------------------------------------------------------------------------------------------------------------------------------------ Die Antwort ist 42! Die Antwort ist 42! Die Antwort ist 42! ...wenn ich nur die Frage wüsste... Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Boortsneggor Mitglied Ingenieur
Beiträge: 49 Registriert: 27.12.2011 Win7 Prof, Visual Studio 2010/2012, ObjectARX 2008/2012/2013, ACAD 2008/2012/2013
|
erstellt am: 16. Feb. 2013 11:14 <-- editieren / zitieren --> Unities abgeben:
Hallo Andreas, in VB stecke ich leider nicht so tief drin. Aber bei mir war die Geschichte mit dem DocumentLock auch wichtig. Bei jedem Eingriff des IP-Interfaces locke ich zuerst das aktuelle Dokument bevor ich die Funktionen anwende. Ich kann mich erinnern, dass es ohne diese Sperre zu Problemen kam. Ich hoffe, dass hilft dir weiter. Viel Glück und ein schönes WE! Grüße Robert ------------------ Robert Menger Gabo Engineering GmbH Entwicklung Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Andreas Widmann Mitglied ATHENA Support/Training
Beiträge: 218 Registriert: 24.08.2005
|
erstellt am: 21. Feb. 2013 09:53 <-- editieren / zitieren --> Unities abgeben: Nur für Boortsneggor
Hallo, super, danke Robert, den DocumentLock hab ich total übersehen und jetzt eingebaut. Dass du in VB (und ich in C) nicht so drin bist ist glaub ich kein Problem, es wird ja beides in die selbe Sprache kompiliiert und es sollte daher auch meist einen jeweils gleichbedeutenden Codeschnipsel in der anderen Sprache geben, oder nicht? Also, jedenfalls hat der DocumentLock über den Fehler beim Schreib-Öffnen des BlocktableRecord hinweggeholfen. Das Programm läuft weiter und ACAD fordert mich auf die erste Auswahl zu treffen... und schon steck ich leider in einem neuen Fehler: Ich bekommen einen " FatalExecutionEngineError " vorgestellt. Interessanterweise stürzt hierbei meine Standalone-Exe ab während, nachdem ich die Standalone beendet habe, mich AutoCAD anschließend souverän die Auswahl machen lässt und den In-Process Code einwandfrei vollständig ausführt. Diese Code-Zeile ruft das Interfacecommand auf, und hier wird mir der Error gezeigt (siehe angehängtes Bild):
Code: If Not acapp Is Nothing And Not iPinterface Is Nothing Then iPinterface.Rapid_E()
Muss ich hier den DokumentLock vorübergehend wieder aufheben? Und wie würde ich das machen? @robert: In deiner PM hast du gemeint ich solle das Interface direkt in ACAD laden, was hast du damit gemeint? Oder ist das nun hinfällig? ------------------ Gruß Andreas ------------------------------------------------------------------------------------------------------------------------------------ Die Antwort ist 42! Die Antwort ist 42! Die Antwort ist 42! ...wenn ich nur die Frage wüsste... Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Boortsneggor Mitglied Ingenieur
Beiträge: 49 Registriert: 27.12.2011 Win7 Prof, Visual Studio 2010/2012, ObjectARX 2008/2012/2013, ACAD 2008/2012/2013
|
erstellt am: 21. Feb. 2013 16:08 <-- editieren / zitieren --> Unities abgeben:
Hallo Andreas, wenn ich in meinem IP-Interface eine neue Funktion implementiere, dann teste ich diese zuerst direkt im AutoCAD. Das IP-Interface ist ja eine für AutoCAD kompilierte dll. Ich habe mir zum Test eine Command-Method implementiert, über die ich die Funktionalität des Interfaces testen kann. Code:
//methode to test the interface [CommandMethod("TESTCOMMAND")] public void TestCommand() { Database _db = HostApplicationServices.WorkingDatabase; Document _doc = Application.DocumentManager.MdiActiveDocument; DocumentLock loc = _doc.LockDocument(); using (loc) { //do something you want to test... } }
Sprich einfach im AutoCAD NETLOAD und direkt deine IP-Interface-dll laden. Meist handelt es sich um Fehler, die im AutoCAD entstehen und nicht über die COM-Schnittstelle weitergereicht werden. Grüße robert ------------------ Robert Menger Gabo Engineering GmbH Entwicklung Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Andreas Widmann Mitglied ATHENA Support/Training
Beiträge: 218 Registriert: 24.08.2005
|
erstellt am: 21. Feb. 2013 16:14 <-- editieren / zitieren --> Unities abgeben: Nur für Boortsneggor
Hallo Robert, das kann es in diesem Fall nicht sein denn ich habe das ganze erst als AutoCAD CommandMethod ausgearbeitet und getestet und danach dann das Interface implementiert um es von "aussen" ansprechen zu können. Wenn ich die DLL im ACAD lade und den Befehl eingebe funktioniert alles einwandfrei. ..... oder gibt es Probleme wenn die Sub in meiner Dll vom Interface aufgerufen werden soll, gleichzeitig aber mit dem CommandMethod Attribut versehen ist?? Code: <CommandMethod("Rapid_E")> Function Rapid_E() As String Implements IACADInterface.Rapid_E ... End Sub
------------------ Gruß Andreas ------------------------------------------------------------------------------------------------------------------------------------ Die Antwort ist 42! Die Antwort ist 42! Die Antwort ist 42! ...wenn ich nur die Frage wüsste... Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Brischke Moderator CAD on demand GmbH
Beiträge: 4171 Registriert: 17.05.2001 AutoCAD 20XX, defun-tools
|
erstellt am: 21. Feb. 2013 16:16 <-- editieren / zitieren --> Unities abgeben: Nur für Boortsneggor
Hallo Robert, irgendwie fehlt mir die Fantasie, wozu man dies überhaupt benötigt. Du willst von irgendeiner Anwendung außerhalb vom AutoCAD im AutoCAD irgendetwas machen. Klar, das geht nur via Com. Warum lädtst du aber im AutoCAD nicht einfach die DLL's, die es braucht, um deine Funktionen auszuführen? Dann kannst du mit einfachem SendCommand von deiner externen Anwendung ebenfalls die .Net-Programme laufen lassen. Mich würde jetzt wirklich interessieren, was du damit anstellst. Grüße! Holger ------------------ Holger Brischke FREIE SCHULUNGSPLÄTZE -- C#.NET-Schulung im Mai 2013 Bei Interesse bitte melden! CAD on demand GmbH Individuelle Lösungen von Heute auf Morgen.
defun-tools Das Download-Portal für AutoCAD-Zusatzprogramme!
Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Andreas Widmann Mitglied ATHENA Support/Training
Beiträge: 218 Registriert: 24.08.2005
|
erstellt am: 21. Feb. 2013 16:39 <-- editieren / zitieren --> Unities abgeben: Nur für Boortsneggor
Hallo Holger, *Humor an* weils einfach cooler is *Humor aus* das kann ich dir einfach erklären. Wie du sicher weist, ist die In-Process-Variante (DLL) zum einen wesentlich schneller und zum anderen kommt man "tiefer" als mit COM. Der Grund für das aufwendige Interface ist, dass man von einem per "SendCommand" aufgerufenen Routine keinerlei Rückmeldung erwarten kann (bin mir nicht mal sicher ob man mitbekommt wann der Befehl fertig ist). Über ein richtig implementiertes Interface kannst du aber Ergebnisse wie Strings, Integer, Boolean oder gar ganze Objekte zurückgeben und weiterverarbeiten. Bei mir wird das ganze in einer Art Konfigurator enden der bei manchen Aktionen auf die DWG-Datenbanken zugreift und Informationen extrahiert und als Strukturierte Objekte mit Eigenschaften zurückgibt. Generell muss das Ding aber ohne ACAD laufen. => .Net-Dll wegen Schnelligkeit und tiefem Datenbankzugriff => Exe und Interface zur DLL wegen "Eigentständigkeit" und Rückgabewerten (Objekte) ------------------ Gruß Andreas ------------------------------------------------------------------------------------------------------------------------------------ Die Antwort ist 42! Die Antwort ist 42! Die Antwort ist 42! ...wenn ich nur die Frage wüsste... Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Brischke Moderator CAD on demand GmbH
Beiträge: 4171 Registriert: 17.05.2001 AutoCAD 20XX, defun-tools
|
erstellt am: 21. Feb. 2013 17:01 <-- editieren / zitieren --> Unities abgeben: Nur für Boortsneggor
Zitat: Original erstellt von Andreas Widmann: ... *Humor an* weils einfach cooler is *Humor aus*
das kann ich nachvollziehen. Es gibt so Dinge, da ist der Weg das Ziel. Um die Nachteile deiner weiteren Begründung aus dem Weg zu gehen, verfahre ich anders, wohl weniger aufwändig. Der ganze Zugriff über Com auf AutoCAD geht nur dann, wenn auch ein AutoCAD auf'm Rechner drauf ist. Also kann ich auch gleich alles von AutoCAD aus machen. Um aber die ganze Applikation, die außerhalb vom AutoCAD läuft nicht ein zweites mal für die Verwenung innerhalb vom AutoCAD programmieren zu müssen, habe ich mir angewöhnt, die eigentlichen Dialoge lediglich als Usercontrol zu programmieren. Die Windows-Anwendung und AutoCAD-Applikation implementiert dieses UserControl bzw. implementiert eine Vererbung davon, in der dann die AutoCAD-Funktionen an die Buttons, Listen etc... gebunden sind.
Einziger Nachteil, den ich sehe, der Anwender kann nicht spontan! aus der Windows-Anwenung auf AutoCAD-Inhalte zugreifen. Aber das lässt sich den Anwendern wohl vermitteln, dass bestimmte Funktionen nur vom AutoCAD aus gehen. Ich denke, das ist eine Prinzipfrage. Grüße! Holger ------------------ Holger Brischke FREIE SCHULUNGSPLÄTZE -- C#.NET-Schulung im Mai 2013 Bei Interesse bitte melden! CAD on demand GmbH Individuelle Lösungen von Heute auf Morgen.
defun-tools Das Download-Portal für AutoCAD-Zusatzprogramme!
Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Boortsneggor Mitglied Ingenieur
Beiträge: 49 Registriert: 27.12.2011 Win7 Prof, Visual Studio 2010/2012, ObjectARX 2008/2012/2013, ACAD 2008/2012/2013
|
erstellt am: 21. Feb. 2013 19:39 <-- editieren / zitieren --> Unities abgeben:
Hallo Holger, ich persönlich habe mich für die Com-Dll-Variante entschieden, weil man im AutoCAD zeichnungsübergreifend eingeschränkt ist. Das Interface wird immer erst beim Öffnen einer Zeichnung geladen. Meine Anwendung ist so eine Art Konverter. Ich öffne nacheinander eine Reihe von dwgs, Ersetze und manipuliere Objekte, und speichere diese wieder. Der Vorteil bei meiner Variante ist, dass ich das AutoCAD sichtbar schalten kann und somit die Vorgänge auf den einzelnen Zeichnungen live verfolgen kann. Du hast natürlich recht, man könnte das auch mit SendCommands lösen, aber das ist ja im Grunde das Gleiche. Allerdings können die Commands meiner Erfahrung nach bei dem Ablaufen direkt nacheinander folgender, von einander abhängiger Befehle Probleme machen. Außerdem steht noch der Vorteil, mit den Rückgabewerten, den Andreas angesprochen hat. @Andreas Konntest du dein Problem schon lösen. Ich hab dich wahrscheinlich falsch verstanden. Du hast quasi die Funktionen deines IP-Interfaces bereits direkt getestet. Ob man die com-veröffentlichten Methoden gleichzeitig als Command-Methods verwenden kann, weis ich nicht. Aber ich habe diese bei mir von einander getrennt. Es könnte schon sein, dass das die Ursache deines Fehlers ist. Einen schönen Abend! Grüße Robert ------------------ Robert Menger Gabo Engineering GmbH Entwicklung Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Brischke Moderator CAD on demand GmbH
Beiträge: 4171 Registriert: 17.05.2001 AutoCAD 20XX, defun-tools
|
erstellt am: 21. Feb. 2013 19:57 <-- editieren / zitieren --> Unities abgeben: Nur für Boortsneggor
Zitat: Original erstellt von Boortsneggor: ... weil man im AutoCAD zeichnungsübergreifend eingeschränkt ist. <snip> Ich öffne nacheinander eine Reihe von dwgs, Ersetze und manipuliere Objekte, und speichere diese wieder. ...
auch da sehe ich keinen Grund, das ganze nicht direkt in der AutoCAD-Umgebung zu machen. Gerade wenn es auf Geschwindigkeit ankommt, wenn mehrere Zeichnungen bearbeitet werden sollen, lade ich diese Zeichnungen nur als Database und bearbeite diese ohne anzuzeigen. Es gibt auch Situationen, da kommt man um ein SendStringToExecute nicht umhin. Diesgeht ja bekanntlich nur in aktiven Zeichnungen. Für diese Fälle ist mit 3 Zeilen ein DocumentCreated-Reaktor geschrieben, der die auszuführenden Befehle absetzt. Naja, egal. Ich werde nicht den Weg über Com gehen. Zumal ich ohnehin auch unter .Net auf das Einbinden von Com-Objekten verzichte, da spätestens dadurch die Versions-unabhängigkeit verloren geht (leider ist aber noch nicht alles in der .Net-API enthalten). Das ist bei mir aber vielleicht auch etwas anderes, da meine Kunden imgrunde alle auf dem MArkt verfügbaren AutoCAD-Versionen im Einsatz haben - ich also keinesfalls auf nur eine Version bezogen programmieren kann/will. Grüße! Holger ------------------ Holger Brischke FREIE SCHULUNGSPLÄTZE -- C#.NET-Schulung im Mai 2013 Bei Interesse bitte melden! CAD on demand GmbH Individuelle Lösungen von Heute auf Morgen.
defun-tools Das Download-Portal für AutoCAD-Zusatzprogramme!
Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Boortsneggor Mitglied Ingenieur
Beiträge: 49 Registriert: 27.12.2011 Win7 Prof, Visual Studio 2010/2012, ObjectARX 2008/2012/2013, ACAD 2008/2012/2013
|
erstellt am: 21. Feb. 2013 20:29 <-- editieren / zitieren --> Unities abgeben:
Da hast du wohl ein wichtiges Argument von mir ignoriert. Live-Verfolgung! Außerdem benötigen manche grafische Änderungen die geöffnete Zeichnung. Beispiel Positionierung. Auf das Thema Versionsunabhängigkeit bei AutoCad möchte ich nicht weiter eingehen. Grüße robert ------------------ Robert Menger Gabo Engineering GmbH Entwicklung Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Brischke Moderator CAD on demand GmbH
Beiträge: 4171 Registriert: 17.05.2001 AutoCAD 20XX, defun-tools
|
erstellt am: 21. Feb. 2013 20:37 <-- editieren / zitieren --> Unities abgeben: Nur für Boortsneggor
Zitat: Original erstellt von Boortsneggor: Da hast du wohl ein wichtiges Argument von mir ignoriert. Live-Verfolgung!
ok, manchmal sind die Operationen so langsam, dass man ja tatsächlich schon eine Sichtprüfung während der Bearbeitung machen könnte ;) Zitat: Original erstellt von Boortsneggor: Außerdem benötigen manche grafische Änderungen die geöffnete Zeichnung. Beispiel Positionierung.
... das ist ja ohne weiteres möglich, wenn man es schafft den Befehl automatisiert anzuwerfen. Dafür der oben genannte Reactor, der den Befehl dann anwirft. Zitat: Original erstellt von Boortsneggor: Auf das Thema Versionsunabhängigkeit bei AutoCad möchte ich nicht weiter eingehen.
Das ist sicher gut .. denn das könnte einen weitern Thread füllen. Danke für deine Ausführungen! Grüße! Holger
------------------ Holger Brischke FREIE SCHULUNGSPLÄTZE -- C#.NET-Schulung im Mai 2013 Bei Interesse bitte melden! CAD on demand GmbH Individuelle Lösungen von Heute auf Morgen.
defun-tools Das Download-Portal für AutoCAD-Zusatzprogramme!
Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
| Anzeige.:
Anzeige: (Infos zum Werbeplatz >>)
|