tag:blogger.com,1999:blog-10425945.post111439489907382550..comments2024-03-14T18:15:27.812-03:00Comments on ObjectARX & Dummies: Class 11 - Custom ObjectARX ClassFernando Malardhttp://www.blogger.com/profile/09852061806995998594noreply@blogger.comBlogger36125tag:blogger.com,1999:blog-10425945.post-85918946610216248262017-08-02T08:06:11.382-03:002017-08-02T08:06:11.382-03:00Hi Subir,
You can only read through .NET what was...Hi Subir,<br /><br />You can only read through .NET what was exposed through C++ classes via .NET wrappers.<br />If the Custom Entity author didn't create a mixed-mode module exposing their classes and properties you won't be able to read from .NET anything beyond the AutoCAD base class level information. Thinks like Layer, Color, LineType, etc.<br /><br />To hack DBX object enablers you would need to replicate all the class structure, their embedded objects, their properties and worse, figure out the sequence they were saved into the DWG once it is a binary sequential file.<br /><br />Regards,Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-47029608911113322422017-08-02T00:18:53.758-03:002017-08-02T00:18:53.758-03:00I got a drawing with Custom Entities and also got ...I got a drawing with Custom Entities and also got the Object Enablers. So now the entities show up in the drawing. Now is it possible to read the properties of the Custom Entities through .Net API ? I also need to read the position of the Custom Entity and need to dimension them.<br /><br />My best guess is, the developer of the Custom Entity need to take care about exposing the properties so that those properties can be accessed by .Net API. Am I correct ? Now I don't have anything excepts the object enablers ( dbx ). How to proceed ?CADventurehttps://www.blogger.com/profile/03635563000617167319noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-19426973071272895512009-05-11T05:42:00.000-03:002009-05-11T05:42:00.000-03:00Fernando,
you are probably right. I looked at pol...Fernando,<br /><br />you are probably right. I looked at polysamp and it displays the custom classname in the property palette. But polysamp has several thousand lines and I am not able to find out where the crucial information hides. Trying to adapt compoly to my custom object produced more than 100 errors and I have no idea what idl is & how it works. Probably it's not worth the effort.Marknoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-60854681836602944092009-05-06T11:10:00.000-03:002009-05-06T11:10:00.000-03:00Mark,
OPM dialog uses COM to access your entity's...Mark,<br /><br />OPM dialog uses COM to access your entity's class information.<br /><br />When you derive from a class different of AcDbEntity I guess the OPM use the COM class descriptor to display a name at OPM dialog. If you don't implement the COM interface it will look up the next parent class information which is AcDbPolyline in your case.<br /><br />This seems to be a specific behavior and I'm not sure you can avoid this by implementing some COM interface methods for your custom class. You need to try to see what happens.<br /><br />Have you tried to compile and test PolySamp which derives from AcDbPolyline too but implements a COM interface? Take a look and see what OPM display for it.<br /><br />Regards.Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-34448900347848724502009-05-06T10:58:00.000-03:002009-05-06T10:58:00.000-03:00My custom object is derived from AcDbPolyline. If ...My custom object is derived from AcDbPolyline. If I select the object the property palette shows "Polyline" instead of "MyCustomObject". How can I achieve this ?<br /><br />ThanksMarknoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-61944921362846979822009-05-02T20:15:00.000-03:002009-05-02T20:15:00.000-03:00Hi Mark,
No, DBX modules can contain only non-Aut...Hi Mark,<br /><br />No, DBX modules can contain only non-AutoCAD interface stuff. If you add commands you will violate the DBX/ARX module rules.<br /><br />Regards.Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-52457167996431124132009-05-01T06:01:00.000-03:002009-05-01T06:01:00.000-03:00Fernando,
is it possible to add a command to a db...Fernando,<br /><br />is it possible to add a command to a dbx-module ? I would like to add a command which returns a versioninfo-string.<br />ACED_ARXCOMMAND_ENTRY does not compile in a dbx-module.Marknoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-14255628645382202552009-04-27T15:19:00.000-03:002009-04-27T15:19:00.000-03:00Fernando,
as I see your blog cuts the lines so so...Fernando,<br /><br />as I see your blog cuts the lines so some information is missing.<br />I want to test my solution a bit further to be quite sure that it is ok. At the moment some things simply work but I do not know why.<br /><br />The motivation behind this is to reduce the quite unproductive and error-prone C++ to the minimum (i.e. the custom object DBX). <br />I hope that I do not need C++ any longer for the ARX part.<br />I also do not know whether the wrapper library will have performance impacts.<br /><br />I could not find your email-adress. If you send it to lebakram1_at_gmx.net I will send you the routines which you can hopefully publish in a readable form.Marknoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-74502361520387085912009-04-27T13:57:00.000-03:002009-04-27T13:57:00.000-03:00Mark,
That's great!
If you want, organize the inf...Mark,<br /><br />That's great!<br />If you want, organize the information with the code fragments you built and I can publish it here with credits to you (send me your name, e-mail, etc). This way other people will find it easier.<br /><br />Regards.Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-51068859932331765162009-04-27T13:53:00.000-03:002009-04-27T13:53:00.000-03:00Fernando,
with your help I got it, thanks again :...Fernando,<br /><br />with your help I got it, thanks again :) I hope this may help others as well<br /><br />bool Test1::BPipeline::GapInsert(Autodesk::AutoCAD::Geometry::Point3dCollection& points, const double distance)<br />{<br /> AcGePoint3dArray upta;<br /> for (int i=0; i < points.Count; i++) upta.append(GETPOINT3D(points.get_Item(i)));<br /> return GetImpObj()->GapInsert(upta, distance);<br />}Marknoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-47756468258602815992009-04-27T11:36:00.000-03:002009-04-27T11:36:00.000-03:00Mark,
I'm afraid you will have to copy element by...Mark,<br /><br />I'm afraid you will have to copy element by element once this parameter is an array and its element is also a complex type (a 3D point).<br /><br />Try to copy point by point.<br /><br />Regards.Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-43990906035347372972009-04-27T11:03:00.000-03:002009-04-27T11:03:00.000-03:001. String. I got it working the following way:
a) ...1. String. I got it working the following way:<br />a) In my dbx I changed APipeline(AcString sHatch) to APipeline(const wchar_t* sHatch)<br />b) In my wrapper I wrote<br />APlant::BPipeline::BPipeline(System::String* sHatch) :Autodesk::AutoCAD::DatabaseServices::Polyline(new APipeline(StringToWchar::StringToWchar(sHatch)), true)<br />StringToWchar is defined in mgdinterop.h<br /><br />2. Point3dCollection<br />bool Test1::BPipeline::GapInsert(const Autodesk::AutoCAD::Geometry::Point3dCollection& points, const int distance)<br />{<br /> return GetImpObj()->GapInsert(*reinterpret_cast<const AcGePoint3dArray*>(&(points)), distance);<br />}<br /><br />But this does not compile. How should that be converted ?Marknoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-64881694163333572882009-04-27T09:45:00.000-03:002009-04-27T09:45:00.000-03:00Mark,
You need to marshal the string. Take a look...Mark,<br /><br />You need to marshal the string. Take a look at the Marshal class and more closely to these two methods:<br /><br />Marshal.PtrToStringAuto()<br />Marshal.StringToHGlobalAuto()<br /><br />The "Auto" version of these methods will handle both ANSI and UNICODE scenarios accordingly.<br /><br />More info here:<br />http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal_methods.aspx<br /><br />Let me know if it did the trick.<br />Regards.Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-35761014374588312882009-04-27T09:29:00.000-03:002009-04-27T09:29:00.000-03:00I am still stuck with (invalid conversion)
APlant:...I am still stuck with (invalid conversion)<br />APlant::BPipeline::BPipeline(System::String* sHatch) :Autodesk::AutoCAD::DatabaseServices::Polyline(new APipeline(sHatch), true)<br /><br />I tried<br />APlant::BPipeline::BPipeline(System::String* sHatch) <br />{<br /> const wchar_t __pin* unmngStr = PtrToStringChars(sHatch);<br /> new BPipeline(new APipeline(unmngStr), true);<br />}<br />This compiles, but gives rt message Forgot to call Dispose?Marknoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-83567776331179358702009-04-27T08:13:00.000-03:002009-04-27T08:13:00.000-03:00Mark,
The problem is due the types you are using ...Mark,<br /><br />The problem is due the types you are using at your function's parameters.<br /><br />You need to use .NET AutoCAD types instead of C++ types.<br /><br />For example, does not use AcGePoint3d but use Point3d. Take a look at .NET arxmgd.chm documentation inside ObjectARX doc folder.<br /><br />Change your method's parameter from AcGePoint3dArray to:<br /><br />Autodesk::AutoCAD::Geometry::Point3dCollection.<br /><br />From the doc:<br />"This .NET class wraps the AcGePoint3dArray ObjectARX class. Point3dArray is a template class that uses the AcArray class template."<br /><br />It will do the trick.<br /><br />Regards,<br />Fernando.Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-88340264512122634742009-04-27T06:29:00.000-03:002009-04-27T06:29:00.000-03:00Fernando,
you are on the right track. string did ...Fernando,<br /><br />you are on the right track. string did not work, but<br />BPipeline(System::String* sHatch)<br />does. But how can I convert this to AcString ?<br />APlant::BPipeline::BPipeline(System::String* sHatch) :Autodesk::AutoCAD::DatabaseServices::Polyline(new APipeline(*sHatch), true) {} ?<br />The next headache will be my GapInsert function. I need to find an equivalent for AcGePoint3dArray&<br /><br />You will already have noticed that I am not very familiar with C++.Marknoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-70788049903658983302009-04-26T15:08:00.000-03:002009-04-26T15:08:00.000-03:00Mark,
What happens if you change your other const...Mark,<br /><br />What happens if you change your other constructor from:<br /><br />BPipeline(const AcString sHatch);<br /><br />to:<br /><br />BPipeline(string sHatch);<br /><br />Does it become accessible from VB.NET?<br /><br />I think the problem is related to the parameters types because AcString is not recognized out of your mixed-mode class.<br /><br />Regards.<br /><br />Regards,<br />Fernando.Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-84442840689368573922009-04-25T05:57:00.000-03:002009-04-25T05:57:00.000-03:00My wrapper header file:
namespace Test1 {
...My wrapper header file:<br />namespace Test1 {<br /> <br /> [Autodesk::AutoCAD::Runtime::Wrapper("APipeline")]<br /> public __gc class BPipeline : public Autodesk::AutoCAD::DatabaseServices::Polyline<br /> {<br /><br /> public:<br /> BPipeline();<br /> BPipeline(const AcString sHatch) ;<br /><br /> public private:<br /> BPipeline(System::IntPtr unmanagedPointer, bool autoDelete);<br /> inline APipeline* GetImpObj()<br /> {<br /> return static_cast<APipeline*>(UnmanagedObject.ToPointer());<br /> }<br /><br /> public:<br /> __property void set_Center(Point2d point);<br /> __property Point2d get_Center();<br /> bool GapInsert(const AcGePoint3dArray& points, const int distance);<br /> };<br />}<br /><br />In VB.Net I can do:<br />Dim pl1 as New Test1.BPipeline()<br />but<br />Dim pl1 as New Test1.BPipeline("Test2")<br />fails (constructor not available)<br />The center property is also available but not GapInsertMarknoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-3932495530477620552009-04-24T15:41:00.000-03:002009-04-24T15:41:00.000-03:00Mark,
I see, but it will depend on how you will n...Mark,<br /><br />I see, but it will depend on how you will need to use this DLL.<br /><br />If you create the Wrapper following the ARX guidelines it need to work with both C#, VB.NET or any other VS.NET language.<br /><br />Please, let me know about your progress on that...thanks.Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-86168349324072318252009-04-24T12:50:00.000-03:002009-04-24T12:50:00.000-03:00Fernando,
I created a separate wrapper DLL for .N...Fernando,<br /><br />I created a separate wrapper DLL for .NET. If I open this DLL with Reflector everything looks fine, but if I add the DLL to a VB.NET project I only see the underlying Polyline object and none of my class properties. If you wish, I can send you the DLL or the project.<br /><br />Thanks for your effort.Marknoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-25610915993706496872009-04-23T13:40:00.000-03:002009-04-23T13:40:00.000-03:00Mark,
PInvoke depend on the functions signature (...Mark,<br /><br />PInvoke depend on the functions signature (decorated name) that may change in future releases.<br /><br />For Custom Entities the best solution is to create the Wrapper once it will also expose to .NET only things you want and will respect the ObjectARX open/close mechanism, pointer allocation, etc.<br /><br />If you still want to use Interop I would suggest a better article of my friend Kean Walmsley:<br /><br />http://through-the-interface.typepad.com/through_the_interface/2006/07/calling_objecta.html<br /><br />Regards.Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-71060164572303173182009-04-23T12:31:00.000-03:002009-04-23T12:31:00.000-03:00Further experimenting showed that the ObjectARX .N...Further experimenting showed that the ObjectARX .NET wrapper gives you some more headaches. I found a better solution at <A HREF="http://www.quuxsoft.com/Programming/PInvoke.aspx" REL="nofollow">Invoking Unmanaged Methods from AutoCAD's .NET API"></A>.<br />You can apply this to your own DBX.Marknoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-75932293760190757202009-04-22T14:45:00.000-03:002009-04-22T14:45:00.000-03:00Mark,
That's great.
Thanks for the feedback.
Reg...Mark,<br /><br />That's great.<br />Thanks for the feedback.<br /><br />Regards.Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.comtag:blogger.com,1999:blog-10425945.post-11238653071137382282009-04-22T14:35:00.000-03:002009-04-22T14:35:00.000-03:00I got it, but it was not easy. So I hope this will...I got it, but it was not easy. So I hope this will help other readers as well:<br /><br />In my ObjectARX class explorer there is definitely no "Add a .NET wrapper".<br />I enabled it via editing C:\Program files\Autodesk\ObjectARX Wizards for AutoCAD 2008\ArxAddInWiz\resources\1033\ArxAddinWiz.xml<br />Add in ^ClassExplorer>^ContextMenu>^Project>" the following line:<br />^Entry wizard="vc\vcaddclass\ObjectARX\ArxNETWrapper.vsz">Add a .NET Wrapper...^/Entry><br />You must restart VS that the change takes effect.<br /><br />At first: you must create your ObjectDBX-project with ".NET mixed managed code support" otherwise you will get compilation errors.<br />Now we can right-click on "Add a .NET wrapper".<br />It is important to fill in the correct "Managed Base class". E.g. when your object derives from AcDbPolyline you must fill in Polyline.<br /><br />You will still get compilation errors with GetImpObj. To resolve this you have to add to your StdAfx.h the line #include "yourclass.h".<br />Now you can view your class in the object-explorer. <br /><br />Phew, that was hard work.<br /><br />MarkAnonymousnoreply@blogger.comtag:blogger.com,1999:blog-10425945.post-39247136854561087972009-04-22T10:29:00.000-03:002009-04-22T10:29:00.000-03:00Mark,
COM Wrapper and .NET Wrapper are not the sa...Mark,<br /><br />COM Wrapper and .NET Wrapper are not the same thing.<br /><br />COM Wrapper is used to expose your class to be accessed via COM interface clients such as VBA.<br /><br />.NET Wrapper will create a .NET class to allow your to manipulate your custom C++ class from .NET world.<br /><br />Try to create a simple project, with a custom entity without any COM stuff then open ARX Class View, right click and select .NET Wrapper Wizard.<br /><br />Regards.Fernando Malardhttps://www.blogger.com/profile/09852061806995998594noreply@blogger.com