从Windows PATH而不是清单加载不正确的DLL

时间:2015-04-13 04:45:47

标签: python-2.7 py2exe dllregistration comtypes

我在注册用Python编写的COM服务器时遇到问题,该服务器似乎与标准的uuid Python模块有关。

我在64位Windows 7专业版上运行32位Python 2.7.9。

当我在服务器中包含uuid模块时,在注册或取消注册过程中会出现故障(使用regsvr32)。如果我从我的项目中移除uuid,一切似乎都有效。

我使用了Dependency Walker进行调查。我没有详细了解正在发生的事情,但很明显,该进程在Windows PATH中找到了MSVCR90.DLL的副本,这恰好是DLL的错误版本,因此会出现故障。

现在我可以从路径中删除这个特定的MSVCR90.DLL文件,但它不属于我!它是由我们的IT部门安装的一些英特尔软件的分发版!无论如何,我希望能够将我的服务器分发给其他用户,并且无法控制其计算机的配置。

另外需要注意的是,我在COM服务器DLL旁边的清单中提供了正确版本的MSVCR90.DLL(通常用于分发基于Python的DLL可执行文件)。所以我希望Python uuid模块找到那个DLL并使用它。

我完全卡住了。任何人都可以提供解决方案吗?

以下是Dependency Walker的一些摘录。我看到从Windows PATH

加载的DLL不正确
00:00:04.742: LoadLibraryA("msvcr90.dll") called from "c:\proj_py\gtxl\sxs\dist\_CTYPES.PYD" at address 0x1D1A9742.
00:00:04.773: Loaded "c:\program files (x86)\intel\icls client\MSVCR90.DLL" at address 0x59AE0000.  Successfully hooked module.

下面几行我看到了这一行(第一行和最后一行显示为红色)

00:00:12.807: DllMain(0x59AE0000, DLL_PROCESS_ATTACH, 0x00000000) in "c:\program files (x86)\intel\icls client\MSVCR90.DLL" returned 0 (0x0).
00:00:12.839: DllMain(0x59AE0000, DLL_PROCESS_DETACH, 0x00000000) in "c:\program files (x86)\intel\icls client\MSVCR90.DLL" called.
00:00:12.839: DllMain(0x59AE0000, DLL_PROCESS_DETACH, 0x00000000) in "c:\program files (x86)\intel\icls client\MSVCR90.DLL" returned 0 (0x0).
00:00:12.854: Unloaded "c:\program files (x86)\intel\icls client\MSVCR90.DLL" at address 0x59AE0000.
00:00:12.870: LoadLibraryA("msvcr90.dll") returned NULL. Error: A dynamic link library (DLL) initialization routine failed (1114).

这似乎是错误点。

现在,在我看来,一个名为_CTYPES.PYD的Python DLL会导致加载不需要的DLL。我假设uuid模块正在调用Python ctypes模块,该模块以某种方式与_ctypes.pyd相关联。

这是否意味着Python 2.7.9发行版中的_ctypes.pyd存在问题?

也许是最后一条线索。当我从PATH中删除有问题的DLL时。注册过程没有错误。但是,在Dependency Walker中我看到了这个

00:00:03.728: LoadLibraryA("msvcr90.dll") called from "c:\proj_py\gtxl\sxs\dist\_CTYPES.PYD" at address 0x1D1A9742.
00:00:03.759: LoadLibraryA("msvcr90.dll") returned NULL. Error: %1 is not a valid Win32 application (193).

第二行以红色突出显示。看起来这个尝试失败了,但是注册只是继续进行(我没有看到任何其他对msvcr90.dll的引用)。

以下是导致问题的简单示例的文件。我正在使用Python comtypes包与py2exe结合来创建服务器。

必须由MIDL编译器

编写的IDL文件test.idl
import "oaidl.idl";
import "ocidl.idl";

[
        uuid(EAE82E0D-312C-4C23-99D8-8BA686D89B72),
        dual,
        oleautomation
]
interface IMSLTest : IDispatch {
        HRESULT TestMethod([in] INT a, [in] INT b, [out, retval] INT *presult);
}

