py2exe com dll问题

发布于 2024-09-07 00:32:36 字数 10216 浏览 8 评论 0原文

我正在尝试用 python 制作一个 com dll。但我尝试注册到编译的 dll 时出现错误消息“运行时错误 r6034”和“无法加载 python dll”这个问题的解决方案是什么?

mycode:

setup.py:

# This is the distutils script for creating a Python-based com dll
# server using ctypes.com.  This script should be run like this:
#
#  % python setup.py py2exe
#
# After you run this (from this directory) you will find two directories here:
# "build" and "dist".  The .dll file in dist is what you are looking for.
##############################################################################

from distutils.core import setup
import py2exe
import sys

class Target:
    def __init__(self, **kw):
        self.__dict__.update(kw)
        # for the version info resources (Properties -- Version)
        self.version = "0.0.1"
        self.company_name = "my company"
        self.copyright = "2006, my company"
        self.name = "my com server name"

my_com_server_target = Target(
    description = "my com server",
    # use module name for ctypes.com dll server
    modules = ["view.view"],
    # the following line embeds the typelib within the dll
    #other_resources = [("TYPELIB", 1, open(r"view\view.tlb", "rb").read())],
    # we only want the inproc (dll) server
    create_exe = False
    )

setup(
    name="my_com_server",
    # the following two parameters embed support files within dll file
    options={"py2exe": {"bundle_files": 1, }},
    zipfile=None,
    version="0.0.1",
    description="my com server",
    # author, maintainer, contact go here:
    author="First Last",
    author_email="some_name@some_company.com",
    packages=["view"],
    ctypes_com_server=[my_com_server_target]
    )

和view.py:

# -*- coding: utf-8 -*-

# A sample context menu handler.
# Adds a 'Hello from Python' menu entry to .py files.  When clicked, a
# simple message box is displayed.
#
# To demostrate:
# * Execute this script to register the context menu.
# * Open Windows Explorer, and browse to a directory with a .py file.
# * Right-Click on a .py file - locate and click on 'Hello from Python' on
#   the context menu.

import ConfigParser
import os.path
import urllib
import pythoncom
from win32com.shell import shell, shellcon
import win32gui
import win32con

IContextMenu_Methods = ["QueryContextMenu", "InvokeCommand", "GetCommandString"]
IShellExtInit_Methods = ["Initialize"]

#HKCR Key   Affected object types
#*  All files
#AllFileSystemObjects   All regular files and file folders
#Folder     All folders, virtual and filesystem
#Directory  File folders
#Drive  Root folders of all system drives
#Network    Entire network
#NetShare   All network shares

TYPES = [
    '*',
    'Directory',
    ]
SUBKEY = 'MindRetrieve'

def alertError(hwnd, exc):
    win32gui.MessageBox(hwnd, str(exc), str(exc.__class__), win32con.MB_OK)


class ShellExtension:
    _reg_progid_ = "MindRetrieve.ShellExtension.ContextMenu"
    _reg_desc_ = "MindRetrieve Shell Extension (context menu)"
    _reg_clsid_ = "{ABB05546-EB55-4433-B068-A57667706828}"

    _com_interfaces_ = [shell.IID_IShellExtInit, shell.IID_IContextMenu]
    _public_methods_ = IContextMenu_Methods + IShellExtInit_Methods

    def Initialize(self, folder, dataobj, hkey):
        print "Init", folder, dataobj, hkey
        self.dataobj = dataobj

    def QueryContextMenu(self, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags):
        print "QCM", hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags

        try:
            # Query the items clicked on
#            files = self.getFiles()
#            msg =  len(files) > 1 and '&Tag %s files' % len(files) or '&Tag with MindRetrieve'
#            # TODO: we do not support tagging multiple files now
#            if not(files):
#                return
            msg = '&Tag with MindRetrieve'

            idCmd = idCmdFirst
            items = []
            if (uFlags & 0x000F) == shellcon.CMF_NORMAL: # Check == here, since CMF_NORMAL=0
                print "CMF_NORMAL..."
                items.append(msg)
            elif uFlags & shellcon.CMF_VERBSONLY:
                print "CMF_VERBSONLY..."
                items.append(msg)# + " - shortcut")
            elif uFlags & shellcon.CMF_EXPLORE:
                print "CMF_EXPLORE..."
                items.append(msg)# + " - normal file, right-click in Explorer")
            elif uFlags & shellcon.CMF_DEFAULTONLY:
                print "CMF_DEFAULTONLY...\r\n"
            else:
                print "** unknown flags", uFlags
            win32gui.InsertMenu(hMenu, indexMenu,
                                win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
                                0, None)
            indexMenu += 1
            for item in items:
                win32gui.InsertMenu(hMenu, indexMenu,
                                    win32con.MF_STRING|win32con.MF_BYPOSITION,
                                    idCmd, item)
                indexMenu += 1
                idCmd += 1

            win32gui.InsertMenu(hMenu, indexMenu,
                                win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
                                0, None)
            indexMenu += 1
            return idCmd-idCmdFirst # Must return number of menu items we added.

        except Exception, e:
            alertError(hwnd, e)
            raise


    def InvokeCommand(self, ci):
        mask, hwnd, verb, params, dir, nShow, hotkey, hicon = ci

        try:
            files = self.getFiles()
            if not files:
                return
            fname = files[0]

