Author Topic: NET P/INVOKE Routines  (Read 35296 times)

0 Members and 2 Guests are viewing this topic.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
NET P/INVOKE Routines
« on: January 27, 2010, 06:49:43 PM »
LIBRARY THREAD for  AutoCAD P/INVOKE
 Members are encouraged to post any functions, methods, snips regarding
AutoCAD P/INVOKE in .NET : C# ,  VB , F# , Python , etc

Feel free to include comments, descriptive notes, limitations,  and images to document your post.

Please post questions in a regular thread.


added Note:
Be aware that the p/invoke methods sometimes have :
different entry points in different ACAD Versions due to name mangling
and
different entry point signatures dependant on x32 or x64 platforms.
« Last Edit: January 29, 2010, 05:45:35 PM by Kerry Brown »
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

MickD

  • King Gator
  • Posts: 3636
  • (x-in)->[process]->(y-out) ... simples!
Re: NET P/INVOKE Routines
« Reply #1 on: January 27, 2010, 07:40:27 PM »
Here's a few to kick off with, some or all may be obselete now but they may be of use just for reference.

Code: [Select]

        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl,
             EntryPoint = "?acedSetCurrentView@@YA?AW4ErrorStatus@Acad@@PAVAcDbViewTableRecord@@PAVAcDbViewport@@@Z")]
        private static extern int acedSetCurrentView(IntPtr pVtr, /*IntPtr.Zero*/IntPtr pVP);

        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedTrans")]
        static extern int acedTrans(double[] point, IntPtr fromRb, IntPtr toRb, int disp, double[] result);

        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl,
             EntryPoint = "?acedVports2VportTableRecords@@YA?AW4ErrorStatus@Acad@@XZ")]
        private static extern bool acedVports2VportTableRecords();

        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl,
             EntryPoint = "?acedVportTableRecords2Vports@@YA?AW4ErrorStatus@Acad@@XZ")]
        private static extern bool acedVportTableRecords2Vports();
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: NET P/INVOKE Routines
« Reply #2 on: January 27, 2010, 08:50:15 PM »
Since p/invoke methods sometimes have different entry points due to name mangling, maybe it would be a good idea to specify the Acad version.

fixo

  • Guest
Re: NET P/INVOKE Routines
« Reply #3 on: January 28, 2010, 04:06:56 AM »
Since p/invoke methods sometimes have different entry points due to name mangling, maybe it would be a good idea to specify the Acad version.
Would be interesting to see the example of usage as well...:)

~J'~

LE3

  • Guest
Re: NET P/INVOKE Routines
« Reply #4 on: April 13, 2010, 12:52:43 PM »
Just by any chance...
Anyone have done a PInvoke for std:map ?

Like from unmanaged:
Code: [Select]
extern "C" __declspec(dllexport)
void steelMEPcollisions (map<AcDbObjectId, double> pipeDiamMap) { ... }

I wish the above could be to easy like to managed:
Code: [Select]
[DllImport(STEEL_ARX, CallingConvention = CallingConvention.Cdecl, EntryPoint = "steelMEPcollisions ")]
public static extern void CollisionsSteelMEP ( Dictionary<ObjectId, Double> pipeDiamMap );

Thanks.
« Last Edit: August 13, 2010, 02:34:03 PM by LE »

LE3

  • Guest
Re: NET P/INVOKE Routines
« Reply #5 on: April 13, 2010, 01:50:03 PM »
On the mean time, will go into this route:
> To use separate arguments for the ids and the doubles and make sure to keep the same location in their AcArray's - have done some with these types, so guess will be much easier.
 
Like from unmanaged:
Code: [Select]
extern "C" __declspec(dllexport)
void steelMEPcollisions (map<AcDbObjectId, double> pipeDiamMap) { ... }

I which the above could be to easy like to managed:
Code: [Select]
[DllImport(STEEL_ARX, CallingConvention = CallingConvention.Cdecl, EntryPoint = "steelMEPcollisions ")]
public static extern void CollisionsSteelMEP ( Dictionary<ObjectId, Double> pipeDiamMap );

