如何读取win32com获取的VB.Net COM返回PyIUnknown?或适配Python字典列表的VB.Net类型
我之前对接VB.Net写的COM组件时也碰到过一模一样的情况——字符串类型能正常读取,但返回Dictionary<TKey, TValue>时Python拿到的是PyIUnknown对象,没法直接操作。这里分享两个可行的解决思路:
思路1:直接在Python端处理PyIUnknown对象
VB.Net的Dictionary本质上实现了COM兼容的接口(比如IDictionary、ICollection),你可以通过调用它的原生方法来提取数据。假设你从COM对象拿到的实例叫com_dict,可以这样操作:
步骤1:获取所有键并遍历取值
import win32com.client # 假设已经获取到COM对象实例,调用方法得到PyIUnknown类型的dict com_obj = win32com.client.Dispatch("YourCustomCOMObject") com_dict = com_obj.GetYourDictionary() # 转换为Python字典 python_dict = {} # 获取所有键(返回的是ICollection,可直接遍历) keys = com_dict.Keys() for key in keys: # 通过Item方法获取对应值,VB.Net的Dictionary默认属性就是Item value = com_dict.Item(key) python_dict[key] = value # 现在就可以正常使用python_dict了 print(python_dict)
如果你的Dictionary嵌套了其他集合,只需要递归处理即可——比如碰到PyIUnknown就判断是否有Keys或Count方法,再做转换。
思路2:修改VB.Net端的返回类型(更省心的长期方案)
如果可以修改COM组件的代码,推荐返回更易被Python识别的COM兼容类型,避免后续的转换麻烦:
选项A:使用COM可见的集合类型
比如用System.Collections.Specialized.StringDictionary(适合键为字符串的场景),它天生支持COM交互,Python端拿到后可以直接像字典一样操作:
VB.Net代码示例:
Imports System.Collections.Specialized <ComVisible(True)> Public Class YourCustomCOMObject Public Function GetStringDict() As StringDictionary Dim dict As New StringDictionary() dict.Add("Key1", "Value1") dict.Add("Key2", "Value2") Return dict End Function End Class
Python端直接读取:
com_obj = win32com.client.Dispatch("YourCustomCOMObject") string_dict = com_obj.GetStringDict() # 直接通过键取值 print(string_dict["Key1"])
选项B:返回JSON字符串(兼容性最强)
如果你的数据结构比较复杂(比如嵌套字典、列表),最稳妥的方式是在VB.Net端把数据序列化为JSON字符串,Python端再解析成字典/列表:
VB.Net代码示例(需要引用Newtonsoft.Json):
Imports Newtonsoft.Json <ComVisible(True)> Public Class YourCustomCOMObject Public Function GetDataAsJson() As String Dim data As New Dictionary(Of String, Object) From { {"Name", "Test"}, {"Values", New List(Of Integer) From {1, 2, 3}} } Return JsonConvert.SerializeObject(data) End Function End Class
Python端解析:
import json import win32com.client com_obj = win32com.client.Dispatch("YourCustomCOMObject") json_str = com_obj.GetDataAsJson() python_data = json.loads(json_str) # 直接使用Python原生的字典和列表 print(python_data["Values"])
选项C:自定义COM可见的集合类
如果需要自定义键值类型,可以自己实现一个继承自CollectionBase的类,并标记ComVisible(True),同时暴露Add、Item、Count等方法,这样Python端可以直接遍历和取值。
内容的提问来源于stack exchange,提问作者Stefano Giraldi