#            win32gui.MessageBox(hwnd, fname,  str(fname.__class__), win32con.MB_OK)

            fname = fname.encode('utf-8')
            file_url = urllib.pathname2url(fname)

    # 2005-12-20 Test urllib.pathname2url()
    #
    #>>> urllib.pathname2url(r'c:\tung\wäi')
    #'///C|/tung/w%84i'
    #>>> urllib.pathname2url(r'\tung\wäi')
    #'/tung/w%84i'
    #>>> urllib.pathname2url(r'tung\wäi')
    #'tung/w%84i'

            # prefer ':' as the drive separator rather than '|'
            if file_url.startswith('///') and file_url[4:5] == '|':
                file_url = file_url.replace('|',':',1)

            if file_url.startswith('//'):
                file_url = 'file:' + file_url
            elif file_url.startswith('/'):
                file_url = 'file://' + file_url
            else:
                # fname is a relative filename? Should not happen!
                file_url = 'file:///' + file_url

            url = getBaseURL() + '?url=' + urllib.quote(file_url)
            shell.ShellExecuteEx(fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
                                 lpFile=url,
                                 nShow=win32con.SW_NORMAL,
                                )
        except Exception, e:
            alertError(hwnd, e)
            raise


    def GetCommandString(self, cmd, typ):
        return "&Tag with MindRetrieve"


    def getFiles(self):
        format_etc = win32con.CF_HDROP, None, 1, -1, pythoncom.TYMED_HGLOBAL
        sm = self.dataobj.GetData(format_etc)
        num_files = shell.DragQueryFile(sm.data_handle, -1)
        files = [shell.DragQueryFile(sm.data_handle, i) for i in range(num_files)]
        return files


def getConfigPath():
    """ get the DLL path from registry """
    import _winreg

    # _winreg.QueryValue() may throw WindowsError

    # COM server registration in deployed environment
    # e.g. HKEY_CLASSES_ROOT\CLSID\{ABB05546-EB55-4433-B068-A57667706828}\InprocServer32
    #       =c:\Program Files\MindRetrieve\context_menu.dll
    subkey = 'CLSID\\%s\\InprocServer32' % ShellExtension._reg_clsid_
    path = _winreg.QueryValue(_winreg.HKEY_CLASSES_ROOT, subkey)
    head, tail = os.path.split(path)
    # quick check if this is in deployed environment
    if os.path.isabs(head):
        return head

    # Otherwise assume in development environment
    # e.g. HKEY_CLASSES_ROOT\CLSID\{ABB05546-EB55-4433-B068-A57667706828}\PythonCOMPath
    #       =g:\bin\py_repos\mindretrieve\trunk\minds\weblib\win32
    subkey = 'CLSID\\%s\\PythonCOMPath' % ShellExtension._reg_clsid_
    path = _winreg.QueryValue(_winreg.HKEY_CLASSES_ROOT, subkey)
    idx = path.lower().rfind('minds')   # truncate trailing 'minds\weblib\win32'
    if idx > 0:
        path = path[:idx-1]
    return path



def getHTTPAdminPort():
    """ get HTTP.admin_port from config.ini """
    pathname = os.path.join(getConfigPath(), 'config.ini')
    cp = ConfigParser.ConfigParser()
    cp.read(pathname)
    admin_port = cp.getint('http','admin_port')
    return admin_port


def getBaseURL():
    """ get the base URL """
    port = getHTTPAdminPort()
    return 'http://localhost:%s/weblib/_' % port


def DllRegisterServer():
    import _winreg
    for typ in TYPES:
        # e.g. HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\MindRetrieve
        key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT, "%s\\shellex" % typ)
        subkey = _winreg.CreateKey(key, "ContextMenuHandlers")
        subkey2 = _winreg.CreateKey(subkey, SUBKEY)
        _winreg.SetValueEx(subkey2, None, 0, _winreg.REG_SZ, ShellExtension._reg_clsid_)
    print ShellExtension._reg_desc_, "registration complete."