LE3

  • Guest
Re: NET P/INVOKE Routines
« Reply #6 on: April 13, 2010, 08:45:18 PM »
In case someone end up smashing on the same wall:

The ticket (or the easier route for me) was to use resbuf* and ResultBuffer

Code: [Select]
// C++ - unmanaged
extern "C" __declspec(dllexport)
void steelMEPcollisions ( resbuf *pArgs ) { ... }

// C# - managed    
public static class SteelFunctions        
{
    [DllImport(STEEL_ARX, CallingConvention = CallingConvention.Cdecl, EntryPoint = "steelMEPcollisions ")]
    public static extern void CollisionsSteelMEP ( IntPtr pArgs );
}
        
public static void CollisionsMEPSteel ( ResultBuffer args )    
{        
    SteelFunction.CollisionsSteelMEP( args.UnmanagedObject );        
}

ResultBuffer args = new ResultBuffer();                        
args.Add(new TypedValue((int)LispDataType.ListBegin, -1));                        
args.Add(new TypedValue((int)LispDataType.ListBegin, -1));                        
args.Add(new TypedValue((int)LispDataType.Int32, oldIdPtr.ToInt32()));                        
args.Add(new TypedValue((int)LispDataType.Double, diam));                      
args.Add(new TypedValue((int)LispDataType.ListEnd, -1));                        
args.Add(new TypedValue((int)LispDataType.ListEnd, -1));

PInvoke.CollisionsMEPSteel(args);
« Last Edit: April 14, 2010, 10:37:52 AM by LE3 »

jgr

  • Guest
Re: NET P/INVOKE Routines
« Reply #7 on: May 25, 2010, 08:16:17 PM »
FindText "API", with acad 2007 32-bit

Code: [Select]
'#define AC_SRCH_BLOCK         0x01
'#define AC_SRCH_DIM_TEXT      0x02
'#define AC_SRCH_TEXT          0x04
'#define AC_SRCH_LINK_DESC     0x08
'#define AC_SRCH_LINK_URL      0x10
'#define AC_SRCH_MATCH_CASE    0x20
'#define AC_SRCH_WHOLE_WORD    0x40

'#define AC_SRCH_DEFAULT       0x1F

'bool acdbTextFind(AcDbDatabase* pDatabase,
'                  AcDbObjectIdArray& resultSet,
'                  const ACHAR* findString,
'                  const ACHAR* replaceString = NULL,
'                  Adesk::UInt8 searchOptions = AC_SRCH_DEFAULT,
'                  const AcDbObjectIdArray& selSet = 0);

Public Const AC_SRCH_BLOCK As Integer = 1

Public Const AC_SRCH_DIM_TEXT As Integer = 2

Public Const AC_SRCH_TEXT As Integer = 4

Public Const AC_SRCH_LINK_DESC As Integer = 8

Public Const AC_SRCH_LINK_URL As Integer = 16

Public Const AC_SRCH_MATCH_CASE As Integer = 32

Public Const AC_SRCH_WHOLE_WORD As Integer = 64

Public Const AC_SRCH_DEFAULT As Integer = 31


<DllImport("acdb17.dll", CallingConvention:=CallingConvention.Cdecl, CharSet:=CharSet.Unicode, EntryPoint:="?acdbTextFind@@YA_NPAVAcDbDatabase@@AAV?$AcArray@VAcDbObjectId@@V?$AcArrayMemCopyReallocator@VAcDbObjectId@@@@@@PB_W2EABV2@@Z")> _
Private Shared Function acdbTextFind(ByVal pDb As System.IntPtr, _
                                 ByVal resultSet As System.IntPtr, _
                           <System.Runtime.InteropServices.InAttribute(), System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)> ByVal findString As String, _
                           <System.Runtime.InteropServices.InAttribute(), System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)> ByVal replaceString As String, _
                           ByVal searchOptions As Integer, _
                           ByVal selSet As System.IntPtr) As <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.I1)> Boolean
End Function



