Author Topic: CLR equivalents ?  (Read 8709 times)

0 Members and 1 Guest are viewing this topic.

Spike Wilbury

  • Guest
CLR equivalents ?
« on: September 14, 2008, 12:46:42 AM »
I want to add more options to my ARX/ATL project, by adding some new functions that will be exported via Platform Invocation Services (PInvoke).

Note: First time I use extern "C" __declspec(dllexport)

For example:

ARX function:
Code: [Select]
extern "C" __declspec(dllexport)
void GbPeIntPoly(AcGePoint3d ipt,const TCHAR *LayerName,double dtol,short poltip,double areamin,short dirpolhor,LONG *objid)
{
AcDbLayerTable *LayerTable=NULL;
acdbHostApplicationServices()->workingDatabase()->getSymbolTable(LayerTable,AcDb::kForRead);
if(!LayerTable->has(LayerName))
LayerName=_T("0");
LayerTable->close();
ads_name sspol;
intergbpoly(ipt,LayerName,dtol,poltip,areamin,dirpolhor,sspol);
long length=0;
if ((acedSSLength(sspol,&length) != RTNORM) || (length==0))
{
acedSSFree(sspol);
return;
}
AcDbObjectId objId;
ads_name ename;
acedSSName(sspol,0,ename);
if (acdbGetObjectId(objId,ename) != Acad::eOk) return;
acedSSFree(sspol);
*objid=objId.asOldId();
}

Pinvoke call: Note on this was no problem, at all.
Code: [Select]
[DllImport("GbPolyEngine17.arx", CharSet = CharSet.Auto, EntryPoint = "GbPeIntPoly")]
public static extern void GbPeIntPoly(Point3d point, string layer, double tol, short poltype, double minarea, short poldir, out ObjectId id);

C# function: Note this function works as expected.
Code: [Select]
[CommandMethod("InPoly")]
static public void GbPolyInPoly()
{
    Document doc = AcadApp.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;
    PromptPointResult ptRes = ed.GetPoint("\nPick internal point: ");
    if (ptRes.Status != PromptStatus.OK) return;
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        ObjectId id = new ObjectId();
        Point3d point = new Point3d();
        point = ptRes.Value;
        string polLayer = "TEST"; // Polyline layer - default="0"
        double polTol = 0.001; // Tolerance to find intersections
        short polType = 0; // 0=LWPOLYLINE, 1=POLYLINE
        double polMin = 20.0; // Minimum area for polyline generation
        short polDir = 1; // 0=CLOCKWISE 1=COUNTER-CLOCKWISE
       
        GbPeIntPoly(point, polLayer, polTol, polType, polMin, polDir, out id);

        if (id.IsValid)
        {
            Polyline poly = tr.GetObject(id, OpenMode.ForRead, false) as Polyline;
            if (poly != null)
            {
                ed.WriteMessage("\nThe entity is one [" + poly.GetType().Name + "]");
                ed.WriteMessage("\nObjectId is [{0}]", id.ToString());

                // the generated polyline is now here open for read.
            }
        }
        else if (!id.IsValid && id.IsNull)//test
            ed.WriteMessage("\nObjectId is not valid and null [{0}]", id.ToString());

        tr.Commit();
    }
} //end of InPoly

