异常:无效的类字符串 (Invalid Class String)

使用python操作COM组件的朋友应该都碰到过,这个报错来自于python标准库pythoncomwin32com也是建立在pythoncom基础上的,在我使用win32com一年多的期间,印象中碰到三次这个报错。有时候各种办法都尝试了,也无法解决,最后不得已重装了系统,虽然有点为了抓只老鼠把家给拆了的感觉,但最后也能解决了问题。

好死不死,昨天(2024年1月17日),我又碰到了这个问题,第四次了!,下面是业务场景:

线上测试时,有一台机器报错,同时本地开发环境也报同样的错:无效的类字符串。每台下游机器均在子进程中运行win32com,并不在主进程中。(是不是和进程有关呢?按下不表)。接下来,就逐步分析,彻底把把这只老鼠给揪出来消灭掉。

win32com是如何工作的

弄清楚这个问题,一切就好办了。我们直接以win32com的客户端启动器DispatchDispatchEx来举例,下面是一个简单的示例:

from win32com.client import Dispatch

client = Dispatch('kwps.application')

无效的类字符串的错误在Dispatch('kwps.application')这一步就会出现。

为何实参kwps.application就能启动wps客户端、word.application能启动ms word客户端,而visio.application能启动Visio呢。简单粗暴地说:使用不同的实参,就能启动不同的客户端。

实参是什么,实际上是由程序在windows注册表中的程序ID(ProgId)决定的,看图:

在注册表中搜索关键词wps就能看到红框中所示的KWPS.Application的程序ID,这是一种身份标识,是唯一的。Dispatch('kwps.application')凭借实参,通过pythoncom来实现在注册表中查找与之匹配的应用程序。同样的,如果你安装了ms office,你通过word也能查到相关的程序ID。注意,Dispatch入参不区分大小写。

跑题:你是否也看到了截图中红框下方有KWPS.Document,那么,是不是也可以Dispatch('kwps.document'),它会启动一个什么呢?我已经试过了,并且瞬间就找到了一个为下游机器节省开销的方法。有好奇心的你不妨也尝试下。

分析

有了上面的理解作为基础,再来分析报错的原因。

情况一

错误的程序ID

当我使用Dispatch('wps.application')时(注意,入参少了个k),就会报错:无效的类字符串,因为COM组件无法通过wps.application匹配到应用程序,正确的应为kwps.application,毫无疑问,入参要求和程序ID完全匹配。如果你报了同样的错误,不妨检查下注册表中的程序ID。

情况二

正常运行的程序,突然不行了

由于某种原因,程序的注册表信息有损坏导致COM组件无法唤起客户端,比如wps,但这种情况下有可能连手动也打不开wps了,一般重装wps能解决问题。

情况三

在IDE中可以运行,但在cmd窗口中就无法执行,在其他电脑上也正常

如图,这是我自己测试的

图一:在PowShell中运行出错

图二:在vscode中运行正常

其实,之前大概率碰到的就是这种情形,莫名其妙就崩了。我将这两张图发到群里时,估计有不少朋友都看出问题所在了:权限问题。

情景还原

截图中涉及到的是上面提到的下游机器之一,不过是在本地的开发环境中,是一套django服务,runserver时,命令行窗口使用了管理员身份,图二是使用vscode控制台直接运行的,图一和图二最终运行的都是同一套win32com服务。它们的唯一的差异,就是权限不同。所以,我有足够的理由推测:由权限引起的。为了验证我的推测,我做了下面的测试:

测试一

写个win32com的最小实现:demo.py

from win32com.client import Dispatch

client = Dispatch('kwps.application')
client.Quit()

1、分别使用管理员身份启动cmdPowerShell,使用python demo.py来运行这段脚本,结果都报错:无效的类字符串

2、使用当前用户身份来启动cmdPowerShell,也就是正常打开命令行工具,使用python demo.py来运行这段脚本,结果正常。

上面提到,我的win32com运行在子进程中,为了保险,进一步测试在多进程中的表现如何,所以看测试二。

测试二

把demo.py变成多进程,如下:

import pythoncom
from multiprocessing import Process from win32com.client import DispatchEx def demo():
pythoncom.CoInitialize()
client = DispatchEx('kwps.application')
print('wps客户端实例:', client)
client.Quit()
pythoncom.CoUninitialize() if __name__ == '__main__':
p = Process(target=demo)
p.start()

再次重复测试一的步骤,测试结果一致。不关乎进程,测试结果只和身份有关,管理员身份当前用户身份最大的区别就是权限,意味着,即便是程序ID无误,也无法启动目标客户端。

更为详细的原因,我就不得而知了,超纲了。但已经完全可以确定,这种情况与权限有关,即以何种权限来启动程序,和当前的用户身份是否匹配。如果哪位大佬知晓更为本质的原因,欢迎点拨一二。

回到我的项目中,我一定是手贱了,在本地无意中以管理员身份启动了命令行工具,在部署测试时,手贱在一台下游机器上执行了同样的操作。

由于知识有限,个人的分析并不一定正确,碰到的情况也并不一定和你的相同,请多多多交流。