Public Shared Sub ZZ()

    Dim oidIn As New ObjectIdCollection
    Dim oidOut As New ObjectIdCollection
    Dim ret As Boolean

    Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database

    ret = acdbTextFind(db.UnmanagedObject, oidOut.UnmanagedObject, "hello", Nothing, AC_SRCH_DEFAULT, oidIn.UnmanagedObject)

    If ret Then
        For Each id As ObjectId In oidOut
            '
        Next
    End If

    oidIn.Dispose()
    oidOut.Dispose()
End Sub


can someone explain to me why different entry point signatures dependant on x32 or x64 platforms? i read this in first post, and i do not understand (I come from vba/vb6)
« Last Edit: May 25, 2010, 08:24:59 PM by jgr »

Peter Jamtgaard

  • Guest
Re: NET P/INVOKE Routines
« Reply #8 on: May 28, 2010, 05:41:38 PM »
I have been playing with this for using lisp.

Code: [Select]

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.ApplicationServices
Imports System.Runtime.InteropServices 'for DllImport()
Imports System.Security

<System.Security.SuppressUnmanagedCodeSecurity(), DllImport("acad.exe", CallingConvention:=CallingConvention.Cdecl)> _
    Private Shared Function acedInvoke(ByVal rbIn As IntPtr, <Out()> ByRef rbOut As IntPtr) As Integer
    End Function
    Public Shared Function InvokeLisp(ByVal resbuf As ResultBuffer) As ResultBuffer
        Dim rb As IntPtr = IntPtr.Zero
        Class1.acedInvoke(resbuf.UnmanagedObject, rb)
        Return DirectCast(DisposableWrapper.Create(GetType(ResultBuffer), rb, True), ResultBuffer)
    End Function

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: NET P/INVOKE Routines
« Reply #9 on: May 28, 2010, 06:27:58 PM »

Peter,

Isn't that the code gile posted for you elsewhere ??

Regards,

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: NET P/INVOKE Routines
« Reply #10 on: May 28, 2010, 08:44:43 PM »

Peter,

Isn't that the code gile posted for you elsewhere ??

Regards,



looks like a vb version of  http://www.theswamp.org/index.php?topic=33352.msg387539#msg387539 ?

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: NET P/INVOKE Routines
« Reply #11 on: May 29, 2010, 03:39:43 AM »
Hi,

The code I posted "elsewhere" was greatly inspired by Daniel's and Tony's (here) ones.
Speaking English as a French Frog

Peter Jamtgaard

  • Guest
Re: NET P/INVOKE Routines
« Reply #12 on: May 29, 2010, 08:37:08 AM »

Peter,

Isn't that the code gile posted for you elsewhere ??

Regards,



Yes, I just thought I would add it here, for discussion.

LE3

  • Guest
Re: NET P/INVOKE Routines
« Reply #13 on: August 13, 2010, 02:25:34 PM »
Here is one, I just found out:
Code: [Select]
[DllImport("acad.exe")]
public static extern void acedPostCommandPrompt ( );

Just place this at the end of your function: acedPostCommandPrompt(); and will do the trick.

Have been fighting on re-display the Command: line prompt after calling/executing a function from a modeless form.
i.e:
Command:
Table position:

And after finished with the function, and going back to the form (focus) you will still see in the command line:
Table position:

Until you go to the drawing screen area and do a click with your mouse, for example, and that will bring back the prompt:
Command:

Jeff H

  • Needs a day job
  • Posts: 6150
Re: NET P/INVOKE Routines
« Reply #14 on: August 13, 2010, 05:04:29 PM »
2011 preview icon for blocks if misssing

<DllImport("acad.exe", CallingConvention:=CallingConvention.Cdecl, CharSet:=CharSet.Unicode)> _
   Private Shared Function acedCommand(ByVal type1 As Integer, ByVal command As String, ByVal type2 As Integer, ByVal blockName As String, ByVal [end] As Integer) As Integer

End Function
 acedCommand(5005, "BLOCKICON", 5005, blkName, 5000)