def DllUnregisterServer():
    import _winreg
    for typ in TYPES:
        try:
            # e.g. HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\MindRetrieve
            key = _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT, "%s\\shellex\\ContextMenuHandlers\\%s" % (typ, SUBKEY))
        except WindowsError, details:
            import errno
            if details.errno != errno.ENOENT:
                raise
    print ShellExtension._reg_desc_, "unregistration complete."


def main(argv):
    # assume argv == sys.argv
    from win32com.server import register
    register.UseCommandLine(ShellExtension,
                   finalize_register = DllRegisterServer,
                   finalize_unregister = DllUnregisterServer)


def test(argv):
    """ adhoc tests """
    print 'URL:', getBaseURL()


if __name__=='__main__':
    import sys
    if '-t' not in sys.argv:
        main(sys.argv)
    else:
        test(sys.argv)

i'm trying making a com dll in python. but i try register to compiled dll have a error message "run time error r6034" and "could not load python dll" what is the solution this problem ?

mycode :

setup.py:

# This is the distutils script for creating a Python-based com dll
# server using ctypes.com.  This script should be run like this:
#
#  % python setup.py py2exe
#
# After you run this (from this directory) you will find two directories here:
# "build" and "dist".  The .dll file in dist is what you are looking for.
##############################################################################

from distutils.core import setup
import py2exe
import sys

class Target:
    def __init__(self, **kw):
        self.__dict__.update(kw)
        # for the version info resources (Properties -- Version)
        self.version = "0.0.1"
        self.company_name = "my company"
        self.copyright = "2006, my company"
        self.name = "my com server name"

my_com_server_target = Target(
    description = "my com server",
    # use module name for ctypes.com dll server
    modules = ["view.view"],
    # the following line embeds the typelib within the dll
    #other_resources = [("TYPELIB", 1, open(r"view\view.tlb", "rb").read())],
    # we only want the inproc (dll) server
    create_exe = False
    )

setup(
    name="my_com_server",
    # the following two parameters embed support files within dll file
    options={"py2exe": {"bundle_files": 1, }},
    zipfile=None,
    version="0.0.1",
    description="my com server",
    # author, maintainer, contact go here:
    author="First Last",
    author_email="some_name@some_company.com",
    packages=["view"],
    ctypes_com_server=[my_com_server_target]
    )

and view.py:

# -*- coding: utf-8 -*-

# A sample context menu handler.
# Adds a 'Hello from Python' menu entry to .py files.  When clicked, a
# simple message box is displayed.
#
# To demostrate:
# * Execute this script to register the context menu.
# * Open Windows Explorer, and browse to a directory with a .py file.
# * Right-Click on a .py file - locate and click on 'Hello from Python' on
#   the context menu.

import ConfigParser
import os.path
import urllib
import pythoncom
from win32com.shell import shell, shellcon
import win32gui
import win32con

IContextMenu_Methods = ["QueryContextMenu", "InvokeCommand", "GetCommandString"]
IShellExtInit_Methods = ["Initialize"]

#HKCR Key   Affected object types
#*  All files
#AllFileSystemObjects   All regular files and file folders
#Folder     All folders, virtual and filesystem
#Directory  File folders
#Drive  Root folders of all system drives
#Network    Entire network
#NetShare   All network shares

TYPES = [
    '*',
    'Directory',
    ]
SUBKEY = 'MindRetrieve'

def alertError(hwnd, exc):
    win32gui.MessageBox(hwnd, str(exc), str(exc.__class__), win32con.MB_OK)


class ShellExtension:
    _reg_progid_ = "MindRetrieve.ShellExtension.ContextMenu"
    _reg_desc_ = "MindRetrieve Shell Extension (context menu)"
    _reg_clsid_ = "{ABB05546-EB55-4433-B068-A57667706828}"

    _com_interfaces_ = [shell.IID_IShellExtInit, shell.IID_IContextMenu]
    _public_methods_ = IContextMenu_Methods + IShellExtInit_Methods

    def Initialize(self, folder, dataobj, hkey):
        print "Init", folder, dataobj, hkey
        self.dataobj = dataobj

    def QueryContextMenu(self, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags):
        print "QCM", hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags

        try:
            # Query the items clicked on
