当前位置: 首页 > 面试题库 >

通过注册的TLB从python访问未注册的COM对象

姜彬郁
2023-03-14
问题内容

我目前正在使用三段代码:

  • 封闭源应用程序(Main.exe)
  • 实现为dll(comobj.dll)的封闭源VB COM对象
  • 我在Python中开发的代码

comobj.dll承载一个我想从Python使用的COM对象(比如说“
MainInteract”)。我已经可以从IronPython使用此对象,但是由于其他要求,我需要从常规Python使用它。我相信这里最好的方法是使用win32com,但我根本无法取得任何进展。

首先,一些可用的IronPython代码:

import clr
import os
import sys

__dir__ = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, __dir__)
sys.path.append(r"C:\Path\To\comobj.dll") #This is where the com object dll actually is

clr.AddReferenceToFileAndPath(os.path.join(__dir__, r'comobj_1_1.dll')) #This is the .NET interop assembly that was created automatically via SharpDevelop's COM Inspector

from comobj_1_1 import clsMainInteract

o = clsMainInteract()
o.DoStuff(True)

现在,我在常规Python中尝试的代码:

>>> import win32com.client
>>> win32com.client.Dispatch("{11111111-comobj_guid_i_got_from_com_inspector}")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python26\lib\site-packages\win32com\client\__init__.py", line 95, in Dispatch
    dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx)
  File "C:\Python26\lib\site-packages\win32com\client\dynamic.py", line 104, in _GetGoodDispatchAndUserName
    return (_GetGoodDispatch(IDispatch, clsctx), userName)
  File "C:\Python26\lib\site-packages\win32com\client\dynamic.py", line 84, in _GetGoodDispatch
    IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch)
 pywintypes.com_error: (-2147221164, 'Class not registered', None, None)

我也尝试使用TLB的友好名称:

>>> import win32com.client
>>> win32com.client.Dispatch("Friendly TLB Name I Saw")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python26\lib\site-packages\win32com\client\__init__.py", line 95, in Dispatch
dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx)
  File "C:\Python26\lib\site-packages\win32com\client\dynamic.py", line 104, in _GetGoodDispatchAndUserName
return (_GetGoodDispatch(IDispatch, clsctx), userName)
  File "C:\Python26\lib\site-packages\win32com\client\dynamic.py", line 84, in _GetGoodDispatch
    IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch)
pywintypes.com_error: (-2147221005, 'Invalid class string', None, None)

实际上,我唯一的成功就是:

import pythoncom
tlb = pythoncom.LoadRegTypeLib("{11111111-comobj_guid_i_got_from_com_inspector}",1,1,0)
>>> tlb
<PyITypeLib at 0x00AD7D78 with obj at 0x0025EDF0>
>>> tlb.GetDocumentation(1)
(u'clsMainInteract', None, 0, None)

但是我不知道如何从那里得到一个物体。我认为我的问题是我需要将dll加载到我的进程中,并使其在进程的COM源中进行自身注册,因此可以在其上正确地CoCreateInstance
/ win32com.client.Dispatch()。

我还看到了引用的激活上下文,特别是在谈论“不注册COM”时,但是通常用诸如“如果您在.manifest文件中指定正确的内容,Windows将为您创建上下文”之类的句子中。我想尽可能避免使用清单文件,因为与(封闭源)COM对象dll在同一文件夹中将需要一个清单文件,如果可以避免的话,我宁愿不删除该目录中的任何文件。

谢谢您的帮助。


问题答案:

有关包装object-from-DLL和其他情况的有用实用程序模块,请参见https://gist.github.com/4219140

__all__ = (
    ####### Class Objects

    #CoGetClassObject - Normal, not wrapped
    'CoDllGetClassObject', #Get ClassObject from a DLL file

    ####### ClassFactory::CreateInstance Wrappers

    'CoCreateInstanceFromFactory', #Create an object via IClassFactory::CreateInstance
    'CoCreateInstanceFromFactoryLicenced', #Create a licenced object via IClassFactory2::CreateInstanceLic

    ###### Util

    'CoReleaseObject', #Calls Release() on a COM object

    ###### Main Utility Methods

    #'CoCreateInstance', #Not wrapped, normal call
    'CoCreateInstanceLicenced', #CoCreateInstance, but with a licence key

    ###### Hacky DLL methods for reg-free COM without Activation Contexts, manifests, etc
    'CoCreateInstanceFromDll', #Given a dll, a clsid, and an iid, create an object
    'CoCreateInstanceFromDllLicenced', #Given a dll, a clsid, an iid, and a license key, create an object
)