And here is another ARX function:
Code: [Select]
extern "C" __declspec(dllexport)
void GbPeSSPoly(AcDbObjectIdArray ids,const TCHAR *LayerName,const TCHAR *LayerNameOut,double dtol,short poltip,double areamin,short inpol,short outpol,short dirpolhor,AcDbObjectIdArray *objids)
{
// layers exists?
AcDbLayerTable *LayerTable=NULL;
acdbHostApplicationServices()->workingDatabase()->getSymbolTable(LayerTable,AcDb::kForRead);
if(!LayerTable->has(LayerName))
LayerName=_T("0"); // default
if(!LayerTable->has(LayerNameOut))
LayerNameOut=_T("0"); // default
LayerTable->close();
ads_name sspol;
if (!ids.isEmpty())
gbpoly(ids,LayerName,LayerNameOut,dtol,poltip,areamin,inpol,outpol,dirpolhor,sspol);
// now verify if the selection set has some generated polylines
long len=0;
if ((acedSSLength(sspol,&len) != RTNORM) || (len==0))
{
acedSSFree(sspol);
return;
}
// fill the output array of object ids
for (int i=0; i<len; i++)
{
AcDbObjectId objId;
ads_name ename;
acedSSName(sspol,i,ename);
if (acdbGetObjectId(objId,ename) != Acad::eOk) return;
objids->append(objId);
}
acedSSFree(sspol);
}

Here is my question, where I can find a table or something like the attached image or the equivalent of AcDbObjectIdArray in CLR Type?

I had tried something like:
Code: [Select]
[DllImport("GbPolyEngine17.arx", CharSet = CharSet.Auto, EntryPoint = "GbPeSSPoly")]
public static extern void GbPeSSPoly(ObjectIdCollection ids, string layerInternal, string layerExternal, double tol, short poltype, double minarea, short inpol, short outpol, short poldir, out ObjectIdCollection oids);
//public static extern void GbPeSSPoly(ObjectId[] ids, string layerInternal, string layerExternal, double tol, short poltype, double minarea, short inpol, short outpol, short poldir, out ObjectId[] oids);

Code: [Select]
[CommandMethod("SsPoly")]
static public void GbPolySsPoly()
{
    Document doc = AcadApp.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;

    PromptSelectionOptions prOpts = new PromptSelectionOptions();
    prOpts.MessageForAdding = "\nSelect curve objects: ";

    TypedValue[] filter = new TypedValue[1];
    Object obj = "LINE,ARC,LWPOLYLINE,POLYLINE,CIRCLE";

    filter[0] = new TypedValue(0, obj);
    SelectionFilter ssFilter = new SelectionFilter(filter);

    PromptSelectionResult res = ed.GetSelection(prOpts, ssFilter);
    if (res.Status != PromptStatus.OK) return;

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        string layerInternal = "TESTINT";
        string layerExternal = "TESTEXT";
        double tol = 0.5;
        short poltype = 1;
        double minarea = 20.0;
        short inpol = 1;
        short outpol = 1;
        short poldir = 1;

        ObjectIdCollection ids = new ObjectIdCollection();
        ObjectIdCollection oids = new ObjectIdCollection();

        foreach (ObjectId id in res.Value.GetObjectIds())
            ids.Add(id);

        //ObjectId[] oids = new ObjectId[res.Value.Count];

        try
        {
            //GbPeSSPoly(res.Value.GetObjectIds(), layerInternal, layerExternal, tol, poltype, minarea, inpol, outpol, poldir, out oids);
            GbPeSSPoly(ids, layerInternal, layerExternal, tol, poltype, minarea, inpol, outpol, poldir, out oids);
        }
        catch (System.Exception ex)
        {
            ed.WriteMessage("Error: " + ex.Message);
        }

        tr.Commit();
    }
}

Show this error:
Quote
Select curve objects:
Error: This type has a ComVisible(false) parent in its hierarchy, therefore
QueryInterface calls for IDispatch or class interfaces are disallowed.

Now, I have seen the free pinvoke add-in for VS from pinvoke.net, but have not downloaded, might that work?.... I had use Depends.exe with other dll's and return data types that helps, but not for this arx (that is an ATL COM)

Thanks!
Luis.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8718
  • AKA Daniel
Re: CLR equivalents ?
« Reply #1 on: September 14, 2008, 01:35:43 AM »
Quote
the equivalent of AcDbObjectIdArray in CLR Type?

is ObjectIdCollection.UnmanagedObject right?

Spike Wilbury

  • Guest
