Author Topic: SetCurrentVport in .Net  (Read 3164 times)

0 Members and 1 Guest are viewing this topic.

Keith Brown

  • Swamp Rat
  • Posts: 601
SetCurrentVport in .Net
« on: September 10, 2016, 12:10:39 PM »
I have a need to set the current viewport using C# but I could not find any method that would do so.  I fired up google and came away with a couple of posts shown below.


https://www.theswamp.org/index.php?topic=35873.0
http://forums.autodesk.com/t5/net/set-current-paperspace-viewport-autocad-2011-x64/td-p/2842674
http://www.theswamp.org/index.php?topic=11973.msg148924#msg148924


Unfortunately for whatever reason the solutions posted do not work for me.  The most disappointing was the actual help file from autodesk.  They show like the other posts using an entry point into acad.exe to access the c++ function.  Now I will be the first to admit that I know absolutely nothing about unmanaged code and how to access it but I can copy and paste with the best of them.  So i copied the code and it did not work.  I suspect it was because of a 32/64 bit issue  which Autodesk fails to point out when using unmanaged stuff in their help files.


So i downloaded and fired up dependency walker and got the following two entry points.




So I put them in my code and tried them and I still get an error.  For the first call i get:

{"Unable to find an entry point named '?acedSetCurrentVPort@@YA?AW4ErrorStatus@Acad@@H@Z' in DLL 'acad.exe'.":""} as an error message.

For my second attemp i get this as an error message:

Unable to find an entry point named '?' in DLL 'acad.exe'.

Here is the full code that I am using.