IID_IClassFactory2 = "{B196B28F-BAB4-101A-B69C-00AA00341D07}"

from uuid import UUID
from ctypes import OleDLL, WinDLL, c_ulong, byref, WINFUNCTYPE, POINTER, c_char_p, c_void_p
from ctypes.wintypes import HRESULT
import pythoncom
import win32com.client

import logging
log = logging.getLogger(__name__)


def _raw_guid(guid):
    """Given a string GUID, or a pythoncom IID, return the GUID laid out in memory suitable for passing to ctypes"""
    return UUID(str(guid)).bytes_le

proto_icf2_base = WINFUNCTYPE(HRESULT,
    c_ulong,
    c_ulong,
    c_char_p,
    c_ulong,
    POINTER(c_ulong),
)
IClassFactory2__CreateInstanceLic = proto_icf2_base(7, 'CreateInstanceLic', (
    (1, 'pUnkOuter'),
    (1 | 4, 'pUnkReserved'),
    (1, 'riid'),
    (1, 'bstrKey'),
    (2, 'ppvObj'),
    ), _raw_guid(IID_IClassFactory2))

#--------------------------------
#--------------------------------

def _pc_wrap(iptr, resultCLSID=None):
    #return win32com.client.__WrapDispatch(iptr)
    log.debug("_pc_wrap: %s, %s"%(iptr, resultCLSID))
    disp = win32com.client.Dispatch(iptr, resultCLSID=resultCLSID)
    log.debug("_pc_wrap: %s (%s)", disp.__class__.__name__, disp)
    return disp

def CoCreateInstanceFromFactory(factory_ptr, iid_interface=pythoncom.IID_IDispatch, pUnkOuter=None):
    """Given a factory_ptr whose interface is IClassFactory, create the instance of clsid_class with the specified interface"""
    ClassFactory = pythoncom.ObjectFromAddress(factory_ptr.value, pythoncom.IID_IClassFactory)
    i = ClassFactory.CreateInstance(pUnkOuter, iid_interface)
    return i

def CoCreateInstanceFromFactoryLicenced(factory_ptr, key, iid_interface=pythoncom.IID_IDispatch, pUnkOuter=None):
    """Given a factory_ptr whose interface is IClassFactory2, create the instance of clsid_class with the specified interface"""
    requested_iid = _raw_guid(iid_interface)

    ole_aut = WinDLL("OleAut32.dll")
    key_bstr = ole_aut.SysAllocString(unicode(key))
    try:
        obj = IClassFactory2__CreateInstanceLic(factory_ptr, pUnkOuter or 0, c_char_p(requested_iid), key_bstr)
        disp_obj = pythoncom.ObjectFromAddress(obj, iid_interface)
        return disp_obj
    finally:
        if key_bstr:
            ole_aut.SysFreeString(key_bstr)

#----------------------------------

def CoReleaseObject(obj_ptr):
    """Calls Release() on a COM object. obj_ptr should be a c_void_p"""
    if not obj_ptr:
        return
    IUnknown__Release = WINFUNCTYPE(HRESULT)(2, 'Release', (), pythoncom.IID_IUnknown)
    IUnknown__Release(obj_ptr)

#-----------------------------------

def CoCreateInstanceLicenced(clsid_class, key, pythoncom_iid_interface=pythoncom.IID_IDispatch, dwClsContext=pythoncom.CLSCTX_SERVER, pythoncom_wrapdisp=True, wrapas=None):
    """Uses IClassFactory2::CreateInstanceLic to create a COM object given a licence key."""
    IID_IClassFactory2 = "{B196B28F-BAB4-101A-B69C-00AA00341D07}"
    ole = OleDLL("Ole32.dll")
    clsid_class_raw = _raw_guid(clsid_class)
    iclassfactory2 = _raw_guid(IID_IClassFactory2)
    com_classfactory = c_void_p(0)

    ole.CoGetClassObject(clsid_class_raw, dwClsContext, None, iclassfactory2, byref(com_classfactory))
    try:
        iptr = CoCreateInstanceFromFactoryLicenced(
                factory_ptr = com_classfactory,
                key=key,
                iid_interface=pythoncom_iid_interface,
                pUnkOuter=None,
        )
        if pythoncom_wrapdisp:
            return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class)
        return iptr
    finally:
        if com_classfactory:
            CoReleaseObject(com_classfactory)

#-----------------------------------------------------------
#DLLs

