如何为COM构建对象列表?

2 投票
1 回答
1600 浏览
提问于 2025-04-17 17:52

这是一个之前用VBA写的真实项目。

我想把它转到Python,并使用“用Python进行AutoCAD的ActiveX自动化脚本”这个方法。这是我的代码:

# -*- coding: utf-8 -*-

from pyautocad import Autocad, APoint, aDouble


acad = Autocad(False,  True)
acad.prompt("Hello, Autocad from Python\n")
print acad.doc.Name

xx = acad.model.AddCircle(APoint(0, 0),  10)
print(xx)
yy = acad.model.Add3Dpoly(aDouble([0,  0,  0,  10,  10,  10,  30,  20,  30,  0,  0,  0]))
print(yy.ObjectName)
print(yy.PlotStyleName)

# How to contruct an objectlist for AddRegion?
#regions = acad.model.AddRegion([yy])
#acad.model.AddExtrudedSolid(regions[0], 20, 0)

我想问的是,如何为AddRegion构建一个对象列表?也许comtypes有关于VARINT的相关内容。我对COM这些东西真的没有经验……

1 个回答

1

让一切正常运作可能比看起来要复杂得多。用Python读取数据还算简单,但写数据就有点棘手了。对初学者来说,得小心你要面对的挑战。


你可能需要的东西

如果你对autolisp有些了解,那会大大帮助你,因为在这种情况下,它的表现更好,文档也更完善,整合得也更好……而且你可能需要它来获取Python无法提供的“未知/隐藏/未记录”的信息。(可以看看vlax-vla-系列的lisp函数)。

接下来,你需要从命令行使用win32com的make_py和gen_py脚本,或者你可以在Python中主要使用win32com.client.gencode

准备好处理一些非常难看的文本(我说的可不是lisp =])。要做好失败的准备,并期待找出原因。

大部分问题都和COM-Variants有关。然后你会遇到奇怪的东西,比如Variant-Variant-Arrays。如果你查看win32com.client.pythoncom,你会发现所有的数据类型都映射为整数。(例如,VT_BOOL是11)。


细节问题

下次你尝试使用ModelSpace.AddCircle时,注意你得到的调试输出;所有传递给InvokeTypes的参数都是你需要关注的……(这是我从AutoCAD注册接口的make-py输出中提取的)

def AddLine(self, StartPoint=defaultNamedNotOptArg, EndPoint=defaultNamedNotOptArg):       
    ret = self._oleobj_.InvokeTypes(
                        1581, LCID, 1, (9, 0), ((12, 1), (12, 1)),StartPoint, EndPoint)
    if ret is not None:
        ret = Dispatch(ret, u'AddLine', '{DF524ECB-D59E-464B-89B6-D32822282778}'

这告诉你win32com认为它需要哪些COM类型,所以确保你至少要匹配这些类型。

我发现很多输入函数实际上被错误地记录和调用(我在与AutoLisp反复试验后才明白这一点)。我们上面看到的外部值是1581(这更像是一个类名,而不是真正的数据类型),然后是一个元组,基本上是说(DISPATCH, EMPTY):(9,0),接着是一个VT_VARIANTS的数组:((12,1),(12,1))。

通常会缺少一个COM所期望的外部包装,而make-py似乎没有意识到这一点。如果你深入研究AutoLisp的vlax-内容,你会注意到还有一个额外的包装。我认为它要么是VARIANT_ARRAY,要么就是字面意义上的VARIANT-VARIANT-ARRAY(四重指针之类的)。这些的代码是(vt_array=8192, vt_variant=12)。

抱歉我不记得具体细节,但我相信读取((12,1),(12,1))的部分应该变成(8192, 12, ((12,1),(12,1))),或者类似的东西。即使你弄清楚了应该是什么,我也不确定是否有快速的解决办法。对于我来说,从AutoCAD 2010开始,这意味着要仔细查看庞大的gen_py输出,找到我真正想要的函数,然后手动更改InvokeTypes()调用,以匹配COM的期望。

之后一切都如预期般正常工作。


可能的解决方法

COM很麻烦。如果你是Python新手,但在AutoCAD方面有点经验(也就是说你想做一些相对复杂的自动化),那么最好避免使用python->win32com->AutoCAD的流程。使用LISP。尽管这样说让我有点痛苦,但你最终会写很多LISP测试用例和调试器来配合你的Python工作,不如直接投入进去。

  • Ironpython和.NET
    • 我认为这个接口比COM更受支持
  • Visual Studio Professional (2008+)
    • 我从未使用过官方的VS-Pro工具(我用的是PythonWIN和MINGW),不确定是否有额外的功能会改变win32com处理AutoCAD的方式。我知道官方的AutoCAD ARX扩展提供了它们的源代码在一个Studio项目中。最糟糕的情况是你会有实际的文档在手,这也是整个Python-AutoCAD话题变得复杂的原因。

撰写回答