2010-06-27 103 views
3

我想在Python中製作COM DLL。但我嘗試註冊到編譯的DLL有一個錯誤消息「運行時錯誤r6034」和「無法加載python dll」這個問題的解決方案是什麼?py2exe的COM 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="[email protected]_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) 

回答

2

the docs有關錯誤R6034,它意味着你加載C運行時庫錯誤因爲你錯過了一個「清單」。每this thread,似乎需要的辦法就是:

我發現,如果我做一個清單文件 和複製 python.exe.manifest一切的內容 正常工作

(無法驗證這是真的,因爲我仍然沒有工作的Windows - 我現在擁有一臺廉價的翻新Windows機器,只是爲了嘗試和幫助解決這些問題,但找不到防病毒磁盤當然我不能安全地上網)。

py2exe's tutorial涵蓋了綁定運行時庫併爲此製作清單的問題,並且比上述引用的簡短說明更詳細。

0

我看到一個潛在的問題。您將view指定爲包名稱和模塊名稱。這是令人困惑以及不推薦。至少出於獲得幫助的目的,將包重命名爲view_p(或更具描述性的內容),以便我們可以參考其中的一個或另一個。

所以現在:

modules = ['view_p.view'] 

packages = ['view_p'] 

而且view.py進去一個叫view_p目錄,並在該目錄中,也應該有一個__init__.py

0

我看到的另一個潛在的問題是你使用pywin32來構建你的COM服務器,但你使用「ctypes_com_server」參數py2exe。也許這是支持的,但可能會有一些不兼容的問題妨礙您的預期用法。