#            files = self.getFiles()
#            msg =  len(files) > 1 and '&Tag %s files' % len(files) or '&Tag with MindRetrieve'
#            # TODO: we do not support tagging multiple files now
#            if not(files):
#                return
            msg = '&Tag with MindRetrieve'

            idCmd = idCmdFirst
            items = []
            if (uFlags & 0x000F) == shellcon.CMF_NORMAL: # Check == here, since CMF_NORMAL=0
                print "CMF_NORMAL..."
                items.append(msg)
            elif uFlags & shellcon.CMF_VERBSONLY:
                print "CMF_VERBSONLY..."
                items.append(msg)# + " - shortcut")
            elif uFlags & shellcon.CMF_EXPLORE:
                print "CMF_EXPLORE..."
                items.append(msg)# + " - normal file, right-click in Explorer")
            elif uFlags & shellcon.CMF_DEFAULTONLY:
                print "CMF_DEFAULTONLY...\r\n"
            else:
                print "** unknown flags", uFlags
            win32gui.InsertMenu(hMenu, indexMenu,
                                win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
                                0, None)
            indexMenu += 1
            for item in items:
                win32gui.InsertMenu(hMenu, indexMenu,
                                    win32con.MF_STRING|win32con.MF_BYPOSITION,
                                    idCmd, item)
                indexMenu += 1
                idCmd += 1

            win32gui.InsertMenu(hMenu, indexMenu,
                                win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
                                0, None)
            indexMenu += 1
            return idCmd-idCmdFirst # Must return number of menu items we added.

        except Exception, e:
            alertError(hwnd, e)
            raise


    def InvokeCommand(self, ci):
        mask, hwnd, verb, params, dir, nShow, hotkey, hicon = ci

        try:
            files = self.getFiles()
            if not files:
                return
            fname = files[0]

#            win32gui.MessageBox(hwnd, fname,  str(fname.__class__), win32con.MB_OK)

            fname = fname.encode('utf-8')
            file_url = urllib.pathname2url(fname)

    # 2005-12-20 Test urllib.pathname2url()
    #
    #>>> urllib.pathname2url(r'c:\tung\wäi')
    #'///C|/tung/w%84i'
    #>>> urllib.pathname2url(r'\tung\wäi')
    #'/tung/w%84i'
    #>>> urllib.pathname2url(r'tung\wäi')
    #'tung/w%84i'

            # prefer ':' as the drive separator rather than '|'
            if file_url.startswith('///') and file_url[4:5] == '|':
                file_url = file_url.replace('|',':',1)

            if file_url.startswith('//'):
                file_url = 'file:' + file_url
            elif file_url.startswith('/'):
                file_url = 'file://' + file_url
            else:
                # fname is a relative filename? Should not happen!
                file_url = 'file:///' + file_url

            url = getBaseURL() + '?url=' + urllib.quote(file_url)
            shell.ShellExecuteEx(fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
                                 lpFile=url,
                                 nShow=win32con.SW_NORMAL,
                                )
        except Exception, e:
            alertError(hwnd, e)
            raise


    def GetCommandString(self, cmd, typ):
        return "&Tag with MindRetrieve"


    def getFiles(self):
        format_etc = win32con.CF_HDROP, None, 1, -1, pythoncom.TYMED_HGLOBAL
        sm = self.dataobj.GetData(format_etc)
        num_files = shell.DragQueryFile(sm.data_handle, -1)
        files = [shell.DragQueryFile(sm.data_handle, i) for i in range(num_files)]
        return files


def getConfigPath():
    """ get the DLL path from registry """
    import _winreg

    # _winreg.QueryValue() may throw WindowsError

    # COM server registration in deployed environment
    # e.g. HKEY_CLASSES_ROOT\CLSID\{ABB05546-EB55-4433-B068-A57667706828}\InprocServer32
    #       =c:\Program Files\MindRetrieve\context_menu.dll
    subkey = 'CLSID\\%s\\InprocServer32' % ShellExtension._reg_clsid_
    path = _winreg.QueryValue(_winreg.HKEY_CLASSES_ROOT, subkey)
    head, tail = os.path.split(path)
    # quick check if this is in deployed environment
    if os.path.isabs(head):
        return head

    # Otherwise assume in development environment
    # e.g. HKEY_CLASSES_ROOT\CLSID\{ABB05546-EB55-4433-B068-A57667706828}\PythonCOMPath
    #       =g:\bin\py_repos\mindretrieve\trunk\minds\weblib\win32
    subkey = 'CLSID\\%s\\PythonCOMPath' % ShellExtension._reg_clsid_
    path = _winreg.QueryValue(_winreg.HKEY_CLASSES_ROOT, subkey)
    idx = path.lower().rfind('minds')   # truncate trailing 'minds\weblib\win32'
    if idx > 0:
        path = path[:idx-1]
    return path



