1

我工作得很好GetNameSpace('MAPI'),但我写了一个 ActiveState 代码:使用 win32com 导入 Outlook 联系人并且GetNameSpace不再有用。

现在代码变了:很有用GetNamespace('MAPI')。为什么会发生这种情况以及如何返回GetNameSpace('MAPI')

import win32com.client as client
outlook = client.Dispatch('Outlook.Application')
namespace = outlook.GetNameSpace('MAPI')
drafts = namespace.GetDefaultFolder(16)
contacts = namespace.GetDefaultFolder(10)
inbox = namespace.GetDefaultFolder(6)

结果:

AttributeError: '<win32com.gen_py.Microsoft Outlook 16.0 Object Library._Application
  instance at 0x2538077068688>' object has no attribute 'GetNameSpace'

我正在研究 VSCode。

4

2 回答 2

0

简短回答:如果您更改此行:

outlook = client.Dispatch('Outlook.Application')

至:

outlook = client.dynamic.Dispatch('Outlook.Application')

您的原始代码适用于GetNameSpace("MAPI")(使用大写“S”)

或者,将您的代码更改为GetNamespace().

长答案:问题的出现是因为win32com创建 Outlook 应用程序对象的方式,或者实际上是一般的 COM 对象。这种解释不仅限于 Python,在 VBA 和其他语言(例如 C++、C#)中也可以看到。

您可以通过两种方式连接或绑定到 COM 对象及其方法和属性:早期绑定或后期绑定。

早期绑定:在这里,所有关于对象支持的方法和属性的信息都提前被调用代码知道。此信息位于与提供对象的应用程序一起提供的类型库中。有时它位于单独的.tlb文件中,也可能位于应用程序的可执行文件中(Excel 就是这种情况)。类型库包含关于类、它们的方法以及可能定义的任何常量的所有信息。这有时被称为“自定义”界面。调用的函数必须与类型库方法完全匹配,并且函数名区分大小写

后期绑定:在这里,调用应用程序对对象的前期知之甚少。该对象公开了一个通用函数调用接口,即Dispatch接口。应用程序可以尝试调用此接口上的任何函数,这些函数可能有效也可能无效。在运行时,Dispatch 接口按名称查找请求的函数,并尝试将其与数字标识符或 ID 匹配。如果返回一个有效的 Id,则使用参数列表调用该函数。这里的一个关键点是函数名查找不区分大小写

一个松散的类比可能是去餐馆吃点东西

  1. 你可以去餐厅门口看看外面的菜单。您已经根据其供应的美食选择了这家餐馆。这将告诉您有哪些食物可供选择,并可能分为开胃菜、主菜和甜点。作为用餐者,您可以放心,在开门之前,您将能够坐下并订购您选择的物品。这是早期绑定:您有很多前期信息。

  2. 或者,您可以打开大街上的任何一扇门,走进去,坐下来要食物,也许可以指定“牛排”和“薯条”。您可能事先不知道这是餐厅还是牙医。如果您选择了正确的门,并且菜单上有牛排和薯条,那就太好了。如果没有,您将遇到问题或“错误”。这是后期绑定,你必须为事情不会像你希望的那样发展做好准备。

一般来说,早期绑定完成了一次匹配函数和参数的所有艰苦工作,然后每次调用都很快。它还允许调用应用程序创建包装类,以反映正在创建的对象的类模型。但并非每个对象都提供类型库,并且一些调用应用程序不具备生成包装器的能力。后期绑定更通用,需要很少的对象的前期知识,但执行起来自然更慢。在许多应用程序中,用户不会注意到速度差异。

最后,回到win32com。这是 COM 对象的 Python 包装器,可以在早期或后期绑定模式下运行。大多数提供 COM 对象的应用程序(例如 Outlook、Excel 等)都支持这两种模式:所谓的双界面win32com有两种绑定路径:win32com.client.gencache早期绑定和win32com.dynamic后期绑定。

win32com早期绑定涉及读取对象类型库的包并gencache用于makepy生成 python 代码来包装自定义接口。此代码存储在 python 包文件系统中以供以后使用(具体位置取决于您的配置)。另dynamic一种方法只是尝试后期绑定。

在更高级别,该win32com.client.Dispatch()函数将为您选择一种绑定方法。如果自定义接口的包装文件存在,那么它将用于早期绑定。如果他们不这样做,则使用后期绑定。

这里的关键点是,如果您从未(在您的应用程序或其他 python 应用程序中)调用outlook=win32com.client.gencache.EnsureDispatch('Outlook.Application')过,您将不会生成用于提前绑定到 Outlook 应用程序对象的包装代码缓存因此,调用win32com.client.Dispatch()将退回到使用后期绑定。

在这种情况下,使用后期绑定,无论您调用outlook.GetNameSpace()outlook.GetNamespace()还是确实,Python 代码都可以工作outlook.GeTnAmEsPaCe(),因为后期绑定 Dispatch 接口上的函数查找不区分大小写。

但是,如果在某个时间点(今天、昨天、一年前)gencache.EnsureDispatch('Outlook.Application')调用了该函数(并且在 OP 链接到的示例代码中调用了该函数),则将生成包装函数,win32com.client.Dispatch('Outlook.Application')并将执行最佳操作并使用早期绑定。这里的问题是函数名称现在区分大小写,并且现在只有 outlook.GetNamespace()小写的 's' 才能工作。这是显示拼写的MS 文档GetNamespace()

这不是特定于 Python / win32com。您可以在 VBA 中观察到相同的效果。

如果你这样写:

Dim ol As Object
Set ol = CreateObject("Outlook.Application")

Dim ns As Object
Set ns = ol.GeTnaMeSpAcE("MAPI")

它会正常工作。这是因为除非您包含“Microsoft Outlook 16.0 对象库”(使用工具 | 参考),否则 VBA 使用不区分大小写的后期绑定。

但是,如果您确实包含了类型库引用并使用了类类型,那么您现在正在使用早期绑定:

Dim ol As Outlook.Application
Set ol = CreateObject("Outlook.Application")
    
Dim ns As Outlook.Namespace
Set ns = ol.GetNamespace("MAPI")

VBA 编辑器可能会强制执行正确的区分大小写的拼写。

虽然 VBA 也很困惑(至少在我的设置中):当您键入时, Dim ns as Outlook. ...VBA 会提示NameSpace完成(大写“S”),但一旦选择,IntelliSense 将Dim ns as Outlook.Namespace使用小写“s”更正它!

于 2022-01-23T12:15:39.213 回答
0

到目前为止,Outlook 对象模型中没有任何更改。Session属性和GetNamespace方法可以互换使用以获取NameSpace当前会话的对象。两个成员都有相同的目的。例如,以下语句执行相同的功能:

Set objNamespace = Application.GetNamespace("MAPI") 

Set objSession = Application.Session

请注意,有时,当您在 Outlook 中配置了多个配置文件时,您可能需要使用Logon方法的GetNamespace方法。

于 2022-01-22T20:51:01.970 回答