Re: CLR equivalents ?
« Reply #2 on: September 14, 2008, 10:24:22 AM »
Quote
the equivalent of AcDbObjectIdArray in CLR Type?

is ObjectIdCollection.UnmanagedObject right?

Hi Daniel,

It has that public property.

Is there something I overlook or did not see?.... :)

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8718
  • AKA Daniel
Re: CLR equivalents ?
« Reply #3 on: September 14, 2008, 10:42:50 AM »
Is there something I overlook or did not see?.... :)

See if this helps
http://www.theswamp.org/index.php?topic=20700.0

Spike Wilbury

  • Guest
Re: CLR equivalents ?
« Reply #4 on: September 14, 2008, 11:14:10 AM »
Daniel,

Nope.... does not work.


I am going to re-think the way I am doing the ARX function.


Thanks!
Luis.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8718
  • AKA Daniel
Re: CLR equivalents ?
« Reply #5 on: September 14, 2008, 11:48:49 AM »
Try changing the signature to
GbPeSSPoly(AcDbObjectIdArray  &ids,….

Spike Wilbury

  • Guest
Re: CLR equivalents ?
« Reply #6 on: September 14, 2008, 12:14:54 PM »
Try changing the signature to
GbPeSSPoly(AcDbObjectIdArray  &ids,….


Daniel,

I tried that one too, before and again.... and no luck.

I am now using std::vector<LONG> and will see, now the problem is how is this data type converted or readed from C#.... Do you know if there is a Table available? - Time to read, I guess....

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8718
  • AKA Daniel
Re: CLR equivalents ?
« Reply #7 on: September 14, 2008, 12:30:31 PM »
I’m not sure what’s going wrong, you should be able to use ObjectIdCollection.
Sorry I can’t test anything right now, I’m on my laptop


Spike Wilbury

  • Guest
Re: CLR equivalents ?
« Reply #8 on: September 14, 2008, 12:42:15 PM »
I’m not sure what’s going wrong, you should be able to use ObjectIdCollection.
Sorry I can’t test anything right now, I’m on my laptop

No problem, Daniel... Thank you for your help.

And yes, sound very obvious the usage of ObjectIdCollection...

Have you used the pinvoke.net add-in? BTW.

The problem is that if I use Depends.exe on my ARX it does not show any signature for my function, and normally you will get from there some data types, useful for doing your pinvoke functions.

Spike Wilbury

  • Guest
Re: CLR equivalents ?
« Reply #9 on: September 14, 2008, 05:00:54 PM »
And Daniel, I found this PInvokeLibAddin in codeproject.com here:

http://www.codeproject.com/KB/macros/PInvokeLibAddin.aspx

And it returns basically the same like:

Quote
[DllImport("TestLib.dll", EntryPoint="GbPeSSPoly", CallingConvention=CallingConvention::Winapi)]
static public void GbPeSSPoly(IntPtr ids,IntPtr LayerName,IntPtr LayerNameOut,Double dtol,Int16 poltip,Double areamin,Int16 inpol,Int16 outpol,Int16 dirpolhor,IntPtr objids);

For now, I can live with the method returned via COM.... that works.

Spike Wilbury

  • Guest
Re: CLR equivalents ?
« Reply #10 on: September 15, 2008, 12:24:32 PM »
And also, I am going to ask on the other side, and see if they have an idea..., I'll post here

The other thing I was avoiding is to use or have a mix project.... I like the idea of a single ARX with the COM and the Pinvoke together.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8718
  • AKA Daniel
Re: CLR equivalents ?
« Reply #11 on: September 15, 2008, 01:05:16 PM »
Have you thought of using C++/CLI to make your wrapper then expose the method to COM via .NET?

Spike Wilbury

  • Guest
Re: CLR equivalents ?
« Reply #12 on: September 15, 2008, 01:29:44 PM »
Have you thought of using C++/CLI to make your wrapper then expose the method to COM via .NET?

Hi Daniel,

Yes, that will be one of the other routes.... do you know if that can be access via reflector? - ummm but won't be much of a problem, I have the main project in ARX....


Thanks.
Luis.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8718
  • AKA Daniel
Re: CLR equivalents ?
« Reply #13 on: September 15, 2008, 08:04:09 PM »
Reflector would not be able to dissemble any of your native code, basically all it would see is a compiler generated P/Invoke. :-)

Spike Wilbury

  • Guest
Re: CLR equivalents ?
« Reply #14 on: September 18, 2008, 11:02:25 AM »
Well,

I found the solution it was just the usage of:

DisposableWrapper.Create();

I'll post the function later from home.

There are some minor things to do, but that's the trick - one thing, appears that it is better (is this the appropriate word?) to use a ResultBuffer (and from the ARX to use a resbuf).... and that can be pass to an Array, ArrayList or List or etc.

But, it was a good excuse to start making some extensions in the mix-code, not bad at all :)

Spike Wilbury

  • Guest
Re: CLR equivalents ?
« Reply #15 on: September 19, 2008, 12:28:39 AM »
Here is the solution:

ARX function
Code: [Select]
extern "C" __declspec(dllexport)
resbuf *GbPeSSPoly(AcDbObjectIdArray &ids,
  const TCHAR *LayerName,
  const TCHAR *LayerNameOut,
  double dtol,
  short poltip,
  double areamin,
  short inpol,
  short outpol,
  short dirpolhor)
{
resbuf* head=NULL;
resbuf* next=NULL;
// layers exists?
AcDbLayerTable *LayerTable=NULL;
acdbHostApplicationServices()->workingDatabase()->getSymbolTable(LayerTable,AcDb::kForRead);
if(!LayerTable->has(LayerName))
LayerName=_T("0"); // default
if(!LayerTable->has(LayerNameOut))
LayerNameOut=_T("0"); // default
LayerTable->close();
ads_name sspol;
if (!ids.isEmpty())
gbpoly(ids,LayerName,LayerNameOut,dtol,poltip,areamin,inpol,outpol,dirpolhor,sspol);
// now verify if the selection set has some generated polylines
long len=0;
if ((acedSSLength(sspol,&len) != RTNORM) || (len==0))
{
acedSSFree(sspol);
return head;
}
// fill the output array of object ids
for (long i=0; i<len; i++)
{
AcDbObjectId objId;
ads_name ename;
acedSSName(sspol,i,ename);
if (acdbGetObjectId(objId,ename) != Acad::eOk) return head;
if(!head)
{
head=acutNewRb(RTLONG);
next=head;
}
else
{
next->rbnext=acutNewRb(RTLONG);
next=next->rbnext;
}
next->resval.rlong=objId.asOldId();
}
acedSSFree(sspol);
return head;
acutRelRb(head);
}

And from C#
Code: [Select]
[DllImport("GbPolyEngine17.arx", CharSet = CharSet.Unicode, EntryPoint = "GbPeSSPoly")]
static extern IntPtr pGbPeSSPoly(IntPtr ptrids, string layerInternal, string layerExternal,
    double tol, short poltype, double minarea, short inpol, short outpol, short poldir);

public static ObjectIdCollection GbPeSSPoly(ObjectIdCollection ids, string layerInternal, string layerExternal,
    double tol, short poltype, double minarea, short inpol, short outpol, short poldir)
{
    ObjectIdCollection oic = new ObjectIdCollection();
    IntPtr ip = IntPtr.Zero;
    ip = pGbPeSSPoly(ids.UnmanagedObject, layerInternal, layerExternal, tol, poltype, minarea, inpol, outpol, poldir);
    if (ip != IntPtr.Zero)
    {
        try
        {
            ResultBuffer rb = DisposableWrapper.Create(typeof(ResultBuffer), ip, true) as ResultBuffer;
            foreach (TypedValue tv in rb)
            {
                ObjectId id = new ObjectId((int)tv.Value);
                oic.Add(id);
            }
            rb.Dispose();
        }
        catch { return null; }
    }
    return oic;
}

[CommandMethod("SsPoly")]
static public void GbPolySsPoly()
{
    Document doc = AcadApp.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;
    PromptSelectionOptions prOpts = new PromptSelectionOptions();
    prOpts.MessageForAdding = "\nSelect curve objects: ";
    TypedValue[] filter = new TypedValue[1];
    Object obj = "LINE,ARC,LWPOLYLINE,POLYLINE,CIRCLE";
    filter[0] = new TypedValue(0, obj);
    SelectionFilter ssFilter = new SelectionFilter(filter);
    PromptSelectionResult res = ed.GetSelection(prOpts, ssFilter);
    if (res.Status != PromptStatus.OK) return;
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        string layerInternal = "TESTINT";
        string layerExternal = "TESTEXT";
        double tol = 0.5;
        short poltype = 1;
        double minarea = 20.0;
        short inpol = 1;
        short outpol = 1;
        short poldir = 1;
        ObjectIdCollection inOids = new ObjectIdCollection();
        ObjectIdCollection outIds = new ObjectIdCollection();
        foreach (ObjectId id in res.Value.GetObjectIds())
            inOids.Add(id);
        try
        {
            outIds = GbPeSSPoly(inOids, layerInternal, layerExternal, tol, poltype, minarea, inpol, outpol, poldir);
            if (outIds.Count > 0)
                ed.WriteMessage("\nNumber[{0}]", outIds.Count.ToString());
        }
        catch (System.Exception ex)
        {
            ed.WriteMessage("Error: " + ex.Message);
        }
        tr.Commit();
    }
}

:)

HTH

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8718
  • AKA Daniel
Re: CLR equivalents ?
« Reply #16 on: September 19, 2008, 10:49:24 PM »
Hi Luis,

I had a chance to play around with this a little. Here is an example of how to do AcDbObjectIdArray <--> ObjectIdCollection

Code: [Select]
extern "C" __declspec(dllexport)
void pTest(AcDbObjectIdArray &ids)
{
  Acad::ErrorStatus es;
  int counter = 0;
  AcDbBlockTableRecord *pTableRecord;
  AcDbDatabase *pDatabase =
    acdbHostApplicationServices()->workingDatabase();
  AcDbBlockTablePointer
    pBlockTable(pDatabase,AcDb::kForRead);
  AcDbBlockTableIterator *pBlockTableIterator;
  pBlockTable->newIterator(pBlockTableIterator);
  for (pBlockTableIterator->start();
       !pBlockTableIterator->done();
        pBlockTableIterator->step())
  {
    es = pBlockTableIterator->getRecord(pTableRecord, AcDb::kForRead,Adesk::kFalse);
    if (es == Acad::eOk &&  pTableRecord->hasAttributeDefinitions() == Adesk::kTrue)
    {
      AcDbObjectIdArray blockReferenceIds;
      pTableRecord->getBlockReferenceIds(blockReferenceIds);
      ids.append(blockReferenceIds);
      pTableRecord->close();
    }
  }
  delete pBlockTableIterator;
}


Code: [Select]
public class Commands
    {
        [DllImport("LuisArx.arx",CallingConvention = CallingConvention.Cdecl)]
        static extern IntPtr pTest(IntPtr ptrIds);

        [CommandMethod("doit")]
        static public void test()
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            try
            {
                ObjectIdCollection ids = new ObjectIdCollection();
                pTest(ids.UnmanagedObject);
                ed.WriteMessage(ids.Count.ToString());
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage(ex.Message);
            }
        }
    }

Spike Wilbury

  • Guest
Re: CLR equivalents ?
« Reply #17 on: September 20, 2008, 12:07:49 AM »
Hi Daniel,

Don't tell me....  :oops: --- well, what can I say....

I'll be doing the update to my project as your code sample.


Thank you.
Luis.