[
      uuid(7587E538-7AFD-4663-A444-34F32997B0E9)
]
library MSLTestLib
{
        importlib("stdole2.tlb");

        [uuid(B7051914-24BC-4FBB-A447-F75A9FA8E295)]
              coclass MyObject {
              [default] interface IMSLTest;
        };
};

Python COM服务器的源文件server.py

import comtypes
import comtypes.server.inprocserver

import uuid

# # generate wrapper code for the type library, this needs
# # to be done only once (but also each time the IDL file changes)
# # !!! NB  It needs to be done before py2exe is run !!!
# from comtypes.client import GetModule
# GetModule("test.tlb")

# Something has been created here
from comtypes.gen.MSLTestLib import MyObject

class MyObjectImpl(MyObject):

    # registry entries
    _reg_threading_ = "Both"
    _reg_progid_ = "MSLTestLib.MyObject"
    _reg_desc_ = "A test COM server"
    _reg_clsctx_ = comtypes.CLSCTX_INPROC_SERVER

    def __init__(self):
        MyObject.__init__(self)
        l = uuid.uuid4().int

    def TestMethod(self,a,b):
        return a + b

if __name__ == "__main__":
    from comtypes.server.register import UseCommandLine
    UseCommandLine(MyObjectImpl)

    # # Does it work?
    # # Must register the server using the two lines above first, 
    # # then uncomment these and comment out those above.
    # from comtypes.client import CreateObject
    # x = CreateObject("MSLTestLib.MyObject")
    # print x.TestMethod(3,4)

py2exe的配置文件,setup.py(放入清单中的文件的glob是特定于我的设置)

from distutils.core import setup
import py2exe
from glob import glob

data_files = [
        ("Microsoft.VC90.CRT", glob(r'C:\usr\lib\msvcr\*.*'))
    ]

class Target:
    def __init__(self, **kw):
        self.__dict__.update(kw)
        # for the version info resources (Properties -- Version)
        self.version = "0.0.0"
        self.company_name = "Mine"
        self.copyright = "c 2015"
        self.name = "Test"

my_com_server_target = Target(
    description = "A test server",
    # use module name for win32com exe/dll server
    modules = ["server"],
    # the following line embeds the typelib within the dll
    other_resources = [("TYPELIB", 1, open(r"test.tlb", "rb").read())],
    # specify which type of com server you want (exe and/or dll)
    create_exe = False,
    create_dll = True
)

includes = ["win32com" ,"win32service", "win32serviceutil", "win32event"]
excludes = ['tcl', 'Tkconstants', 'Tkinter', 'distutils','numpy','unittest']
packages = []
dll_excludes = [
    'tcl84.dll', 'tk84.dll', 
    'SHFOLDER.dll', 
    'Secur32.dll', 
    'MPR.dll', 
    'CRYPT32.dll', 
    'KERNELBASE.dll',
]
setup(
    data_files=data_files, 
    options={ "py2exe":
        dict(
            includes=includes,
            excludes=excludes,
            packages=packages,
            dll_excludes=dll_excludes,
            ascii=False,
            bundle_files=3,
            # skip_archive=True
        )      
    },
    ctypes_com_server = [my_com_server_target],
    zipfile=None,
)

以下是我的清单文件Microsoft.VC90.CRT.manifest的内容,它位于名为Microsoft.VC90.CRT的文件夹中,与msvcr90.dll一起,与我的COM服务器位于同一目录中。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) Microsoft Corporation.  All rights reserved. -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <noInheritable/>
    <assemblyIdentity
        type="win32"
        name="Microsoft.VC90.CRT"
        version="9.0.21022.8"
        processorArchitecture="x86"
        publicKeyToken="1fc8b3b9a1e18e3b"
    >
    </assemblyIdentity>
    <file name="msvcr90.dll" /> 
</assembly>

DLL中还有一个嵌入式清单。这是由py2exe自动生成的,没有任何内容。这是

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
</assembly>

0 个答案:

没有答案