CN109614165A - 一种com组件的多版本并行运行方法和装置 - Google Patents

一种com组件的多版本并行运行方法和装置 Download PDF

Info

Publication number
CN109614165A
CN109614165A CN201811476646.1A CN201811476646A CN109614165A CN 109614165 A CN109614165 A CN 109614165A CN 201811476646 A CN201811476646 A CN 201811476646A CN 109614165 A CN109614165 A CN 109614165A
Authority
CN
China
Prior art keywords
com component
virtual
path
function
module
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Granted
Application number
CN201811476646.1A
Other languages
English (en)
Other versions
CN109614165B (zh
Inventor
杨国萍
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Shandong University of Finance and Economics
Original Assignee
Shandong University of Finance and Economics
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Shandong University of Finance and Economics filed Critical Shandong University of Finance and Economics
Priority to CN201811476646.1A priority Critical patent/CN109614165B/zh
Publication of CN109614165A publication Critical patent/CN109614165A/zh
Application granted granted Critical
Publication of CN109614165B publication Critical patent/CN109614165B/zh
Active legal-status Critical Current
Anticipated expiration legal-status Critical

Links

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F9/00Arrangements for program control, e.g. control units
    • G06F9/06Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
    • G06F9/44Arrangements for executing specific programs
    • G06F9/445Program loading or initiating
    • G06F9/44536Selecting among different versions
    • G06F9/44542Retargetable
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F9/00Arrangements for program control, e.g. control units
    • G06F9/06Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
    • G06F9/44Arrangements for executing specific programs
    • G06F9/445Program loading or initiating
    • G06F9/44521Dynamic linking or loading; Link editing at or after load time, e.g. Java class loading

Landscapes

  • Engineering & Computer Science (AREA)
  • Software Systems (AREA)
  • Theoretical Computer Science (AREA)
  • Physics & Mathematics (AREA)
  • General Engineering & Computer Science (AREA)
  • General Physics & Mathematics (AREA)
  • Stored Programmes (AREA)

Abstract

本发明涉及一种在Windows操作系统上实现COM组件多版本并行运行的方法,以及一种实现装置。一种COM组件的多版本并行运行方法,包括如下步骤:a.把虚拟注册数据保存到虚拟注册文件中;b.把COM组件的动态链接库和虚拟注册文件安装到程序目录下;c.把虚拟注册文件导入到一个对主程序运行路径散列运算所得的一个注册表节点;d.初始化程序进程全局信息;e.采用钩子函数拦截操作系统内核层的由ntdll.dll导出的注册表访问函数对于HKEY_CLASSES_ROOT的访问,重定向到步骤c的散列运算所得到的虚拟注册表节点路径。本发明通过在程序进程启动时导入COM组件的虚拟注册数据,以及在访问COM组件时通过注册表重定向到虚拟注册数据,实现了COM组件多个版本并行运行。

Description

一种COM组件的多版本并行运行方法和装置
技术领域
本发明涉及一种在Windows操作系统上实现COM组件多版本并行运行的方法,以及一种实现装置。
背景技术
COM是ComponentObjectModel(组件对象模型)的缩写。COM是开发软件组件的一种方法,是微软公司为了计算机工业的软件生产更加符合人类的行为方式开发的一种新的软件开发技术,在COM构架下,可以开发出各种各样的功能专一的组件,然后将它们按照需要组合起来,构成复杂的应用系统。在实践中,COM组件由以Win32动态连接库或可执行文件形式发布的可执行代码所组成,它是遵循COM规范而编写的。COM组件可以给应用程序、操作系统以及其他组件提供服务;自定义的COM组件可以在运行时刻同其他组件连接起来构成某个应用程序;COM组件可以动态的插入或卸出应用。而组件的实例化是由操作系统的基础服务负责的。一个COM组件在使用前必须首先注册。所谓“注册”,也就是向系统注册表的相应位置写入一些数据。这些数据可以完成GUID与组件模块的绝对路径的一一对应,也就是说可以帮助程序通过GUID找到组件模块的位置。组件可以用CLSID作为索引在Windows的注册表中发布包含他们的DLL文件名称。CoCreateInstance将用CLSID作为关键字在注册表中查找所需要的文件名称。注册表是一个由许多元素构成的层次结构。每一个元素均被称作是一个关键字。每一个关键字可以包含一系列子关键字、一系列命名的值及/或一个未命名的值。COM只使用了注册表的一个分支:HKEY_CLASSES_ROOT;在此关键字之下,可以看到有一个CLSID关键字。在CLSID关键字下列有系统中安装的所有组件的CLSID。每一个CLSID关键字有一个子关键字InprocServer32。此子关键字的缺省值是组件所在的模块文件路径名称。参照图2,当程序需要调用某个COM组件时,COM组件创建模块会向注册表读取数据。同一个组件在注册表中的数据存在若干条,每一条的读取过程经历下面四个步骤:1.调用ZwOpenKey(Windows7之后版本用ZwOpenKeyEx)函数打开指定的键。2.调用ZwQueryKey函数查询步骤1打开的键的概要信息。3.根据步骤2查询所得的概要信息调用ZwQueryValueKey读取键值。4.调用ZwClose关闭步骤1打开的键。
组件技术有很多优点,应用可以非常灵活扩展和定制,但是多个应用程序使用公共的模块和组件也会导致严重的问题。最典型的情况是,某个应用程序将要安装一个新版本的共享组件,而该组件与机器上的现有版本向后不兼容。虽然刚安装的应用程序运行正常,但原来依赖前一版本共享组件的应用程序也许已无法再工作。在某些情况下,问题的起因更加难以预料。比如,当用户浏览某些Web站点时会同时下载某个ActiveX控件。如果下载该控件,它将替换机器上原有的任何版本的控件。如果机器上的某个应用程序恰好使用该控件,则很可能也会停止工作。另一种场景是一些在较低版本操作系统运行良好的应用软件要在新版本的操作系统上运行,但是常常因为新版本的操作系统中的组件并不兼容老版本,导致应用程序运行失败。
微软的.NET平台针对动态链接库的组件冲突问题,提出了版本管理技术。并行执行利用具有强名称的程序集将类型信息绑定到程序集的特定版本。这可防止应用程序或组件绑定到程序集的无效版本。具有强名称的程序集还允许同一计算机上存在一个文件的多个版本,并且还允许应用程序使用一个文件的多个版本。.NETFramework在全局程序集缓存中提供了版本识别代码存储。全局程序集缓存是全计算机范围的代码缓存,存在于所有安装了.NETFramework的计算机上。它根据版本、区域性和发行者信息存储程序集,并且支持组件和应用程序的多个版本。隔离,使用.NETFramework,可以创建以隔离方式执行的应用程序和组件,这是并行执行的一个基本组成部分。实施隔离时需要了解正在使用的资源以及在应用程序或组件的多个版本间安全地共享的资源。隔离还包括使用版本特定的方式存储文件。具有强名称的程序集内置版本元数据和签名信息,但是该版本管理技术要求子模块必须用.NET平台重新开发,而且对现存的Win32原生动态链接库无效。由于操作系统向下兼容原因,Windows平台下的应用程序仍然对原生动态链接库有很深的依赖。因此在.NET平台已经盛行的情况下,仍然存在原生组件的版本冲突问题,而且随着技术人员的新老代谢,对历史遗留技术知识的欠缺,导致技术人员解决此类问题的成本很高。因此一种解决原生COM组件多版本并行运行的技术是很有现实应用价值的。
发明内容
本发明提供了一种通过在进程内部COM组件虚拟注册以及实例化时注册数据的访问重定向,解决应用程序对COM组件的加载无法控制的技术问题,使得多版本的COM组件可以并行运行。
一种COM组件的多版本并行运行方法,包括如下步骤:
a.预先把COM组件的注册数据采集后处理成虚拟注册数据,把COM组件模块路径设为某一虚拟路径作为占位符,把虚拟注册数据保存到虚拟注册文件中;
b.把COM组件的动态链接库和虚拟注册文件安装到程序目录下;
c.程序进程启动时,把虚拟注册文件导入到一个对主程序运行路径散列运算所得的一个注册表节点,该节点在HKEY_CURRENT_USER节点下的子节点,把COM组件所在模块的注册路径InprocServer32调整为基于程序主模块绝对路径;
d.初始化程序进程全局信息;
e.当程序进程需要调用COM组件时,采用钩子函数拦截操作系统内核层的由ntdll.dll导出的注册表访问函数对于HKEY_CLASSES_ROOT的访问,重定向到步骤c的散列运算所得到的虚拟注册表节点路径,这样COM组件在系统中实现了虚拟注册,虽未实际注册但是得以顺利启用,程序正常运行;
f.重复步骤a-e,使另一版本的COM组件顺利启用,从而实现COM组件的多版本并行运行。
优选地,步骤c在注册表节点中还写入虚拟注册文件的MD5校验值和初次导入虚拟注册文件时的时间戳;步骤c运行时先判断虚拟注册文件的MD5校验值与注册表节点的数据是否一致,如果一致,则直接跳过导入步骤。
优选地,步骤a的虚拟路径为C:\VirDir。
优选地,步骤a利用注册表蜂巢技术来实现,具体包括如下细分步骤:
a1.创建HKEY_CLASSES_ROOT键在自定义hive中的映射键,开启Hive状态;
a2.准备DllRegisterServer的函数指针类型;
a3.调用LoadLibrary()加载COM组件所在模块;
a4.调用GetProcAddress()获得DllRegisterServer的地址;
a5.调用OleInitialize()初始化COM库;
a6.使用a4步骤得到的地址调用DllRegisterServer;
a7.执行必要的清理工作:清理COM库,卸载组件,取消蜂巢化状态;
a8.把Hive键下的所有内容递归导出写入虚拟注册文件,把键路径改为HKEY_CLASSES_ROOT,把模块路径替换为模块虚拟路径,最后保存虚拟注册文件。
优选地,步骤b具体包括如下细分步骤:
b1.复制COM组件的动态链接库到应用程序的主exe文件同一目录下;
b2.把步骤a生成的虚拟注册文件放入应用程序主exe的同级的registry目录。
优选地,步骤c具体包括如下细分步骤:
c1.调用系统接口函数GetCurrentProcessId得到当前程序进程的id;
c2.根据进程id查询进程的模块信息,得到进程的主模块绝对路径;
c3.用哈希算法将绝对路径生成为固定长度的字符串,用CRC32算法生成绝对路径的校验值字符串;
c4.在HKEY_CURRENT_USER\SOFTWARE\VIRREG\[CRC32]\HKCU节点下查询是否存在虚拟注册文件的MD5校验值以及时间戳,如果存在,则直接跳过后续步骤;
c5.加载虚拟注册文件到内存流中,用正则表达式进行文本处理,把子模块组件路径占位符中的虚拟路径替换为c2计算得到的进程主模块绝对路径;
c6.把虚拟注册数据中的路径HKEY_CLASSES_ROOT替换为HKEY_CURRENT_USER\SOFTWARE\VIRREG\[CRC32]\HKCUR,其中的[CRC32]是c3步骤计算得到的校验值;
c7.将修改后的注册信息写入到注册表中;
c8.在HKEY_CURRENT_USER\SOFTWARE\VIRREG\[CRC32]\HKCU节点下写入导入文件的MD5校验值和导入时的时间戳,用于判断步骤c是否需要重新导入虚拟注册数据。
优选地,步骤d具体包括如下细分步骤:
d1.初始化一个注册表键句柄列表对象;
d2.调用OpenThreadToken函数得到当前线程的AccessToken;
d3.调用ObtainTextSid函数传入d2步骤得到的AccessToken得到当前用户的sid;
d4.关闭AccessToken。
优选地,步骤e具体包括如下细分步骤:
e1.当程序进程需要调用COM组件时,COM组件创建模块向注册表发送查询组件注册信息的请求;
e2.采用打开键钩子函数,调用内核ZwOpenKey函数,重定向到步骤c的虚拟注册表节点路径;
e3.采用键信息查询钩子函数,调用内核ZwQueryKey函数,查询e3步骤打开的键的概要信息;
e4.采用键值读取钩子函数,调用内核ZwQueryValueKey函数,读取键值,并将键值发送给COM组件创建模块,从而COM组件得以顺利启用;
e5.采用关闭键钩子函数,调用内核ZwClose函数关闭打开的键。
优选地,步骤e2具体包括如下细分步骤:
e2-1.调用ZwOpenKey函数尝试打开注册键;
e2-2.检查e2-1返回值,如果返回值为STATUS_SUCCESS,根据键的路径判断是否属于虚拟注册组件的路径,如果是则记录到全局列表中以备后续检索;跳转到步骤e2-5;
e2-3.继续检查步骤e2-1返回值,如果返回值为STATUS_OBJECT_NAME_NOT_FOUND,把虚拟注册路径和e2-1步骤的键路径结合得到绝对路径;
e2-4.用e2-3步骤的绝对路径调用ZwOpenKey,将句柄记录到全局列表中;
e2-5.函数返回,完成步骤e2;
步骤e3具体包括如下细分步骤:
e3-1.对查询的键句柄KeyHandle与¥FFFFFFFC进行“位与运算”,得到一个新句柄;
e3-2.对e3-1步骤的新句柄在步骤e2-2保存的全局列表中进行检索,如果未检索到则跳转到e3-4;
e3-3.根据入参判断函数调用方是否仅查询键值长度,再检查传入的缓冲长度参数是否足以容纳键值,如果可以容纳就设置状态标识为STATUS_SUCCESS,否则设置状态标识为STATUS_BUFFER_TOO_SMALL,然后跳到步骤e3-5;其他情况,直接执行下一步;
e3-4.调用ZwQueryKey并返回结果;
e3-5.函数返回,完成步骤e3;
步骤e4具体包括如下细分步骤:
e4-1.调用ZwQueryKey函数查询键的路径,如果路径是以\REGISTRY\MACHINE\SOFTWARE\Classes开头或者以\REGISTRY\USER\<sid>\Classes开头,则把此开头部分替换为HKEY_CLASSES_ROOT,这里的sid是d3步骤所获取的具体的用户的sid,这一步就得到注册表键的绝对路径;
e4-2.判断e4-1步骤所得绝对路径是否HKEY_CLASSES_ROOT节点的子路经,如果是,则删除HKEY_CLASSES_ROOT前缀转为相对路径,否则跳转e4-6;
e4-3.调用ZwOpenKey,打开成功把句柄保存;
e4-4.用e4-3临时保存的句柄调用ZwQueryValueKey;
e4-5.调用ZwClose关闭e4-3保存的临时句柄。跳转e4-7;
e4-6.用原来的输入句柄调用ZwQueryValueKey函数;
e4-7.函数返回,完成步骤e4;
步骤e5具体包括如下细分步骤:
e5-1.把KeyHandle参数与¥FFFFFFFC进行“位与运算”,得到新句柄;
e5-2.用e5-1得到的新句柄调用ZwClose;
e5-3.从步骤e2-2的全局列表中删除对应的句柄;
e5-4.函数返回,完成步骤e5。
一种COM组件的多版本并行运行装置,包括:
注册数据生成模块:用于把COM组件的注册数据采集后处理成虚拟注册数据,把COM组件模块路径设为某一虚拟路径作为占位符,把虚拟注册数据保存到虚拟注册文件中;
安装模块:用于把COM组件的动态链接库和虚拟注册文件安装到程序目录下;
注册数据导入模块:用于在程序进程启动时,把虚拟注册文件导入到一个对主程序运行路径散列运算所得的一个注册表节点,该节点在HKEY_CURRENT_USER节点下的子节点,把COM组件所在模块的注册路径InprocServer32调整为基于程序主模块绝对路径;
初始化模块:用于初始化程序进程全局信息;
注册表重定向模块:用于当程序进程需要调用COM组件时,采用钩子函数拦截操作系统内核层的由ntdll.dll导出的注册表访问函数对于HKEY_CLASSES_ROOT的访问,重定向到注册数据导入模块的虚拟注册表节点路径,这样COM组件在系统中实现了虚拟注册,从而使得多个版本的COM组件可以并行运行。
本发明通过应用程序编程接口挂钩技术(API Hook)实现进程内所有对注册表访问的拦截,COM组件的虚拟注册,为安装的应用程序提供专属的组件部署和执行环境,达到COM组件隔离和并行执行的效果。APIHOOK技术是通过改变目标函数头部的代码来使改变后的代码跳转到另外设置的一个钩子函数里,就可以根据参数进行一些判断,执行所需的前置处理,还可以根据具体逻辑需要恢复函数的前几字节并重新调用原函数,调用完毕再执行后置处理逻辑,最后返回函数的返回值。本发明基于APIHook技术原理,对操作系统的COM组件实例化时访问注册表的系统函数进行拦截,实现在COM组件未实际注册的情况下虚拟返回所需的注册数据,并且是为不同的应用程序返回差异化的注册数据,从而实现了COM组件多版本的并行运行。
应该明白,同一个组件在注册表中的数据存在若干条,故步骤e中每一条数据的读取都要经历e2-e3-e4-e5。ZwOpenKey函数(WIN7以上系统为ZwOpenKeyEx函数)、ZwQueryKey函数、ZwQueryValueKey函数、ZwClose函数四个函数是操作系统的模块ntdll.dll导出的注册表访问函数。
本发明的有益效果在于:
(1)本发明通过在程序进程启动时导入COM组件的虚拟注册数据,以及在访问COM组件时通过注册表重定向到虚拟注册数据,COM组件在系统中无需实际注册即可顺利启用,实现了COM组件多个版本并行运行;
(2)由于在重定向目标路径中创建有原始数据的特征码标记和时间戳,进程每次启动时,通过时间戳和特征码进行比对以便于确定是否需要重新初始化进程的专有注册数据,不需要重复导入,从而实现了虚拟数据的持久化与访问的一致性,并节省了系统资源;
(3)在进程内用户态挂钩内核态的注册表函数,确保了装置的兼容性,避免了操作系统的内置模块绕过用户层函数直接使用内核层函数而导致的普通虚拟化技术失效;
(4)在虚拟注册文件中定义虚拟文件路径标记,并根据宿主进程的启动路径替换预置数据中的虚拟标记,然后导入注册表目标路径,从而能够动态修正COM组件的加载路径;
(5)由于打开键的句柄在操作系统从内核层到用户层的传递过程中会被特殊处理,导致句柄发生变化,所以本发明在调用查询键信息函数时对句柄进行解码,在调用关闭键函数时也进行解码,修复了键句柄的不确定性,确保了注册信息读取的准确性。
附图说明
图1为本发明COM组件多版本并行运行的工作流程图;
图2为进程调用COM组件的工作流程图;
图3为注册数据导入模块及注册表重定向模块的工作流程图;
图4是打开键钩子函数的工作流程图;
图5为键信息查询钩子函数的工作流程图;
图6是键值读取钩子函数的工作流程图;
图7是本发明内核函数与钩子函数的对应关系图;
图8是本发明COM组件的多版本并行运行装置的原理框图。
具体实施方式
参照图1、图3,一种COM组件的多版本并行运行方法,包括如下步骤:
a.预先把COM组件的注册数据采集后处理成虚拟注册数据,把COM组件模块路径设为某一虚拟路径作为占位符,把虚拟注册数据保存到虚拟注册文件中;
b.把COM组件的动态链接库和虚拟注册文件安装到程序目录下;
c.程序进程启动时,把虚拟注册文件导入到一个对主程序运行路径散列运算所得的一个注册表节点,该节点在HKEY_CURRENT_USER节点下的子节点,把COM组件所在模块的注册路径InprocServer32调整为基于程序主模块绝对路径;
d.初始化程序进程全局信息;
e.当程序进程需要调用COM组件时,采用钩子函数拦截操作系统内核层的由ntdll.dll导出的注册表访问函数对于HKEY_CLASSES_ROOT的访问,重定向到步骤c的散列运算所得到的虚拟注册表节点路径,这样COM组件在系统中实现了虚拟注册,虽未实际注册但是得以顺利启用,程序正常运行;
f.重复步骤a-e,使另一版本的COM组件顺利启用,从而实现COM组件的多版本并行运行。
步骤c在注册表节点中还写入虚拟注册文件的MD5校验值和初次导入虚拟注册文件时的时间戳;步骤c运行时先判断虚拟注册文件的MD5校验值与注册表节点的数据是否一致,如果一致,则直接跳过导入步骤。
步骤a的虚拟路径为C:\VirDir。
步骤a利用注册表蜂巢技术来实现,具体包括如下细分步骤:
a1.创建HKEY_CLASSES_ROOT键在自定义hive中的映射键,开启Hive状态;
a2.准备DllRegisterServer的函数指针类型;
a3.调用LoadLibrary()加载COM组件所在模块;
a4.调用GetProcAddress()获得DllRegisterServer的地址;
a5.调用OleInitialize()初始化COM库;
a6.使用a4步骤得到的地址调用DllRegisterServer;
a7.执行必要的清理工作:清理COM库,卸载组件,取消蜂巢化状态;
a8.把Hive键下的所有内容递归导出写入虚拟注册文件,把键路径改为HKEY_CLASSES_ROOT,把模块路径替换为模块虚拟路径,最后保存虚拟注册文件。
步骤b具体包括如下细分步骤:
b1.复制COM组件的动态链接库到应用程序的主exe文件同一目录下;
b2.把步骤a生成的虚拟注册文件放入应用程序主exe的同级的registry目录。
步骤c具体包括如下细分步骤:
c1.调用系统接口函数GetCurrentProcessId得到当前程序进程的id;
c2.根据进程id查询进程的模块信息,得到进程的主模块绝对路径;
c3.用哈希算法将绝对路径生成为固定长度的字符串,用CRC32算法生成绝对路径的校验值字符串;
c4.在HKEY_CURRENT_USER\SOFTWARE\VIRREG\[CRC32]\HKCU节点下查询是否存在虚拟注册文件的MD5校验值以及时间戳,如果存在,则直接跳过后续步骤;
c5.加载虚拟注册文件到内存流中,用正则表达式进行文本处理,把子模块组件路径占位符中的虚拟路径替换为c2计算得到的进程主模块绝对路径;
c6.把虚拟注册数据中的路径HKEY_CLASSES_ROOT替换为HKEY_CURRENT_USER\SOFTWARE\VIRREG\[CRC32]\HKCUR,其中的[CRC32]是c3步骤计算得到的校验值;
c7.将修改后的注册信息写入到注册表中;
c8.在HKEY_CURRENT_USER\SOFTWARE\VIRREG\[CRC32]\HKCU节点下写入导入文件的MD5校验值和导入时的时间戳,用于判断步骤c是否需要重新导入虚拟注册数据。
步骤d具体包括如下细分步骤:
d1.初始化一个注册表键句柄列表对象;
d2.调用OpenThreadToken函数得到当前线程的AccessToken;
d3.调用ObtainTextSid函数传入d2步骤得到的AccessToken得到当前用户的sid;
d4.关闭AccessToken。
步骤e具体包括如下细分步骤:
e1.当程序进程需要调用COM组件时,COM组件创建模块向注册表发送查询组件注册信息的请求;
e2.采用打开键钩子函数ZwOpenKeyHook,调用内核ZwOpenKey函数,重定向到步骤c的虚拟注册表节点路径;
e3.采用键信息查询钩子函数ZwQueryKeyHook,调用内核ZwQueryKey函数,查询e3步骤打开的键的概要信息;
e4.采用键值读取钩子函数ZwQueryValueKeyHook,调用内核ZwQueryValueKey函数,读取键值,并将键值发送给COM组件创建模块,从而COM组件得以顺利启用;
e5.采用关闭键钩子函数ZwCloseHook,调用内核ZwClose函数关闭打开的键。
参照图4,步骤e2具体包括如下细分步骤:
e2-1.调用ZwOpenKey函数尝试打开注册键;
e2-2.检查e2-1返回值,如果返回值为STATUS_SUCCESS,根据键的路径判断是否属于虚拟注册组件的路径,如果是则记录到全局列表中以备后续检索;跳转到步骤e2-5;
e2-3.继续检查步骤e2-1返回值,如果返回值为STATUS_OBJECT_NAME_NOT_FOUND,把虚拟注册路径和e2-1步骤的键路径结合得到绝对路径;
e2-4.用e2-3步骤的绝对路径调用ZwOpenKey,将句柄记录到全局列表中;
e2-5.函数返回,完成步骤e2;
参照图5,步骤e3具体包括如下细分步骤:
e3-1.对查询的键句柄KeyHandle与¥FFFFFFFC进行“位与运算”,得到一个新句柄;
e3-2.对e3-1步骤的新句柄在步骤e2-2保存的全局列表中进行检索,如果未检索到则跳转到e3-4;
e3-3.根据入参判断函数调用方是否仅查询键值长度,再检查传入的缓冲长度参数是否足以容纳键值,如果可以容纳就设置状态标识为STATUS_SUCCESS,否则设置状态标识为STATUS_BUFFER_TOO_SMALL,然后跳到步骤e3-5;其他情况,直接执行下一步;
e3-4.调用ZwQueryKey并返回结果;
e3-5.函数返回,完成步骤e3;
参照图6,步骤e4具体包括如下细分步骤:
e4-1.调用ZwQueryKey函数查询键的路径,如果路径是以\REGISTRY\MACHINE\SOFTWARE\Classes开头或者以\REGISTRY\USER\<sid>\Classes开头,则把此开头部分替换为HKEY_CLASSES_ROOT,这里的sid是d3步骤所获取的具体的用户的sid,这一步就得到注册表键的绝对路径;
e4-2.判断e4-1步骤所得绝对路径是否HKEY_CLASSES_ROOT节点的子路经,如果是,则删除HKEY_CLASSES_ROOT前缀转为相对路径,否则跳转e4-6;
e4-3.调用ZwOpenKey,打开成功把句柄保存;
e4-4.用e4-3临时保存的句柄调用ZwQueryValueKey;
e4-5.调用ZwClose关闭e4-3保存的临时句柄。跳转e4-7;
e4-6.用原来的输入句柄调用ZwQueryValueKey函数;
e4-7.函数返回,完成步骤e4;
步骤e5具体包括如下细分步骤:
e5-1.把KeyHandle参数与¥FFFFFFFC进行“位与运算”,得到新句柄;
e5-2.用e5-1得到的新句柄调用ZwClose;
e5-3.从步骤e2-2的全局列表中删除对应的句柄;
e5-4.函数返回,完成步骤e5。
参照图8、图3,一种COM组件的多版本并行运行装置,包括:
注册数据生成模块:用于把COM组件的注册数据采集后处理成虚拟注册数据,把COM组件模块路径设为某一虚拟路径作为占位符,把虚拟注册数据保存到虚拟注册文件中;
安装模块:用于把COM组件的动态链接库和虚拟注册文件安装到程序目录下;
注册数据导入模块:用于在程序进程启动时,把虚拟注册文件导入到一个对主程序运行路径散列运算所得的一个注册表节点,该节点在HKEY_CURRENT_USER节点下的子节点,把COM组件所在模块的注册路径InprocServer32调整为基于程序主模块绝对路径;
初始化模块:用于初始化程序进程全局信息;
注册表重定向模块:用于当程序进程需要调用COM组件时,采用钩子函数拦截操作系统内核层的由ntdll.dll导出的注册表访问函数对于HKEY_CLASSES_ROOT的访问,重定向到注册数据导入模块的虚拟注册表节点路径,这样COM组件在系统中实现了虚拟注册,从而使得多个版本的COM组件可以并行运行。
ZwOpenKey函数(WIN7以上系统为ZwOpenKeyEx函数)、ZwQueryKey函数、ZwQueryValueKey函数、ZwClose函数四个函数是操作系统的模块ntdll.dll导出的注册表访问函数。本装置的注册表重定向模块利用进程内API Hook技术对这几个函数进行拦截。进程内所有对这四个函数的调用实际上会被替换成对相应钩子函数的调用,内核函数与钩子函数的对应关系如图7所示。由于注册表重定向模块里保存了这四个函数的内存地址,所以在钩子函数里还可以在需要时再调用原函数。
本发明并行运行装置中的注册数据导入模块、初始化模块、注册表重定向模块可封装为标准的Windows动态链接库。需要实现COM组件并行运行的应用程序只需在进程入口点首先加载装置即可,不需要调用任何接口函数。修改主程序入口点的方法是调用loadlibrary函数,可以用exescope或类似pe编辑工具把本装置模块写入PE Import列表。
下面用一个实施例来具体的说明本发明的应用方式和实际效果。设有一个COM组件,名字为Cell,它是一个表格组件,它是用ActiveX技术开发的。这个组件有两个不同的版本:1.0和2.0。Cell组件2.0与1.0并不兼容,但是组件的classid等关键数据是相同的。有三个应用程序需要调用这个COM组件。为了便于描述,这三个应用程序分别以应用程序A,应用程序B和应用程序C来命名。这三个应用程序计划安装的路径及调用的COM组件Cell版本如下所示:
应用程序A,安装路径为C:\AAA,调用的Cell组件版本为1.0;
应用程序B,安装路径为C:\BBB,调用的Cell组件版本为1.0;
应用程序C,安装路径为C:\CCC,调用的Cell组件版本为2.0。
现有技术中,Cell组件的传统注册路径数据如下所示(安装程序AAA的场景):
我们在一个“干净”的系统里先安装程序AAA及组件Cell,这时应用程序AAA安装到C:\AAA,它将运行正常。
我们继续安装程序B,在安装过程中也会安装组件Cell,并且会更新组件的注册数据如下(片段)。
在当前状态下,应用程序A和B都会正常运行。
第一种场景:接下来我们删除应用程序B再去运行程序A,这是程序将会报错:表格组件丢失了,因为注册数据指向了C:\BBB\CellPro.ocx,但是这个组件模块已经被删除了,即使C:\AAA\CellPro.ocx模块还存在。
第二种场景:安装程序C,表格组件的注册数据被更新如下(片段)
这时我们运行程序A和B会发现程序运行不正常,因为组件被更新不兼容的版本。
而本发明的COM组件的多版本并行运行方法和装置可以很好地解决这个问题,下面以程序A调用COM组件运行为例,说明如下:
步骤a中生成一个虚拟注册文件,将COM组件模块路径设为某一虚拟路径作为占位符,比如设为“C:\VirDir。”
步骤b是将COM组件的动态链接库v1.0和对应的虚拟注册文件安装在程序A的安装路径下;
当启动程序A时,步骤c该虚拟注册文件导入到HKEY_CURRENT_USER节点下,把COM组件所在模块的注册路径InprocServer32调整为基于程序主模块绝对路径,比如程序A安装在C:\AAA,则把InprocServer32设为@="C:\\AAA\\CellPro.ocx";
步骤e中,COM组件创建模块向注册表发送查询组件注册信息的请求,注册表重定向模块拦截到对于注册表[HKEY_CLASSES_ROOT\的访问,重定向到HKEY_CURRENT_USER下的组件注册信息,由于注册信息与组件的安装路径匹配,从而COM组件在系统中实现了虚拟注册,虽未实际注册但是得以顺利启用,程序A正常运行。
同理,程序B运行时,程序B的安装路径下同样安装有COM组件的动态链接库v1.0和对应的虚拟注册文件。区别是步骤c中将HKEY_CURRENT_USER下的InprocServer32设为@="C:\\BBB\\CellPro.ocx";由于在调用COM组件时,COM组件实现了虚拟注册,从而程序B也能正常运行。
同理,程序C运行时,程序C的安装路径下同样安装有COM组件的动态链接库V2.0和对应的虚拟注册文件。区别是步骤c中将HKEY_CURRENT_USER下的InprocServer32设为@="C:\\CCC\\CellPro.ocx";由于在调用COM组件时,COM组件实现了虚拟注册,从而程序C也能正常运行。
即便删除某个程序,也不影响其它程序的运行,从而实现了COM组件的多版本并行运行。

Claims (10)

1.一种COM组件的多版本并行运行方法,其特征在于包括如下步骤:
a.预先把COM组件的注册数据采集后处理成虚拟注册数据,把COM组件模块路径设为某一虚拟路径作为占位符,把虚拟注册数据保存到虚拟注册文件中;
b.把COM组件的动态链接库和虚拟注册文件安装到程序目录下;
c.程序进程启动时,把虚拟注册文件导入到一个对主程序运行路径散列运算所得的一个注册表节点,该节点在HKEY_CURRENT_USER节点下的子节点,把COM组件所在模块的注册路径InprocServer32调整为基于程序主模块绝对路径;
d.初始化程序进程全局信息;
e.当程序进程需要调用COM组件时,采用钩子函数拦截操作系统内核层的由ntdll.dll导出的注册表访问函数对于HKEY_CLASSES_ROOT的访问,重定向到步骤c的散列运算所得到的虚拟注册表节点路径,这样COM组件在系统中实现了虚拟注册,虽未实际注册但是得以顺利启用,程序正常运行;
f.重复步骤a-e,使另一版本的COM组件顺利启用,从而实现COM组件的多版本并行运行。
2.根据权利要求1所述的COM组件的多版本并行运行方法,其特征在于:步骤c在注册表节点中还写入虚拟注册文件的MD5校验值和初次导入虚拟注册文件时的时间戳;步骤c运行时先判断虚拟注册文件的MD5校验值与注册表节点的数据是否一致,如果一致,则直接跳过导入步骤。
3.根据权利要求1所述的COM组件的多版本并行运行方法,其特征在于:步骤a的虚拟路径为C:\VirDir。
4.根据权利要求1所述的COM组件的多版本并行运行方法,其特征在于:步骤a利用注册表蜂巢技术来实现,具体包括如下细分步骤:
a1.创建HKEY_CLASSES_ROOT键在自定义hive中的映射键,开启Hive状态;
a2.准备DllRegisterServer的函数指针类型;
a3.调用LoadLibrary()加载COM组件所在模块;
a4.调用GetProcAddress()获得DllRegisterServer的地址;
a5.调用OleInitialize()初始化COM库;
a6.使用a4步骤得到的地址调用DllRegisterServer;
a7.执行必要的清理工作:清理COM库,卸载组件,取消蜂巢化状态;
a8.把Hive键下的所有内容递归导出写入虚拟注册文件,把键路径改为HKEY_CLASSES_ROOT,把模块路径替换为模块虚拟路径,最后保存虚拟注册文件。
5.根据权利要求1所述的COM组件的多版本并行运行方法,其特征在于:步骤b具体包括如下细分步骤:
b1.复制COM组件的动态链接库到应用程序的主exe文件同一目录下;
b2.把步骤a生成的虚拟注册文件放入应用程序主exe的同级的registry目录。
6.根据权利要求2所述的COM组件的多版本并行运行方法,其特征在于:步骤c具体包括如下细分步骤:
c1.调用系统接口函数GetCurrentProcessId得到当前程序进程的id;
c2.根据进程id查询进程的模块信息,得到进程的主模块绝对路径;
c3.用哈希算法将绝对路径生成为固定长度的字符串,用CRC32算法生成绝对路径的校验值字符串;
c4.在HKEY_CURRENT_USER\SOFTWARE\VIRREG\[CRC32]\HKCU节点下查询是否存在虚拟注册文件的MD5校验值以及时间戳,如果存在,则直接跳过后续步骤;
c5.加载虚拟注册文件到内存流中,用正则表达式进行文本处理,把子模块组件路径占位符中的虚拟路径替换为c2计算得到的进程主模块绝对路径;
c6.把虚拟注册数据中的路径HKEY_CLASSES_ROOT替换为HKEY_CURRENT_USER\SOFTWARE\VIRREG\[CRC32]\HKCUR,其中的[CRC32]是c3步骤计算得到的校验值;
c7.将修改后的注册信息写入到注册表中;
c8.在HKEY_CURRENT_USER\SOFTWARE\VIRREG\[CRC32]\HKCU节点下写入导入文件的MD5校验值和导入时的时间戳,用于判断步骤c是否需要重新导入虚拟注册数据。
7.根据权利要求1所述的COM组件的多版本并行运行方法,其特征在于:步骤d具体包括如下细分步骤:
d1.初始化一个注册表键句柄列表对象;
d2.调用OpenThreadToken函数得到当前线程的AccessToken;
d3.调用ObtainTextSid函数传入d2步骤得到的AccessToken得到当前用户的sid;
d4.关闭AccessToken。
8.根据权利要求7所述的COM组件的多版本并行运行方法,其特征在于:步骤e具体包括如下细分步骤:
e1.当程序进程需要调用COM组件时,COM组件创建模块向注册表发送查询组件注册信息的请求;
e2.采用打开键钩子函数,调用内核ZwOpenKey函数,重定向到步骤c的虚拟注册表节点路径;
e3.采用键信息查询钩子函数,调用内核ZwQueryKey函数,查询e3步骤打开的键的概要信息;
e4.采用键值读取钩子函数,调用内核ZwQueryValueKey函数,读取键值,并将键值发送给COM组件创建模块,从而COM组件得以顺利启用;
e5.采用关闭键钩子函数,调用内核ZwClose函数关闭打开的键。
9.根据权利要求8所述的COM组件的多版本并行运行方法,其特征在于:
步骤e2具体包括如下细分步骤:
e2-1.调用ZwOpenKey函数尝试打开注册键;
e2-2.检查e2-1返回值,如果返回值为STATUS_SUCCESS,根据键的路径判断是否属于虚拟注册组件的路径,如果是则记录到全局列表中以备后续检索;跳转到步骤e2-5;
e2-3.继续检查步骤e2-1返回值,如果返回值为STATUS_OBJECT_NAME_NOT_FOUND,把虚拟注册路径和e2-1步骤的键路径结合得到绝对路径;
e2-4.用e2-3步骤的绝对路径调用ZwOpenKey,将句柄记录到全局列表中;
e2-5.函数返回,完成步骤e2;
步骤e3具体包括如下细分步骤:
e3-1.对查询的键句柄KeyHandle与¥FFFFFFFC进行“位与运算”,得到一个新句柄;
e3-2.对e3-1步骤的新句柄在步骤e2-2保存的全局列表中进行检索,如果未检索到则跳转到e3-4;
e3-3.根据入参判断函数调用方是否仅查询键值长度,再检查传入的缓冲长度参数是否足以容纳键值,如果可以容纳就设置状态标识为STATUS_SUCCESS,否则设置状态标识为STATUS_BUFFER_TOO_SMALL,然后跳到步骤e3-5;其他情况,直接执行下一步;
e3-4.调用ZwQueryKey并返回结果;
e3-5.函数返回,完成步骤e3;
步骤e4具体包括如下细分步骤:
e4-1.调用ZwQueryKey函数查询键的路径,如果路径是以\REGISTRY\MACHINE\SOFTWARE\Classes开头或者以\REGISTRY\USER\<sid>\Classes开头,则把此开头部分替换为HKEY_CLASSES_ROOT,这里的sid是d3步骤所获取的具体的用户的sid,这一步就得到注册表键的绝对路径;
e4-2.判断e4-1步骤所得绝对路径是否HKEY_CLASSES_ROOT节点的子路经,如果是,则删除HKEY_CLASSES_ROOT前缀转为相对路径,否则跳转e4-6;
e4-3.调用ZwOpenKey,打开成功把句柄保存;
e4-4.用e4-3临时保存的句柄调用ZwQueryValueKey;
e4-5.调用ZwClose关闭e4-3保存的临时句柄。跳转e4-7;
e4-6.用原来的输入句柄调用ZwQueryValueKey函数;
e4-7.函数返回,完成步骤e4;
步骤e5具体包括如下细分步骤:
e5-1.把KeyHandle参数与¥FFFFFFFC进行“位与运算”,得到新句柄;
e5-2.用e5-1得到的新句柄调用ZwClose;
e5-3.从步骤e2-2的全局列表中删除对应的句柄;
e5-4.函数返回,完成步骤e5。
10.一种COM组件的多版本并行运行装置,其特征在于包括:
注册数据生成模块:用于把COM组件的注册数据采集后处理成虚拟注册数据,把COM组件模块路径设为某一虚拟路径作为占位符,把虚拟注册数据保存到虚拟注册文件中;
安装模块:用于把COM组件的动态链接库和虚拟注册文件安装到程序目录下;
注册数据导入模块:用于在程序进程启动时,把虚拟注册文件导入到一个对主程序运行路径散列运算所得的一个注册表节点,该节点在HKEY_CURRENT_USER约定节点下的子节点,把COM组件所在模块的注册路径InprocServer32调整为基于程序主模块绝对路径;
初始化模块:用于初始化程序进程全局信息;
注册表重定向模块:用于当程序进程需要调用COM组件时,采用钩子函数拦截操作系统内核层的由ntdll.dll导出的注册表访问函数对于HKEY_CLASSES_ROOT的访问,重定向到注册数据导入模块的虚拟注册表节点路径,这样COM组件在系统中实现了虚拟注册,从而使得多个版本的COM组件可以并行运行。
CN201811476646.1A 2018-12-04 2018-12-04 一种com组件的多版本并行运行方法和装置 Active CN109614165B (zh)

Priority Applications (1)

Application Number Priority Date Filing Date Title
CN201811476646.1A CN109614165B (zh) 2018-12-04 2018-12-04 一种com组件的多版本并行运行方法和装置

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
CN201811476646.1A CN109614165B (zh) 2018-12-04 2018-12-04 一种com组件的多版本并行运行方法和装置

Publications (2)

Publication Number Publication Date
CN109614165A true CN109614165A (zh) 2019-04-12
CN109614165B CN109614165B (zh) 2020-05-05

Family

ID=66006442

Family Applications (1)

Application Number Title Priority Date Filing Date
CN201811476646.1A Active CN109614165B (zh) 2018-12-04 2018-12-04 一种com组件的多版本并行运行方法和装置

Country Status (1)

Country Link
CN (1) CN109614165B (zh)

Cited By (10)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN110286940A (zh) * 2019-06-26 2019-09-27 四川长虹电器股份有限公司 智能电视日志生成方法
CN111142969A (zh) * 2019-12-27 2020-05-12 贵阳动视云科技有限公司 64位程序调用32位程序模块的方法、装置、介质及设备
CN111240767A (zh) * 2020-02-04 2020-06-05 北京字节跳动网络技术有限公司 组件和页面加载方法、装置、电子设备及存储介质
CN111367586A (zh) * 2020-03-18 2020-07-03 北京艾克斯特科技有限公司 一种plm系统客户端及其工作机制
CN112988353A (zh) * 2021-03-12 2021-06-18 北京明朝万达科技股份有限公司 一种应用程序的运行控制方法及装置
CN113906392A (zh) * 2019-09-27 2022-01-07 茨特里克斯系统公司 用于提供不同版本的虚拟应用的系统和方法
CN114936031A (zh) * 2022-07-22 2022-08-23 浙江中控技术股份有限公司 组件的调用方法及电子设备
CN116795452A (zh) * 2023-07-20 2023-09-22 龙芯中科(北京)信息技术有限公司 驱动程序兼容性的确定方法、装置及设备
CN116975002A (zh) * 2023-09-22 2023-10-31 麒麟软件有限公司 一种在国产Linux操作系统下保护打开文件的方法
CN117931755A (zh) * 2024-03-22 2024-04-26 上海合见工业软件集团有限公司 批量导入封装库的方法、装置、设备和介质

Citations (3)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
WO2000062141A2 (en) * 1999-04-08 2000-10-19 Chicago-Soft, Ltd. Method and system for dynamic injection of execution logic into a shared memory space of a windowed operating system
CN101493766A (zh) * 2009-02-24 2009-07-29 浪潮集团山东通用软件有限公司 一种解决active x组件版本冲突的轻量级虚拟化方法
CN104462956B (zh) * 2013-09-23 2017-07-25 安一恒通(北京)科技有限公司 一种获得操作系统控制权的方法和装置

Patent Citations (3)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
WO2000062141A2 (en) * 1999-04-08 2000-10-19 Chicago-Soft, Ltd. Method and system for dynamic injection of execution logic into a shared memory space of a windowed operating system
CN101493766A (zh) * 2009-02-24 2009-07-29 浪潮集团山东通用软件有限公司 一种解决active x组件版本冲突的轻量级虚拟化方法
CN104462956B (zh) * 2013-09-23 2017-07-25 安一恒通(北京)科技有限公司 一种获得操作系统控制权的方法和装置

Cited By (15)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN110286940A (zh) * 2019-06-26 2019-09-27 四川长虹电器股份有限公司 智能电视日志生成方法
CN110286940B (zh) * 2019-06-26 2022-03-25 四川长虹电器股份有限公司 智能电视日志生成方法
CN113906392A (zh) * 2019-09-27 2022-01-07 茨特里克斯系统公司 用于提供不同版本的虚拟应用的系统和方法
CN111142969A (zh) * 2019-12-27 2020-05-12 贵阳动视云科技有限公司 64位程序调用32位程序模块的方法、装置、介质及设备
CN111240767A (zh) * 2020-02-04 2020-06-05 北京字节跳动网络技术有限公司 组件和页面加载方法、装置、电子设备及存储介质
CN111367586A (zh) * 2020-03-18 2020-07-03 北京艾克斯特科技有限公司 一种plm系统客户端及其工作机制
CN111367586B (zh) * 2020-03-18 2023-09-29 北京艾克斯特科技有限公司 一种plm系统客户端及其工作方法
CN112988353A (zh) * 2021-03-12 2021-06-18 北京明朝万达科技股份有限公司 一种应用程序的运行控制方法及装置
CN114936031A (zh) * 2022-07-22 2022-08-23 浙江中控技术股份有限公司 组件的调用方法及电子设备
CN116795452A (zh) * 2023-07-20 2023-09-22 龙芯中科(北京)信息技术有限公司 驱动程序兼容性的确定方法、装置及设备
CN116795452B (zh) * 2023-07-20 2024-04-02 龙芯中科(北京)信息技术有限公司 驱动程序兼容性的确定方法、装置及设备
CN116975002A (zh) * 2023-09-22 2023-10-31 麒麟软件有限公司 一种在国产Linux操作系统下保护打开文件的方法
CN116975002B (zh) * 2023-09-22 2023-12-26 麒麟软件有限公司 一种在国产Linux操作系统下保护打开文件的方法
CN117931755A (zh) * 2024-03-22 2024-04-26 上海合见工业软件集团有限公司 批量导入封装库的方法、装置、设备和介质
CN117931755B (zh) * 2024-03-22 2024-06-18 上海合见工业软件集团有限公司 批量导入封装库的方法、装置、设备和介质

Also Published As

Publication number Publication date
CN109614165B (zh) 2020-05-05

Similar Documents

Publication Publication Date Title
CN109614165A (zh) 一种com组件的多版本并行运行方法和装置
US6269442B1 (en) Apparatus and method for on-line replacement of a running program code and data using checkpoints
US7644402B1 (en) Method for sharing runtime representation of software components across component loaders
US20030093420A1 (en) Method and system for retrieving sharable information using a hierarchically dependent directory structure
CN101329636B (zh) 虚拟化窗口信息的方法和设备
US6415435B1 (en) Method and apparatus for determining compatibility of parent classes in an object oriented environment using versioning
US6182245B1 (en) Software test case client/server system and method
US8332835B2 (en) Method and system for automated code-source indexing in java virtual machine environment
US6173289B1 (en) Apparatus and method for performing actions on object-oriented software objects in a directory services system
US6529985B1 (en) Selective interception of system calls
US7506338B2 (en) Method and apparatus for simplifying the deployment and serviceability of commercial software environments
US7440980B2 (en) Computer file management system
US7954096B2 (en) Shared loader system and method
US20100205604A1 (en) Systems and methods for efficiently running multiple instances of multiple applications
US20030149799A1 (en) System supporting unified event handling in ECMAScript
US20060225072A1 (en) Packaging multiple groups of read-only files of an application's components into multiple shared libraries
EP0707264A2 (en) System and method for determining whether a software package conforms to packaging rules and requirements
US7814472B2 (en) System and method for shared code-sourcing in a Java Virtual Machine environment
US7930691B2 (en) Methods and apparatus for updating data structures during in-service upgrade of software in network processor
GB2437561A (en) Methods and apparatus for performing in-service upgrade of software in network processor
CA2477783A1 (en) Iterative software development environment with prioritized build rules
JPH1040087A (ja) ソフトウェア工学で使われるデータモデルの取り扱い方法
US8271557B1 (en) Configuration of a large-scale reconfigurable computing arrangement using a virtual file system interface
US7406687B1 (en) Sharing runtime representation of software component methods across component loaders
CN110515647A (zh) 一种静态资源管理方法、装置、设备和存储介质

Legal Events

Date Code Title Description
PB01 Publication
PB01 Publication
SE01 Entry into force of request for substantive examination
SE01 Entry into force of request for substantive examination
GR01 Patent grant
GR01 Patent grant