win32com报错:无效的类字符串(Invalid Class String)的更多相关文章

  1. Poi读取Excle报错 java.util.zip.ZipException: invalid stored block lengths

    一:Poi读取Excle报错  java.util.zip.ZipException: invalid stored block lengths 系统中需要导出excle签收单,excle模板是预设好 ...

  2. 【已解决】ckfinder_php_3.4.4 IIS 报错 无效请求

    ckfinder_php_3.4.4 IIS 报错 无效请求 (Invalid request) Apache 正常,但是在IIS环境下报错,解决方法 设置 C:\Windows\Temp 目录 给 ...

  3. JavaWeb报错:java.sql.SQLException: Invalid value for getInt()

    1.错误描述:在对数据库进行操作时,控制台报错:java.sql.SQLException: Invalid value for getInt() :2.错误原因:数据库中表的字段的类型与实体类中属性 ...

  4. 运行报错:java.io.IOException: invalid constant type: 15

    jdk,tomcat更新到jdk1.8与 tomcat8 运行报错:java.io.IOException: invalid constant type: 15 pom.xml文件中更新javassi ...

  5. spark提交任务报错: java.lang.SecurityException: Invalid signature file digest for Manifest main attributes

    spark提交任务报错: java.lang.SecurityException: Invalid signature file digest for Manifest main attributes ...

  6. SpringBoot整合Swagger2案例,以及报错:java.lang.NumberFormatException: For input string: ""原因和解决办法

    原文链接:https://blog.csdn.net/weixin_43724369/article/details/89341949 SpringBoot整合Swagger2案例 先说SpringB ...

  7. MySQL报错:Cause: java.sql.SQLException: Incorrect string value: '\xE6\x9D\xA8","...' for column 'obj_value' at row 1

    1.插入MySQL表时,报错:Cause: java.sql.SQLException: Incorrect string value: '\xE6\x9D\xA8","...' ...

  8. 从报错“无效操作,连接被关闭”探究Transaction的Timeout超时机制

    1.报错如下:Invalid Operation the connection is closed,无效操作,连接被关闭.这个错误是并不是每次都报,只有在复杂操作.大事务的情况下才偶然报出来. sta ...

  9. iOS-地图报错超出了经纬度范围Invalid Region

    做地图定位的时候,使用一下代码 // 经纬度 CLLocationDegrees latitude = [storeDict[@"lat"] doubleValue]; CLLoc ...

  10. Python创建文件报错OSError:[Errno 22] Invalid argument处理

    问题: windows平台下使用python open函数w模式打开文件报错“OSError: [Errno 22] Invalid argument: '../news/“消费升维”成零售业新风口? ...

随机推荐

  1. 小傅哥带着你做 Java SDK 组件

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 大家好,我是技术UP主小傅哥. 今天小傅哥将开启一个新计划,带着大家一起干"开源&q ...

  2. 使用funcgraph-retval和bpftrace/kprobe快速定位并解决cpu控制器无法使能的问题

    版本 Linux 6.5 背景 在学习cgroupv2的时候,想给子cgroup开启cpu控制器结果失败了: # 查看可以开启哪些控制器 root@ubuntu-vm:/sys/fs/cgroup# ...

  3. 容器网络Cilium:DualStack双栈特性分析

    本文分享自华为云社区<容器网络Cilium入门系列之DualStack双栈特性分析>,作者: 可以交个朋友. 一 . 关于IPV6/IPV4 双栈 目前很多公司开始将自己的业务由ipv4切 ...

  4. Python代码中的偏函数

    技术背景 在数学中我们都学过偏导数\(\frac{\partial f(x,y)}{\partial x}\),而这里我们提到的偏函数,指的是\(f(y)(x)\).也就是说,在代码实现的过程中,虽然 ...

  5. [CSP-S 2023] 密码锁

    题目描述 小 Y 有一把五个拨圈的密码锁.如图所示,每个拨圈上是从 \(0\) 到 \(9\) 的数字.每个拨圈都是从 \(0\) 到 \(9\) 的循环,即 \(9\) 拨动一个位置后可以变成 \( ...

  6. 数字孪生结合GIS会为智慧农业带来怎样的改变?

    数字孪生是一种创新的技术,它通过将现实世界的物理实体与数字模型相结合,实现了实时.动态的仿真和预测.而地理信息系统(GIS)则是一种用于收集.管理.分析和展示地理数据的工具.当这两种技术相互融合时,将 ...

  7. 【笔记】springSecurity-OAuth2.0-授权模式演示

    SpringSecurityOauth2架构 介绍 流程: 用户访问,此时没有Token.Oauth2RestTemplate会报错,这个报错信息会被Oauth2ClientContextFilter ...

  8. H3C 存储换盘操作

    实际存储型号H3C CF8844 环境说明:H3C存储设备存在一个坏盘需要更换. 更换准备 1. 取出备件检查完毕后放置到安全场所(请严格按照<IT产品现场工程师通用服务规(维修篇)>操作 ...

  9. 关于three.js中的矩阵更新

    目录 1. 概述 2. 详解 1. 概述 使用如下代码绘制一个面: 'use strict'; function init() { //console.log("Using Three.js ...

  10. 你的JoinHint为什么不生效

    本文分享自华为云社区<你的JoinHint为什么不生效[绽放吧!GaussDB(DWS)云原生数仓]>,作者:你是猴子请来的救兵吗 . 引言 提起数据库的Hint,几乎每个DBA都知道这一 ...