def CoDllGetClassObject(dll_filename, clsid_class, iid_factory=pythoncom.IID_IClassFactory):
    """Given a DLL filename and a desired class, return the factory for that class (as a c_void_p)"""
    dll = OleDLL(dll_filename)
    clsid_class = _raw_guid(clsid_class)
    iclassfactory = _raw_guid(iid_factory)
    com_classfactory = c_void_p(0)
    dll.DllGetClassObject(clsid_class, iclassfactory, byref(com_classfactory))
    return com_classfactory

def CoCreateInstanceFromDll(dll, clsid_class, iid_interface=pythoncom.IID_IDispatch, pythoncom_wrapdisp=True, wrapas=None):
    iclassfactory_ptr = CoDllGetClassObject(dll, clsid_class)
    try:
        iptr = CoCreateInstanceFromFactory(iclassfactory_ptr, iid_interface)
        if pythoncom_wrapdisp:
            return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class)
        return iptr
    finally:
        CoReleaseObject(iclassfactory_ptr)

def CoCreateInstanceFromDllLicenced(dll, clsid_class, key, iid_interface=pythoncom.IID_IDispatch, pythoncom_wrapdisp=True, wrapas=None):
    iclassfactory2_ptr = CoDllGetClassObject(dll, clsid_class, iid_factory=IID_IClassFactory2)
    try:
        iptr = CoCreateInstanceFromFactoryLicenced(iclassfactory2_ptr, key, iid_interface)
        if pythoncom_wrapdisp:
            return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class)
        return iptr
    finally:
        CoReleaseObject(iclassfactory2_ptr)


 类似资料:
  • 注册与访问 打开后台-会员-注册与访问 1.注册类型:普通注册/邮箱注册/手机注册 如开启邮箱和手机注册,请在通知系统功能中进行邮箱与短信通知配置,游客在注册时通过验证后方能注册成功 2.后台验证码是否开启:开启后显示 商城验证码是否开启:开启后显示 3.是否允许注册会员:设置为不允许则游客无法注册成为站点会员 4.错误多次后显示:配置该项后,开启验证码后验证码默认不显示,在登录错误次数达到设置值

  • 本文向大家介绍使用Python的Windows注册表访问(Winreg),包括了使用Python的Windows注册表访问(Winreg)的使用技巧和注意事项,需要的朋友参考一下 作为一种通用的语言,以及大量用户支持的模块的可用性,我们发现python在操作系统级别的编程方面也很擅长。在本文中,我们将看到python如何访问Windows操作系统的注册表。 我们需要将名为winreg的模块导入py

  • 问题内容: 我已经使用GCM很长时间了。有一天,它突然破裂了。问题是我发送的第一个推送获得了成功状态,但该应用程序未收到任何推送。我发送的第二次推送失败,并显示NotRegistered错误。我重新安装该应用程序:成功(未收到通知),失败(未注册)->循环。我不知道发生了什么变化。Google支持非常无助,需要花费大量时间来回答简单的问题,无论是GCM问题,APNs问题还是客户问题。如果以前有人遇

  • 我正在尝试将一个图像推送到我的docker私有存储库: Docker告诉我: push引用存储库[living-registry.com:5000/busybox]Get https://living-registry.com:5000/v1/_ping:read tcp 195.83.122.16:39714->195.83.122.16:5000:read:对等体重置连接 这些命令正在Core

  • 我正在通过hook\u menu\u alter添加一个新路径,但当我访问此路径时,不会触发正确的页面回调。当我检查drupal core中的menu_execute_active_handler函数选择了什么路由器_项时,它会打印一个缺少最后1个path参数的父路径。这就是我如何改变菜单的方法。 其他模块也实现了hook\u menu\u alter 所以现在当我访问path时,它应该触发在第一

  • void register_object(string object_name, object $object, array allowed methods/properties, boolean format, array block methods) This is to register an object for use in the templates. See the object s

  • 情况:您通过MeterBinder在Spring Boot中注册了一个指标。也许它是自动配置的指标之一,如,或者它可能是您自己的自定义指标。但是有一天,您启动应用程序时,它丢失了。它没有报告,也没有显示在执行器中,它就这样消失了。 根本原因:可能是您的代码或您正在使用的库正在注入计量注册。这样做有很多正当理由,所以不要责怪自己。但是注入计量注册意味着它将在创建所有豆子(包括可能的计量标记)之前创建

  • POST /users 输入 名称 类型 描述 name 字符串 必须,用户名 phone 字符串 如果 verifiable_type 为 sms 则必须, 手机号码。 email String 如果 verifiable_type 为 mail 则必须, E-Mail。 password String 可选,密码,如果不输入密码,允许用户无密码注册。 verifiable_type 枚举: