Author Topic: How to make my App supported by multi-versions of AutoCAD?  (Read 5310 times)

0 Members and 1 Guest are viewing this topic.

waterharbin

  • Guest
How to make my App supported by multi-versions of AutoCAD?
« on: February 26, 2012, 01:41:17 AM »
Hi,everyone.
There are lots of versions of AutoCAD. But the SDK is designed for a certain version. So, here comes the problem: how to develop apps supported by multi-versions?

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: How to make my App supported by multi-versions of AutoCAD?
« Reply #1 on: February 26, 2012, 02:03:10 AM »
Hi,

Excepted very few methods or classes which have changed, an application compiled against 2007 SDK will work for all later versions.
Speaking English as a French Frog

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: How to make my App supported by multi-versions of AutoCAD?
« Reply #2 on: May 24, 2013, 01:22:07 AM »
Please correct me if I'm wrong but I'm thinking if you have used [DllImport...] / PInvoke anywhere then you need a separate build for x86 / x64 of each major AutoCAD version. you want it to run in.

Edit: Or I could just correct myself ... http://forums.autodesk.com/t5/NET/Determine-32-or-64-bit-application/m-p/3748030#M32834
« Last Edit: May 24, 2013, 02:07:03 AM by CADbloke »

TheMaster

  • Guest
Re: How to make my App supported by multi-versions of AutoCAD?
« Reply #3 on: May 24, 2013, 09:07:37 AM »
Please correct me if I'm wrong but I'm thinking if you have used [DllImport...] / PInvoke anywhere then you need a separate build for x86 / x64 of each major AutoCAD version. you want it to run in.

Edit: Or I could just correct myself ... http://forums.autodesk.com/t5/NET/Determine-32-or-64-bit-application/m-p/3748030#M32834

Actually, there is no need for any conditional branching at runtime, every time the API is called. You can use Linq.Expression to compile a method at runtime, that invokes the appropriate version of the function based on the same conditions used in the branching that occurs in every call to the API in Alex's example. The branching would simply select one of four extern methods based on the platform and release, and compile a method that invokes it. The same can be done via reflection as well, except that it is slower, which may not be an issue in some cases.

Here is the relevant part of Alex's code from the above referenced post:

Code - C#: [Select]
  1. private static int acedRegisterFilterWinMsg( WindowHookProc callBackFunc )
  2. {
  3.    if( AcadVer >= 19 )
  4.    {
  5.       if( IntPtr.Size == 4 ) return acedRegisterFilterWinMsg2013x32( callBackFunc );
  6.       else return acedRegisterFilterWinMsg2013x64( callBackFunc );
  7.    }
  8.    else
  9.    {
  10.       if( IntPtr.Size == 4 ) return acedRegisterFilterWinMsg2012x32( callBackFunc );
  11.       else return acedRegisterFilterWinMsg2012x64( callBackFunc );
  12.    }
  13. }
  14.  

In the case of the API he's calling, the runtime branching in each call isn't an issue because the API is never called frequently, but in the case of one that is, the last thing you would want to do is have to branch in each call to the 'wrapper', to call the appropriate P/Invoke method (two conditions with 4 possible methods). That is simply out of the question, and unnecessary to begin with.

Here is how I would do it:

Code - C#: [Select]
  1. /// <summary>
  2. /// Static constructor generates acedRegisterFilterWinMsg
  3. /// dynamically at runtime, to call the appropriate P/Invoke
  4. /// method based on release and platform (same must be done
  5. /// for acedRemoveFilterWinMsg, but that's not shown here):
  6. /// </summary>
  7.  
  8. static Func<WindowHookProc, int> acedRegisterFilterWinMsg = null;
  9.  
  10. static HookESC()
  11. {
  12.    MethodInfo target = null;
  13.    bool x64 = IntPtr.Size > 4;
  14.    if( AcadVer > 18 )
  15.    {
  16.       if( x64 )
  17.          target = ( (Func<WindowHookProc, int>)
  18.             acedRegisterFilterWinMsg2013x64 ).Method;
  19.       else
  20.          target = ( (Func<WindowHookProc, int>)
  21.             acedRegisterFilterWinMsg2013x32 ).Method;
  22.    }
  23.    else
  24.    {
  25.       if( x64 )
  26.          target = ( (Func<WindowHookProc, int>)
  27.             acedRegisterFilterWinMsg2012x64 ).Method;
  28.       else
  29.          target = ( (Func<WindowHookProc, int>)
  30.             acedRegisterFilterWinMsg2012x32 ).Method;
  31.    }
  32.  
  33.    var arg = Expression.Parameter( typeof( WindowHookProc ), "arg" );
  34.  
  35.    acedRegisterFilterWinMsg =
  36.       Expression.Lambda<Func<WindowHookProc, int>>(
  37.          Expression.Call( target, arg ), arg ).Compile();
  38.  
  39. }
  40.  
  41.  
« Last Edit: May 24, 2013, 09:30:31 AM by TT »

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: How to make my App supported by multi-versions of AutoCAD?
« Reply #4 on: May 25, 2013, 07:23:05 AM »
Is there anything LINQ can't do?

Code - C#: [Select]
  1.    var arg = Expression.Parameter( typeof( WindowHookProc ), "arg" );
  2.  
  3.    acedRegisterFilterWinMsg =
  4.       Expression.Lambda<Func<WindowHookProc, int>>(
  5.          Expression.Call( target, arg ), arg ).Compile();

Brilliant solution. It's kinda like when I flew a helicopter - I see what you did there, I can follow how it works, I know I can go through the motions and keep it in the air but I also know I need to understand it properly because it is a very big fan, if you know what I mean.

Code - C#: [Select]
  1.  /// ...(same must be done for acedRemoveFilterWinMsg, but that's not shown here):

You always let go of the cyclic while we're in flight. That's a good teaching technique and I like it - I'll never learn to fly properly if I don't need to. I'll try not to crash and burn. No matter, the Visual Studio debugger is a lot more forgiving than gravity.

In plain English, in case my analogy is clearer in my head than yours, dear reader, I like an answer that says "the answer is this way, go find it" and most of Tony's answers tend to do thhat, in case you hadn't noticed. If that annoys you then I don't care. Control-V and a crossed-fingers stab at F5 just doesn't do it for me. I'd rather learn how to fish. I'd rather know what it is that I don't know. Awesome is a valid aspiration, although its attainability can, unfortunately, be variable.

C# Expression Trees happened during that 20-year break I had from coding (yes I did, seriously; no, I don't recommended it) so I'm not up to speed with that that bit of LINQ yet. For those who don't even know where to start with them, try http://msdn.microsoft.com/en-us/library/bb397951.aspx and/or http://pluralsight.com/training/Courses/TableOfContents/linq-fundamentals (and others) and/or spend a night / week with Google, http://StackOverflow.com and caffeine. Lots of all of those. I'll see you there.
.
For those of us who look at TT's answers and think "Dammit! I will never be that good at this." - welcome to the club. See also Jon Skeet. We may be right to varying degrees but that's no excuse for not striving to be these best you can be at this, or at least better than you were yesterday. Don't let the presence of brilliant minds (there are a few around here) scare you into silence - you won't learn anything if you don't make a dill of yourself once every now and then. I'm a voracious learner, as you may have seen from time to time.

Thanks for this and every other answer Tony, and others.

kaefer

  • Guest
Re: How to make my App supported by multi-versions of AutoCAD?
« Reply #5 on: May 25, 2013, 04:02:15 PM »
Here is how I would do it:

Code - C#: [Select]
  1. /// <summary>
  2. /// Static constructor generates acedRegisterFilterWinMsg
  3. /// dynamically at runtime, to call the appropriate P/Invoke
  4. /// method based on release and platform (same must be done
  5. /// for acedRemoveFilterWinMsg, but that's not shown here):
  6. /// </summary>
  7.  
  8. static Func<WindowHookProc, int> acedRegisterFilterWinMsg = null;
  9.  
  10. static HookESC()
  11. {
  12.    MethodInfo target = null;
  13.    bool x64 = IntPtr.Size > 4;
  14.    if( AcadVer > 18 )
  15.    {
  16.       if( x64 )
  17.          target = ( (Func<WindowHookProc, int>)
  18.             acedRegisterFilterWinMsg2013x64 ).Method;
  19.       else
  20.          target = ( (Func<WindowHookProc, int>)
  21.             acedRegisterFilterWinMsg2013x32 ).Method;
  22.    }
  23.    else
  24.    {
  25.       if( x64 )
  26.          target = ( (Func<WindowHookProc, int>)
  27.             acedRegisterFilterWinMsg2012x64 ).Method;
  28.       else
  29.          target = ( (Func<WindowHookProc, int>)
  30.             acedRegisterFilterWinMsg2012x32 ).Method;
  31.    }
  32.  
  33.    var arg = Expression.Parameter( typeof( WindowHookProc ), "arg" );
  34.  
  35.    acedRegisterFilterWinMsg =
  36.       Expression.Lambda<Func<WindowHookProc, int>>(
  37.          Expression.Call( target, arg ), arg ).Compile();
  38.  
  39. }
  40.  

Sorry for showing my ignorance. I do get your RunCommand example, an expression based wrapper for getting behind the privacy of a method, super-fast and near devine. But this escapes me:

Why do you extract the MethodInfo from a Delegate and construct another Delegate with an identical signature from it, which is basically an identity operation? That is, could you just say the following and be done with it?

Code - C#: [Select]
  1.   if( AcadVer > 18 )
  2.   {
  3.      if( x64 )
  4.         acedRegisterFilterWinMsg = acedRegisterFilterWinMsg2013x64;
  5.      else
  6.         acedRegisterFilterWinMsg = acedRegisterFilterWinMsg2013x32;
  7.   }
  8.   else
  9.   {
  10.      if( x64 )
  11.         acedRegisterFilterWinMsg = acedRegisterFilterWinMsg2012x64;
  12.      else
  13.         acedRegisterFilterWinMsg = acedRegisterFilterWinMsg2012x32;
  14.   }

TheMaster

  • Guest
Re: How to make my App supported by multi-versions of AutoCAD?
« Reply #6 on: May 25, 2013, 05:40:06 PM »
Yes, you're right. In this case, the arguments are the same so there's no point to compiling an expression.

I was following the pattern I use in cases where I P/Invoke native APIs that have differening sigs on 32 and 64 bit builds (this was the case in previous AutoCAD releases also).

In fact, what I posted will end up that way anyways after the jit compiler inlines the method call.