使用C# Late Binding Com类库
之前发过32位版本的后绑定AutoCadCom库的方案,利用了PIA,但是64位AutoCad中桌子似乎偷懒了(常态),而且Cad库直接使用dynamic动态调用也是很麻烦,所以下面是解决方案项目是VS2015编写的,。Net框架的版本为4.0,要注意几个问题:
1、代码使用了C#6.0中的新特性,较低版本的要改写,不过推荐使用VS2015+
2、主项目必须生成AnyCpu才能调用,原因未知。。。
3、没有做很详细的测试,欢迎大家参与测试。。。
2017/11/27
修改Assembly类加载不必要类型的Bug
using System;
using System.Collections.Generic;
using System.IO;
using ComTypes = System.Runtime.InteropServices.ComTypes;
namespace NFox.Runtime.Com.Reflection
{
/// <summary>
/// Com程序集,只有类型集合,类型别名、枚举等未处理
/// </summary>
public class Assembly
{
/// <summary>
/// 程序集字典
/// </summary>
private static Dictionary<AssemblyKey, Assembly> _openedAssemblies
= new Dictionary<AssemblyKey, Assembly>();
public static DirectoryInfo Root
{
get
{
var assem = System.Reflection.Assembly.GetExecutingAssembly();
var fi = new FileInfo(assem.Location);
return fi.Directory.CreateSubdirectory("ComAssemblies");
}
}
/// <summary>
/// 获取IDispatch接口对象的类型信息
/// </summary>
/// <param name="obj">IDispatch接口对象</param>
/// <returns>对象的类型信息</returns>
public static Type GetType(IDispatch obj)
{
AssemblyKey key;
ComTypes.ITypeInfo info;
obj.GetTypeInfo(0, 0, out info);
ComTypes.ITypeLib lib;
int id;
info.GetContainingTypeLib(out lib, out id);
IntPtr ip;
lib.GetLibAttr(out ip);
var la = Utils.GetObject<ComTypes.TYPELIBATTR>(ip);
key = new AssemblyKey(la.guid, la.wMajorVerNum, la.wMinorVerNum);
lib.ReleaseTLibAttr(ip);
if (!_openedAssemblies.ContainsKey(key))
{
string name, doc, helpfile;
int hc;
lib.GetDocumentation(-1, out name, out doc, out hc, out helpfile);
var dir = Root.CreateSubdirectory(name);
var clsdir = dir.CreateSubdirectory(key.ClsId.ToString());
var verdir = clsdir.CreateSubdirectory(key.Version);
_openedAssemblies.Add(key, new Assembly(key, name, verdir));
}
return _openedAssemblies.GetType(id, info);
}
private Assembly(AssemblyKey key, string name, DirectoryInfo path)
{
Key = key;
Name = name;
_root = path;
}
public string Name { get; }
public AssemblyKey Key { get; }
private DirectoryInfo _root;
/// <summary>
/// 类型字典
/// </summary>
public Dictionary<int, Type> Types { get; }
= new Dictionary<int, Type>();
/// <summary>
/// 按索引获取Com程序集中的类型信息
/// </summary>
/// <param name="id">索引</param>
/// <param name="info">ITypeInfo接口</param>
/// <returns>对应索引的类型信息</returns>
public Type GetType(int id, ComTypes.ITypeInfo info)
{
if (!Types.ContainsKey(id))
{
var name = $"{_root.FullName}/{id}.typ";
if (File.Exists(name))
{
Types.Add(id, new Type(this, name));
}
else
{
Type type = new Type(this, info);
type.Save(name);
Types.Add(id, type);
}
}
return Types;
}
public override string ToString()
{
return Name;
}
}
}
下列代码对AutoCad2016 64位和AutoCad2010 32位均测试通过
var app = Comproxy.GetObject("AutoCad.Application");
var doc = app.ActiveDocument;
var util = doc.Utility;
var mspace = doc.ModelSpace;
dynamic obj, pt;
util.GetEntity(out obj, out pt);
double[] p1 = { 0, 0, 0 };
double[] p2 = { 0, 10, 0 };
double[] p3 = { 10, 0, 0 };
var objs =
Comproxy.CreateArray(
mspace.AddLine(p1, p2),
mspace.AddLine(p2, p3),
mspace.AddLine(p3, p1));
var r = mspace.AddRegion(objs); 2016 执行到红色这句错误
public static Type GetType(IDispatch obj)
{
AssemblyKey key;
ComTypes.ITypeInfo info;
obj.GetTypeInfo(0, 0, out info);
ComTypes.ITypeLib lib;
int id;
info.GetContainingTypeLib(out lib, out id);
IntPtr ip;
lib.GetLibAttr(out ip);
var la = Utils.GetObject<ComTypes.TYPELIBATTR>(ip);
key = new AssemblyKey(la.guid, la.wMajorVerNum, la.wMinorVerNum);
lib.ReleaseTLibAttr(ip) 狐哥雄壮!狐哥威武! 下载你的程序,直接运行,出现如下错误
请问是什么原因?
你的cad版本多少? 测试代码运行到哪一步? 你在窗体的代码里设个断点 看走到哪一步 今天重新运行一下,又成功了,有点莫名其妙! 想下载一个试试
页:
[1]
2