AutoCAD.NET二次开发注意事项与开发技巧
2014-03-05 12:03
267 查看
1、如果要在Winform中打开DWG图形文件,这个Form必须用Application.ShowModelessDialog方式显示,不然会报错(执行环境无效)。
2、在非模态窗口中修改实体时,需要将图层锁定,否则会报错;模态窗口则无此情况。
3、写块克隆:WblockCloneObjects第二个参数为块表记录模型空间的ObjectID,此方法会将一个对象集(实体集)完全克隆到另一个DWG文件中,包括图层名、图层设置、坐标位置、扩展数据等。
4、在CAD中用后台打开方式打开DWG图形文件,并进行修改后,要用SaveAs保存,用Save会出错。
5、使用模态窗口时,如果需要与CAD主窗体进行交互,则用using (EditorUserInteraction edUI = ed.StartUserInteraction(this));使用非模态窗口时,会出现焦点切换问题 (如:当在非模态窗口中点击按钮后要去CAD中选择一个实体,但是应用程序的焦点还在非模态窗口中,此时需要在CAD主窗口中点击一下让CAD获取焦点,才能正常进行实体选取),此时可以用WinAPI中的SetFocus将焦点移到CAD主窗口即可:
调用:
要注意的是:需要配合窗体的MouseEnter、MouseLeave事件使用,但效果并不太理想,如果鼠标移动较快的时候,事件来不及触发。暂时还没有找到其他更好的方法,C++中可以接收一个KeepFocus消息,来监视和设置程序焦点,使焦点转换更灵活,C#中也可以收到CAD发来的这个消息,但是这个消息的Msg值不是固定的,C++中使用的时候不需要管这个值,因为是由CAD已经提供了,所以可以准确地方监听这个消息;但是在C#中CAD并没有提供这个Msg值,所以并不能使用监听Windows消息的方法来实现焦点的切换功能。
6、AutoCAD.NET获取CAD当前图层代码:
7、AutoCAD 注册表项在32位与64系统中的不同
AutoCAD注册表信息读取,如获取电脑上已安装的所有CAD版本、安装路径等注册表信息。在32位Windows系统中,这些信息保存在:HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD 中;而64位Windows系统中,32位的CAD软件信息保存在 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Autodesk\AutoCAD 中,64位CAD软件信息保存在 HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD 中。
在64位系统中,安装的CAD版本可能是32位,也可能是64位。如果在32位的CAD中调用我们的DLL,此DLL读取 HKEY_LOCAL_MACHINE\SOFTWARE 时,实际读到的是 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node;如果在64位的CAD中调用我们的DLL,则此时DLL读取 HKEY_LOCAL_MACHINE\SOFTWARE 时,会得到真正的HKEY_LOCAL_MACHINE\SOFTWARE 对象。
上述情况是因为,为了做到64位系统兼容32位程序,同时又为了防止注册表项冲突,所以32位应用程序在64位Windows系统中操作 HKEY_LOCAL_MACHINE\SOFTWARE 键时会被自动转到 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node。(具体说明可见:/article/4898537.html)
这种问题的解决方法参考:
较通用的WINAPI方法
/article/4898538.html
适用.NET 4.0的新方法:
/article/5157930.html
但是还有一点要注意:在CAD二次开发中,由于我们的DLL最终是要被CAD调用的,所以我们程序集的位数是由CAD的位数来决定的。
8、修改命令快捷键并立即生效
在CAD中点击:工具-》自定义-》编辑程序参数(acad.pgp),在打开的文件中找到“Command alias format”,在其下方可以看到命令别名定义列表,定义的格式为:“别名,*命令”,每行只能定义一个,定义完成之后,重启CAD即可生效。如果不想重启CAD,还有两种方式可以让你的定义生效:
1)、在命令文本中输入reinit,回车,在弹窗中选中“PGP文件”,然后确定,如下图:
2)、在命令文本中输入re-init,回车,然后输入16,再回车即可。
第二种方法应该可以在程序中进行实现,不知道AutoCAD.NET中有没有提供现成的方法,不过可以用sendcommand实现。这样可以为用户提供快捷键的自定义功能,并且在用户定义完之后,可以立即生效。acad.pgp文件位置在:CAD安装目录\UserDataCache\Support中,是一个隐藏文件。
9、eInvalidOpenState错误问题
当在事务A中调用GetObject方法获取了对象E,在事务A结束之后,如果在另一个事务B中调用E的UpgradeOpen时,会出现错误提示:eInvalidOpenState,这时候需要在事务B中用GetObject根据E.ObjectId重新获取E才行。
10、eWasNotOpenForWrite错误问题
同问题情况类似,在事务A中调用GetObject方法获取了对象E,在事务A结束之后,如果在另一个事务B中调用E的DowngradeOpen方法,则会出现错误提示:eWasNotOpenForWrite,这时候需要在事务B中用GetObject根据E.ObjectId重新获取E。
11、SelectionFilter 根据XData扩展数据过滤选择集问题
使用根据对象的扩展数据XData进行过滤选择时,如果过滤条件仅为DxfCode.ExtendedDataRegAppName(即注册的应用程序名)时,可以过滤所有类型的对象,但是如果要用DxfCode.ExtendedDataAsciiString、DxfCode.ExtendedDataInteger16等具体数据内容进行过滤时,则仅能选取到部分类型的对象,如:Line、PolyLine、Ellipse、Region,而像DBText、MText、Circle等类型的实体则会被忽略掉。
12、SelectionFilter过滤选择单行文本对象问题
用SelectionFilter过滤选择文本时,切记单行文本必须写成TypedValue((int)DxfCode.Start,"Text"),要写成"Text",而不是"DBText"。
13、用Hatch填充时的问题
用Hatch填充Region时,如果面域对象是由多个面域合并而来,会填充失败,此时可以调用Region对象的Explode方法将Region炸散,得到多个Region,然后将这些Region一一填充。
对于Hatch.AppendLoop第二个参数:ObjectIdCollection 类型,传入的是一个或多个实体对象的ID,这些实体必须满足以下几个条件:
1)、如果只传入一个对象,那么这个对象必须是一个非“回”字型闭合对象,如闭合的pline、单个的Region、Circle、Ellipse等;如果传入的对象是回字型,即中间是空心的,那么将会报错,填充将失败。
2)、如果传入的是多个对象,那么这些对象必须正好可以首尾相接地组成一个闭合图形,且没有富余的对象,这样才能成功填充;如果组成的图形不能闭合,或者闭合后还剩余一些无用处的线、弧等,又或者组成了多个闭合图形,那么将会报错,填充将失败。
14、嵌套事务问题
使用嵌套事务时,好像如果外层的事务不提交,即使里面的事务提交了,最终也会失效,不知道这种说法对不对,因为今天我在里层的事务里创建了一个Hatch并且提交了事务,在代码里看Hatch已经完全创建成功了,但是外层的事务没有提交,结果执行结束后在CAD中完全找不到Hatch的影子。
15、Autodesk.AutoCAD.DatabaseServices.DataTable 扩展数据表使用时要注意
当对象实体的扩展字典中还没有这个表时,DBDictionary.SetAt 和 Transaction.AddNewlyCreatedDBObject 将扩展数据表添加到实体对象,但是修改时就不能再这样了,只需要获取DataTable对象,然后用 DataTable.SetCellAt 方法修改数据表的值,最后提交事务即可。(注:向实体扩展字典中添加DataTable时,必须将DataTable添加到BlockTableRecord中,不然在保存CAD图纸的时候,会保存失败)。
16、PaletteSet停靠。
PaletteSet可以用程序控制其最小尺寸,停靠位置,可停靠位置,按钮、菜单显示等,但是用程序指定其停靠位置时,每个面板只能占据单独一列或一行,不能做到让多个面板上下同列多行停靠,或左右同行多列停靠。
PaletteSet有两个重载函数,一般都用第一个,即在声明PaletteSet时只传一个name参数。第二个重载有两个参数,一个是name参数,一个是guid参数,CAD会以这个guid为标识,记录此面板的位置、大小等信息,这样在下一次,加载这个面板的时候,如果不指定面板的Dock属性,则会自动使用上次保存的设置来管理面板的停靠位置和大小等。即:第一次在CAD里加载此面板时,可以给面板指定一个默认的停靠位置,此时用户可以随意拖动面板重新指定停靠位置,当用户关闭CAD时,这个面板的停靠设置会被CAD保存下来,下一次加载的时候,如果不再给此面板指定Dock属性,则会自动使用上次保存的设置信息进行停靠,要实现这一点,最好用PaletteSet的Add和Save事件进行配合(具体实现,请看这篇文章)。
但是,这种实现方式,会有一个问题:如果在声明PaletteSet时指定了传了name参数,CAD会自动创建一个和这个name一样的启动命令,就像每次打开CAD时的“COMMANDLINE”命令一样,每次CAD启动时都会执行,但是我们创建PaletteSet的方法并不一定会声明成为一个命令,而且就算声明成命令,这个命令也不一定和PaletteSet的name参数一样,这样在CAD启动时,就会提示“未知命令”,令人很不爽,解决方法有三种:
1、将创建PaletteSet的方法声明为一个命令,且命令要和PaletteSet的name参数保持一致,而且你的dll要随CAD自动启动(可以用注册表方法实现),但是这种方法太过狭隘,并不好。
2、在声明PaletteSet的时候,name参数只传一个空字符串,PaletteSet实例化之后,再为PaletteSet指定Text属性指定面板的名称即可,这样CAD启动时,就不会自动执行命令了。
3、CAD保存面板停靠信息时,是保存在特殊文件夹Application Data中的,即C#中的Environment.SpecialFolder.ApplicationData文件夹,比如我在XP系统中用32位CAD 2008测试,保存路径为:C:\Documents and Settings\Administrator\Application Data\Autodesk\AutoCAD 2008\R17.1\chs\Support\Profiles\FixedProfile.aws,这是一个xml文件。
如果声明PaletteSet的时候指定了第二个guid参数,CAD会在FixedProfile.aws文件ToolsInfo节点中添加一个Tool节点,用来保存面板信息,同时会在StartupInfo中也添加一个Tool节点,指定启动命令,这个启动命令和PaletteSet的name参数一样,就算在声明PaletteSet的时候传的是一个空字符串,CAD也会在StartupInfo节点下添加一个Command=""的启动命令,CAD启动时,应该是会把空命令忽略,所以使用第二个解决方法,CAD在启动时不会执行面板对应的启动命令,如果你对此有强迫症,不希望CAD保存启动命令节点的话,那么你可以自行将其删除,方法如下:
在声明PaletteSet的时候,可以随意指定name属性,或干脆留空,这个不再有影响;实现CAD提供的IExtensionApplication接口,此的接口中的Terminate会在你的DLL被卸载时(即CAD被关闭时)执行,我们可以在这个方法内,打开当前CAD对应的FixedProfile.aws文件,然后把StartupInfo节点下面板对应的启动命令删除,此命令和之前声明PaletteSet的时候指定的name参数一样,删除之后,保存FixedProfile.aws文件即可。
17、Application.ShowModelessDialog在不同版本CAD的调用不同
在CAD2010之前,这个方法有三个重载:
而在CAD2010中,这个方法有五个重载:
然而,在CAD2010中,第三和第五个重载并没有什么用,因为CAD2010的窗体对象(Application.MainWindow,即Autodesk.AutoCAD.Windows.Window类)不再实现IWin32Window接口,所以第一个参数没办法传了,只能使用第一、二、四个重载方法。这是我目前的研究结果,不知道第三、第五个重载方法在CAD2010中还有没有其他使用方式。
另外,上面的ShowModelessDialog是针对Winform窗体的,而CAD2010的窗体却都是WPF的,于是在CAD2010中又提供了一个新接口方法:ShowModelessWindow,这个方法也是有五个重载:
这个接口方法是用来显示WPF窗体对象的,但是,虽然有五个重载方法,但是应该和ShowModelessDialog一样,只有第一、二、四个方法能正常使用。
18、不允许所请求的注册表访问权。在win7等64位操作系统中,在CAD调用的C# dll插件中,如果操作注册表(读取、写入等),可能会报这个错误,原因是CAD不是以管理员权限运行的,权限不足,要防止这种情况发生,需要让CAD以管理员身份运行,在CAD的快捷方式或安装目录下的acad.exe上右键,选择“属性”,切换到“兼容性”页面,选中“以管理员身份运行此程序”,这样就不会出现这种情况了。
另外,对于这种错误,网上还有一种解决方案,是在操作注册表的方法上加上RegistryPermissionAttribute属性标识,如[RegistryPermissionAttribute(SecurityAction.PermitOnly, Read = @"HKEY_LOCAL_MACHINE\SOFTWARE\YourApp")],但是这种情况在CAD开发上好像并不适用,会提示错误。
19、在使用各种实体对象之后(如DBObject、Entity、Region、Polyline、DBObjectCollection等),尽量主动调用其Dispose方法进行释放,否则当你频繁对一组实体进行重复操作时,可能会引发一些错误,甚至引起CAD的崩溃。比如我碰到的一种情况:http://www.cnblogs.com/bomb12138/p/4552507.html这里面的第2条。
20、如果为面域指定了实体颜色,在此面域和其他面域进行了布尔运算之后(面域相加、相减、合并),面域的颜色会变成ByLayer 。
21、用注册表实现C#DLL或C++ARX随CAD自动加载,可以往以下两个地方添加启动信息:
1)、HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\RXX.X\ACAD-XXXX:XXX\Applications
2)、64位系统中的64位CAD 或 32位系统中的CAD:HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\RXX.X\ACAD-XXXX:XXX\Applications
64位系统中的32位CAD:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Autodesk\AutoCAD\RXX.X\ACAD-XXXX:XXX\Applications
其中,Current_User项不分32位和64位,而LOCAL_Machine则会分32位和64位,用程序进行注册表读写时需要注意。但是CURRENT_USER注册表信息只对当前登录的系统用户有效,而LOCAL_MACHINE注册表信息则会对系统所有用户都有效。
C#DLL或C++ARX随CAD启动需要向Applications项中添加一个自己命名的项,然后在该项下添加以下几个值:
22、用过滤选择进行polyine的时候,类型名必须写成LWPolyline,而要过滤选择polyline2d对象时,类型名要写成polyline。
23、关于Document.CommandEnded事件:正常来说自己定义的命令都应该可以触发CommandEnded事件,但如果你的命令中使用了Application.ShowModelDialog,那么你的命令将不会触发CommandEnded事件,如果把Application.ShowModelDialog换成Form本身的ShowDialog,则可以正常触发CommandEnded事件。
24、使用VS2010 + AutoCAD2008进行开发时,如果不能调试,可以尝试修改AutoCAD2008安装目录中的acad.exe.config文件:
25、使用SendStringToExecute向CAD发送命令时,如果命令参数中带有路径,这时如果执行有问题,可以尝试使用“/”代替路径中的“\”。
2、在非模态窗口中修改实体时,需要将图层锁定,否则会报错;模态窗口则无此情况。
3、写块克隆:WblockCloneObjects第二个参数为块表记录模型空间的ObjectID,此方法会将一个对象集(实体集)完全克隆到另一个DWG文件中,包括图层名、图层设置、坐标位置、扩展数据等。
4、在CAD中用后台打开方式打开DWG图形文件,并进行修改后,要用SaveAs保存,用Save会出错。
5、使用模态窗口时,如果需要与CAD主窗体进行交互,则用using (EditorUserInteraction edUI = ed.StartUserInteraction(this));使用非模态窗口时,会出现焦点切换问题 (如:当在非模态窗口中点击按钮后要去CAD中选择一个实体,但是应用程序的焦点还在非模态窗口中,此时需要在CAD主窗口中点击一下让CAD获取焦点,才能正常进行实体选取),此时可以用WinAPI中的SetFocus将焦点移到CAD主窗口即可:
[DllImport("user32.dll", EntryPoint = "SetFocus")] public static extern int SetFocus(IntPtr hWnd);
调用:
SetFocus(Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Window.Handle);
要注意的是:需要配合窗体的MouseEnter、MouseLeave事件使用,但效果并不太理想,如果鼠标移动较快的时候,事件来不及触发。暂时还没有找到其他更好的方法,C++中可以接收一个KeepFocus消息,来监视和设置程序焦点,使焦点转换更灵活,C#中也可以收到CAD发来的这个消息,但是这个消息的Msg值不是固定的,C++中使用的时候不需要管这个值,因为是由CAD已经提供了,所以可以准确地方监听这个消息;但是在C#中CAD并没有提供这个Msg值,所以并不能使用监听Windows消息的方法来实现焦点的切换功能。
6、AutoCAD.NET获取CAD当前图层代码:
Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database.Clayer;
7、AutoCAD 注册表项在32位与64系统中的不同
AutoCAD注册表信息读取,如获取电脑上已安装的所有CAD版本、安装路径等注册表信息。在32位Windows系统中,这些信息保存在:HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD 中;而64位Windows系统中,32位的CAD软件信息保存在 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Autodesk\AutoCAD 中,64位CAD软件信息保存在 HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD 中。
在64位系统中,安装的CAD版本可能是32位,也可能是64位。如果在32位的CAD中调用我们的DLL,此DLL读取 HKEY_LOCAL_MACHINE\SOFTWARE 时,实际读到的是 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node;如果在64位的CAD中调用我们的DLL,则此时DLL读取 HKEY_LOCAL_MACHINE\SOFTWARE 时,会得到真正的HKEY_LOCAL_MACHINE\SOFTWARE 对象。
上述情况是因为,为了做到64位系统兼容32位程序,同时又为了防止注册表项冲突,所以32位应用程序在64位Windows系统中操作 HKEY_LOCAL_MACHINE\SOFTWARE 键时会被自动转到 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node。(具体说明可见:/article/4898537.html)
这种问题的解决方法参考:
较通用的WINAPI方法
/article/4898538.html
适用.NET 4.0的新方法:
/article/5157930.html
但是还有一点要注意:在CAD二次开发中,由于我们的DLL最终是要被CAD调用的,所以我们程序集的位数是由CAD的位数来决定的。
8、修改命令快捷键并立即生效
在CAD中点击:工具-》自定义-》编辑程序参数(acad.pgp),在打开的文件中找到“Command alias format”,在其下方可以看到命令别名定义列表,定义的格式为:“别名,*命令”,每行只能定义一个,定义完成之后,重启CAD即可生效。如果不想重启CAD,还有两种方式可以让你的定义生效:
1)、在命令文本中输入reinit,回车,在弹窗中选中“PGP文件”,然后确定,如下图:
2)、在命令文本中输入re-init,回车,然后输入16,再回车即可。
第二种方法应该可以在程序中进行实现,不知道AutoCAD.NET中有没有提供现成的方法,不过可以用sendcommand实现。这样可以为用户提供快捷键的自定义功能,并且在用户定义完之后,可以立即生效。acad.pgp文件位置在:CAD安装目录\UserDataCache\Support中,是一个隐藏文件。
9、eInvalidOpenState错误问题
当在事务A中调用GetObject方法获取了对象E,在事务A结束之后,如果在另一个事务B中调用E的UpgradeOpen时,会出现错误提示:eInvalidOpenState,这时候需要在事务B中用GetObject根据E.ObjectId重新获取E才行。
10、eWasNotOpenForWrite错误问题
同问题情况类似,在事务A中调用GetObject方法获取了对象E,在事务A结束之后,如果在另一个事务B中调用E的DowngradeOpen方法,则会出现错误提示:eWasNotOpenForWrite,这时候需要在事务B中用GetObject根据E.ObjectId重新获取E。
11、SelectionFilter 根据XData扩展数据过滤选择集问题
使用根据对象的扩展数据XData进行过滤选择时,如果过滤条件仅为DxfCode.ExtendedDataRegAppName(即注册的应用程序名)时,可以过滤所有类型的对象,但是如果要用DxfCode.ExtendedDataAsciiString、DxfCode.ExtendedDataInteger16等具体数据内容进行过滤时,则仅能选取到部分类型的对象,如:Line、PolyLine、Ellipse、Region,而像DBText、MText、Circle等类型的实体则会被忽略掉。
12、SelectionFilter过滤选择单行文本对象问题
用SelectionFilter过滤选择文本时,切记单行文本必须写成TypedValue((int)DxfCode.Start,"Text"),要写成"Text",而不是"DBText"。
13、用Hatch填充时的问题
用Hatch填充Region时,如果面域对象是由多个面域合并而来,会填充失败,此时可以调用Region对象的Explode方法将Region炸散,得到多个Region,然后将这些Region一一填充。
对于Hatch.AppendLoop第二个参数:ObjectIdCollection 类型,传入的是一个或多个实体对象的ID,这些实体必须满足以下几个条件:
1)、如果只传入一个对象,那么这个对象必须是一个非“回”字型闭合对象,如闭合的pline、单个的Region、Circle、Ellipse等;如果传入的对象是回字型,即中间是空心的,那么将会报错,填充将失败。
2)、如果传入的是多个对象,那么这些对象必须正好可以首尾相接地组成一个闭合图形,且没有富余的对象,这样才能成功填充;如果组成的图形不能闭合,或者闭合后还剩余一些无用处的线、弧等,又或者组成了多个闭合图形,那么将会报错,填充将失败。
14、嵌套事务问题
使用嵌套事务时,好像如果外层的事务不提交,即使里面的事务提交了,最终也会失效,不知道这种说法对不对,因为今天我在里层的事务里创建了一个Hatch并且提交了事务,在代码里看Hatch已经完全创建成功了,但是外层的事务没有提交,结果执行结束后在CAD中完全找不到Hatch的影子。
15、Autodesk.AutoCAD.DatabaseServices.DataTable 扩展数据表使用时要注意
当对象实体的扩展字典中还没有这个表时,DBDictionary.SetAt 和 Transaction.AddNewlyCreatedDBObject 将扩展数据表添加到实体对象,但是修改时就不能再这样了,只需要获取DataTable对象,然后用 DataTable.SetCellAt 方法修改数据表的值,最后提交事务即可。(注:向实体扩展字典中添加DataTable时,必须将DataTable添加到BlockTableRecord中,不然在保存CAD图纸的时候,会保存失败)。
16、PaletteSet停靠。
PaletteSet可以用程序控制其最小尺寸,停靠位置,可停靠位置,按钮、菜单显示等,但是用程序指定其停靠位置时,每个面板只能占据单独一列或一行,不能做到让多个面板上下同列多行停靠,或左右同行多列停靠。
PaletteSet有两个重载函数,一般都用第一个,即在声明PaletteSet时只传一个name参数。第二个重载有两个参数,一个是name参数,一个是guid参数,CAD会以这个guid为标识,记录此面板的位置、大小等信息,这样在下一次,加载这个面板的时候,如果不指定面板的Dock属性,则会自动使用上次保存的设置来管理面板的停靠位置和大小等。即:第一次在CAD里加载此面板时,可以给面板指定一个默认的停靠位置,此时用户可以随意拖动面板重新指定停靠位置,当用户关闭CAD时,这个面板的停靠设置会被CAD保存下来,下一次加载的时候,如果不再给此面板指定Dock属性,则会自动使用上次保存的设置信息进行停靠,要实现这一点,最好用PaletteSet的Add和Save事件进行配合(具体实现,请看这篇文章)。
但是,这种实现方式,会有一个问题:如果在声明PaletteSet时指定了传了name参数,CAD会自动创建一个和这个name一样的启动命令,就像每次打开CAD时的“COMMANDLINE”命令一样,每次CAD启动时都会执行,但是我们创建PaletteSet的方法并不一定会声明成为一个命令,而且就算声明成命令,这个命令也不一定和PaletteSet的name参数一样,这样在CAD启动时,就会提示“未知命令”,令人很不爽,解决方法有三种:
1、将创建PaletteSet的方法声明为一个命令,且命令要和PaletteSet的name参数保持一致,而且你的dll要随CAD自动启动(可以用注册表方法实现),但是这种方法太过狭隘,并不好。
2、在声明PaletteSet的时候,name参数只传一个空字符串,PaletteSet实例化之后,再为PaletteSet指定Text属性指定面板的名称即可,这样CAD启动时,就不会自动执行命令了。
3、CAD保存面板停靠信息时,是保存在特殊文件夹Application Data中的,即C#中的Environment.SpecialFolder.ApplicationData文件夹,比如我在XP系统中用32位CAD 2008测试,保存路径为:C:\Documents and Settings\Administrator\Application Data\Autodesk\AutoCAD 2008\R17.1\chs\Support\Profiles\FixedProfile.aws,这是一个xml文件。
如果声明PaletteSet的时候指定了第二个guid参数,CAD会在FixedProfile.aws文件ToolsInfo节点中添加一个Tool节点,用来保存面板信息,同时会在StartupInfo中也添加一个Tool节点,指定启动命令,这个启动命令和PaletteSet的name参数一样,就算在声明PaletteSet的时候传的是一个空字符串,CAD也会在StartupInfo节点下添加一个Command=""的启动命令,CAD启动时,应该是会把空命令忽略,所以使用第二个解决方法,CAD在启动时不会执行面板对应的启动命令,如果你对此有强迫症,不希望CAD保存启动命令节点的话,那么你可以自行将其删除,方法如下:
在声明PaletteSet的时候,可以随意指定name属性,或干脆留空,这个不再有影响;实现CAD提供的IExtensionApplication接口,此的接口中的Terminate会在你的DLL被卸载时(即CAD被关闭时)执行,我们可以在这个方法内,打开当前CAD对应的FixedProfile.aws文件,然后把StartupInfo节点下面板对应的启动命令删除,此命令和之前声明PaletteSet的时候指定的name参数一样,删除之后,保存FixedProfile.aws文件即可。
17、Application.ShowModelessDialog在不同版本CAD的调用不同
在CAD2010之前,这个方法有三个重载:
public static void ShowModelessDialog(Form formToShow); public static void ShowModelessDialog(IWin32Window owner, Form formToShow); public static void ShowModelessDialog(IWin32Window owner, Form formToShow, bool persistSizeAndPosition);
而在CAD2010中,这个方法有五个重载:
public static void ShowModelessDialog(Form formToShow); public static void ShowModelessDialog(IntPtr owner, Form formToShow); public static void ShowModelessDialog(IWin32Window owner, Form formToShow); public static void ShowModelessDialog(IntPtr owner, Form formToShow, bool persistSizeAndPosition); public static void ShowModelessDialog(IWin32Window owner, Form formToShow, bool persistSizeAndPosition);
然而,在CAD2010中,第三和第五个重载并没有什么用,因为CAD2010的窗体对象(Application.MainWindow,即Autodesk.AutoCAD.Windows.Window类)不再实现IWin32Window接口,所以第一个参数没办法传了,只能使用第一、二、四个重载方法。这是我目前的研究结果,不知道第三、第五个重载方法在CAD2010中还有没有其他使用方式。
另外,上面的ShowModelessDialog是针对Winform窗体的,而CAD2010的窗体却都是WPF的,于是在CAD2010中又提供了一个新接口方法:ShowModelessWindow,这个方法也是有五个重载:
public static void ShowModelessWindow(System.Windows.Window formToShow); public static void ShowModelessWindow(IntPtr owner, System.Windows.Window formToShow); public static void ShowModelessWindow(System.Windows.Window owner, System.Windows.Window formToShow); public static void ShowModelessWindow(IntPtr owner, System.Windows.Window formToShow, bool persistSizeAndPosition); public static void ShowModelessWindow(System.Windows.Window owner, System.Windows.Window formToShow, bool persistSizeAndPosition);
这个接口方法是用来显示WPF窗体对象的,但是,虽然有五个重载方法,但是应该和ShowModelessDialog一样,只有第一、二、四个方法能正常使用。
18、不允许所请求的注册表访问权。在win7等64位操作系统中,在CAD调用的C# dll插件中,如果操作注册表(读取、写入等),可能会报这个错误,原因是CAD不是以管理员权限运行的,权限不足,要防止这种情况发生,需要让CAD以管理员身份运行,在CAD的快捷方式或安装目录下的acad.exe上右键,选择“属性”,切换到“兼容性”页面,选中“以管理员身份运行此程序”,这样就不会出现这种情况了。
另外,对于这种错误,网上还有一种解决方案,是在操作注册表的方法上加上RegistryPermissionAttribute属性标识,如[RegistryPermissionAttribute(SecurityAction.PermitOnly, Read = @"HKEY_LOCAL_MACHINE\SOFTWARE\YourApp")],但是这种情况在CAD开发上好像并不适用,会提示错误。
19、在使用各种实体对象之后(如DBObject、Entity、Region、Polyline、DBObjectCollection等),尽量主动调用其Dispose方法进行释放,否则当你频繁对一组实体进行重复操作时,可能会引发一些错误,甚至引起CAD的崩溃。比如我碰到的一种情况:http://www.cnblogs.com/bomb12138/p/4552507.html这里面的第2条。
20、如果为面域指定了实体颜色,在此面域和其他面域进行了布尔运算之后(面域相加、相减、合并),面域的颜色会变成ByLayer 。
21、用注册表实现C#DLL或C++ARX随CAD自动加载,可以往以下两个地方添加启动信息:
1)、HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\RXX.X\ACAD-XXXX:XXX\Applications
2)、64位系统中的64位CAD 或 32位系统中的CAD:HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\RXX.X\ACAD-XXXX:XXX\Applications
64位系统中的32位CAD:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Autodesk\AutoCAD\RXX.X\ACAD-XXXX:XXX\Applications
其中,Current_User项不分32位和64位,而LOCAL_Machine则会分32位和64位,用程序进行注册表读写时需要注意。但是CURRENT_USER注册表信息只对当前登录的系统用户有效,而LOCAL_MACHINE注册表信息则会对系统所有用户都有效。
C#DLL或C++ARX随CAD启动需要向Applications项中添加一个自己命名的项,然后在该项下添加以下几个值:
DESCRIPTION | 字符串 | 程序名称或描述 |
LOADCTRLS | DWord | 启动类型(十进制值):2-随CAD启动加载,4-有命令触发时加载,8-有载入请求时加载 |
LOADER | 字符串 | 要加载的文件位置 |
MANAGED | DWord | 如果是C#DLL,十进制为1,如果是ARX则不添加此项 |
23、关于Document.CommandEnded事件:正常来说自己定义的命令都应该可以触发CommandEnded事件,但如果你的命令中使用了Application.ShowModelDialog,那么你的命令将不会触发CommandEnded事件,如果把Application.ShowModelDialog换成Form本身的ShowDialog,则可以正常触发CommandEnded事件。
24、使用VS2010 + AutoCAD2008进行开发时,如果不能调试,可以尝试修改AutoCAD2008安装目录中的acad.exe.config文件:
<configuration> <startup> <!--We always use the latest version of the framework installed on the computer. If you are having problems then explicitly specify .NET 2.0 by uncommenting the following line. <supportedRuntime version="v2.0.50727"/> --> <supportedRuntime version="v2.0.50727" /> </startup> </configuration>
25、使用SendStringToExecute向CAD发送命令时,如果命令参数中带有路径,这时如果执行有问题,可以尝试使用“/”代替路径中的“\”。
相关文章推荐
- AutoCAD.NET二次开发注意事项与开发技巧
- iOS开发中的技巧, 注意事项
- 项目开发注意事项及技巧
- unity游戏开发之相关的注意事项及技巧
- WebApp开发技巧(手机网站开发注意事项)
- AutoCAD.NET二次开发注意事项
- WEBAPP开发技巧小结(手机网站开发注意事项)
- 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获
- IOS项目开发实战——Storyboard设置界面技巧与注意事项
- IOS 开发技巧,小细节,注意事项
- WEBAPP开发技巧(手机网站开发注意事项)
- WEBAPP开发技巧小结(手机网站开发注意事项)
- WEBAPP开发技巧(手机网站开发注意事项)
- MVC的注意事项及开发技巧
- iOS项目开发实战——storyboard设置界面技巧与注意事项
- web移动端开发技巧与注意事项汇总
- 数据库设计的14个技巧--在实际开发中,注意运用体会吧
- eclipse插件开发的简单经验和一些注意事项
- 开发环境中biztalk项目设置注意事项
- 跨平台移动APP开发进阶(一)mui开发注意事项