def getHTTPAdminPort():
    """ get HTTP.admin_port from config.ini """
    pathname = os.path.join(getConfigPath(), 'config.ini')
    cp = ConfigParser.ConfigParser()
    cp.read(pathname)
    admin_port = cp.getint('http','admin_port')
    return admin_port


def getBaseURL():
    """ get the base URL """
    port = getHTTPAdminPort()
    return 'http://localhost:%s/weblib/_' % port


def DllRegisterServer():
    import _winreg
    for typ in TYPES:
        # e.g. HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\MindRetrieve
        key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT, "%s\\shellex" % typ)
        subkey = _winreg.CreateKey(key, "ContextMenuHandlers")
        subkey2 = _winreg.CreateKey(subkey, SUBKEY)
        _winreg.SetValueEx(subkey2, None, 0, _winreg.REG_SZ, ShellExtension._reg_clsid_)
    print ShellExtension._reg_desc_, "registration complete."


def DllUnregisterServer():
    import _winreg
    for typ in TYPES:
        try:
            # e.g. HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\MindRetrieve
            key = _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT, "%s\\shellex\\ContextMenuHandlers\\%s" % (typ, SUBKEY))
        except WindowsError, details:
            import errno
            if details.errno != errno.ENOENT:
                raise
    print ShellExtension._reg_desc_, "unregistration complete."


def main(argv):
    # assume argv == sys.argv
    from win32com.server import register
    register.UseCommandLine(ShellExtension,
                   finalize_register = DllRegisterServer,
                   finalize_unregister = DllUnregisterServer)


def test(argv):
    """ adhoc tests """
    print 'URL:', getBaseURL()


if __name__=='__main__':
    import sys
    if '-t' not in sys.argv:
        main(sys.argv)
    else:
        test(sys.argv)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

憧憬巴黎街头的黎明 2024-09-14 00:32:36

根据有关错误 R6034 的文档,这意味着您加载 C 运行时库是错误的,因为您缺少“清单”。根据此线程,看来所需的方法只是:

我发现如果我制作一个清单文件
并复制内容
python.exe.manifest 一切都是
工作正常

(无法验证这是真的,因为我仍然没有可用的 Windows - 我现在拥有一台便宜的翻新 Windows 机器,得到它只是为了尝试帮助更多人解决此类问题,但找不到防病毒磁盘如果没有的话,我当然无法安全地上网)。

py2exe 的教程 涵盖了捆绑运行时库并为其制作清单的问题,并且比上面引用的简短解释更详细。

Per the docs about error R6034, it means you're loading the C runtime libraries wrong because you're missing a "manifest". Per this thread, it seems the needed approach is just:

i found that if i make a manifest file
and copy the content of
python.exe.manifest everything is
working correctly

(can't verify that this is true as I still have no working Windows -- I now do own a cheap refurb Windows machine, got it just to try and help more with such problems, but can't find the antivirus disk and without one of course I can't safely go online).

py2exe's tutorial covers the issues of bundling the runtime libraries and making a manifest for that, and goes in more details than the above-quoted short explanation.

宛菡 2024-09-14 00:32:36

我看到一个潜在的问题。您将 view 指定为包名称和模块名称。这很令人困惑,也不推荐。至少为了获得帮助,请将包重命名为 view_p (或更具描述性的名称),以便我们可以引用其中一个。

现在:

modules = ['view_p.view']

并且

packages = ['view_p']

view.py 进入名为 view_p 的目录,并且在该目录中,还应该有一个 __init__.py

One potential problem I see. You're specifying view as both a package name and a module name. This is confusing as well as not recommended. At least for the purposes of getting help, rename the package to view_p (or something more descriptive) so we can reference one or another.

So now:

modules = ['view_p.view']

and

packages = ['view_p']

And view.py goes in a directory called view_p and in that directory, there should also be a __init__.py.

活泼老夫 2024-09-14 00:32:36

我看到的另一个潜在问题是您正在使用 pywin32 构建 COM 服务器,但您正在使用 py2exe 的“ctypes_com_server”参数。也许这是受支持的,但这些实现之间可能存在一些不兼容性,从而妨碍您的预期使用。

Another potential problem I see is you're using pywin32 to construct your COM server but you're using the "ctypes_com_server" parameter to py2exe. Maybe this is supported, but it's possible that there are some incompatibility across these implementations that prevents your intended usage.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文