Code - C#: [Select]
  1. public class RotatedDimensionAddStrategy : IDimensionAddStrategy
  2. {
  3.         private readonly Viewport _viewport;
  4.  
  5.         [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedSetCurrentVPort@@YA? AW4ErrorStatus@Acad@@PEBVAcDbViewport@@@Z")]
  6.         private static extern int acedSetCurrentVPort(IntPtr acDbVport);
  7.  
  8.         [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedSetCurrentVPort@@YA?AW4ErrorStatus@Acad@@H@Z")]
  9.         private static extern int acedSetCurrentVPort(int acDbVportNumber);
  10.  
  11.         /// <summary>
  12.         /// Initializes a new instance of the <see cref="RotatedDimensionAddStrategy"/> class.
  13.         /// </summary>
  14.         /// <param name="viewport">The viewport.</param>
  15.         public RotatedDimensionAddStrategy(Viewport viewport)
  16.         {
  17.                 this._viewport = viewport;
  18.         }
  19.  
  20.         /// <summary>
  21.         /// Adds the dimensions.
  22.         /// </summary>
  23.         /// <param name="dimensionLines">The dimension lines.</param>
  24.         public void AddDimensions(List<DimensionLine> dimensionLines)
  25.         {
  26.                 if (dimensionLines == null || dimensionLines.Count == 0)
  27.                 {
  28.                         return;
  29.                 }
  30.                
  31.                 using (Transaction transaction = Active.Database.TransactionManager.StartTransaction())
  32.                 {
  33.                         BlockTableRecord ms = Active.Database.ModelSpace(OpenMode.ForWrite);
  34.                         List<ObjectId> dimensions = new List<ObjectId>();
  35.  
  36.                         Matrix3d worldToView = this._viewport.GetModelToPaperTransform();
  37.                         Vector3d viewDirection = this._viewport.ViewDirection.GetNormal();
  38.                         RotatedDimensionBuilder dimensionBuilder = new RotatedDimensionBuilder(viewDirection, 25, this._viewport.CustomScale);
  39.  
  40.                         foreach (DimensionLine dimensionLine in dimensionLines)
  41.                         {
  42.                                 dimensionBuilder.CreateDimensions(dimensionLine);
  43.                                 if (dimensionBuilder.Dimensions.Count > 0)
  44.                                 {
  45.                                         foreach (RotatedDimension dimension in dimensionBuilder.Dimensions)
  46.                                         {
  47.                                                 dimensions.Add(ms.AppendEntity(dimension));
  48.                                                 transaction.AddNewlyCreatedDBObject(dimension, true);
  49.                                         }
  50.                                 }
  51.                         }
  52.  
  53.                         Viewport viewport = this._viewport.ObjectId.OpenAs<Viewport>();
  54.                         if (dimensions.Count > 0)
  55.                         {
  56.                                 SelectionSet selectionSet = SelectionSet.FromObjectIds(dimensions.ToArray());
  57.                                 ObjectId[] viewPortSelection = new ObjectId[1];
  58.                                 viewPortSelection[0] = this._viewport.ObjectId;
  59.                                 SelectionSet viewportSelectionSet = SelectionSet.FromObjectIds(viewPortSelection);
  60.                                 Active.Editor.Command("MSPACE", viewportSelectionSet);
  61.                                 while (Active.Editor.CurrentViewportObjectId != viewport.ObjectId)
  62.                                 {
  63.                                         //acedSetCurrentVPort(viewport.Number);
  64.                                         acedSetCurrentVPort(viewport.UnmanagedObject);
  65.                                 }
  66.                                 Active.Editor.Command("CHSPACE", selectionSet, "");
  67.                         }
  68.                         transaction.Commit();
  69.                 }
  70.         }
  71. }
  72.  

The code that is meaningful is on lines 63 and 64.  I commented out the first call when trying the second as near as i can tell they both do the samething.

The code basically builds dimensions and them moves them to paperspace through a viewport using the mspace command to open a modelspace inside a viewport and then the chspace command to move the objects from modelspace to paperspace.  I am using the chspace command to handle all of the scaling, rotating, etc automatically of the dimensions.  Everything works great if there is only one viewport.  However, when there are two viewports the mspace command opens up the current viewport instead of the currently selected one.  So i need to change the current viewport and this is the only way i can find.  Sending Ctrl-R to the autocad window using send keys did not work either.  Ctrl-R will switch current viewports when using the mspace command.

Does anyone have any ideas or can see the error that I am making?  I would rather not have to write the code to programmatically move the dimensions from modelspace to paperspace and instead just prefer to automate it with the command.  Unless someone has created something or can point me in the right direction to achieve this.  Thanks.

Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: SetCurrentVport in .Net
« Reply #1 on: September 10, 2016, 12:48:49 PM »
Hi,

Some EntryPoint codes used with P/Invoke change at ObjectARX binary breaks (every major version changes) and many APIs have moved from acad.exe to accore.dll with the 2013 "big split").
There's a tool called "findapi.bat" you can use to find the valid EntryPoint.

I'm not sure to understand what you're trying to do, but, by my side, if I want to activate a paper space viewport (i.e. open this viewport model space) I use the CVPORT sysvar passing it the viewport Number.

Non tested code:
Code - C#: [Select]
  1. Viewport viewport = this._viewport.ObjectId.OpenAs<Viewport>();
  2. Active.Editor.SwitchToModelSpace();
  3. Application.SetSystemVariable("cvport", viewport.Number);
Speaking English as a French Frog

Jeff H

  • Needs a day job
  • Posts: 6150
Re: SetCurrentVport in .Net
« Reply #2 on: September 10, 2016, 02:02:15 PM »
As gile mentioned some methods were moved into accore.dll during the split .
I just looked at 2016 and its inside of accore.dll, and sure its the same for 2013 and up.



So the first argument in DllImport attribute should be "accore.dll"  instead of "acad.exe"

Code - C#: [Select]
  1.  
  2.         [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedSetCurrentVPort@@YA? AW4ErrorStatus@Acad@@PEBVAcDbViewport@@@Z")]
  3.         private static extern int acedSetCurrentVPort(IntPtr acDbVport);
  4.  
  5.         [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedSetCurrentVPort@@YA?AW4ErrorStatus@Acad@@H@Z")]
  6.         private static extern int acedSetCurrentVPort(int acDbVportNumber)
  7.  

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: SetCurrentVport in .Net
« Reply #3 on: September 10, 2016, 10:32:31 PM »
Thank guys.  Both things worked for me.  However, i thought about it some and decided that it was much easier for me to automatic moving the dimensions from model space to paper space.  I was going to need to eventually do this anyway to work with side databases.  I thought it was going to be difficult but realized that it was not really difficult at all.


I already have my modelspace to paperspace transform so i just transformed the dimensions by this transform and added them to paperspace.  I need to scale the dimension values, etc but i have the scale factor of the viewport and it looks like it will work for me instead of using the .mspace and chspace commands.


Additionally i did learn some more about the API that i did not know before.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013