J'ai frappé un mur avec celui-ci. J'ai besoin de créer un serveur com basé sur python, l'empaqueter sous Windows Exe et le déployer sur Windows. Il doit avoir une interface "complète" - parce que le consommateur a besoin d'une identité et d'une interface spécifique pour fonctionner. Maintenant, j'ai créé le serveur com et l'ai fait fonctionner sous l'interpréteur et il fonctionne parfaitement avec mon client picky. Cependant, lors de l'empaquetage en tant qu'exe - c'est un localserver - j'obtiens une erreur dans le journal lorsque le système essaie de l'instancier (même à partir d'un script vbs). Alors, voici tout. J'ai cherché haut et bas dans l'itnernet et cela ressemble à un problème d'importation mais je ne sais pas comment importer mon propre objet python pour que le localserver puisse l'utiliser.Python Com Server impossible de créer l'instance lorsqu'il est enveloppé avec py2exe - l'objet d'erreur n'a pas d'attribut
Ceci est python 2.7 avec les extensions pywin32 installées.
Alors d'abord - le IDL j'ai créé pour le serveur:
imtg.idl
// This file will be processed by the MIDL tool to
// produce the type library (imtg.tlb) and marshalling code.
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(4fafbb23-6a38-4613-b93b-68ea66c67043),
dual,
helpstring("IImtGroupApp Interface"),
pointer_default(unique)
]
interface IImtGroupApp : IDispatch
{
[id(1), helpstring("method EchoString")] HRESULT EchoString([in] BSTR in1, [out, retval] BSTR *vals);
[id(2), helpstring("method AddNumbers")] HRESULT AddNumbers([in] long in1, [in] long in2, [out, retval] long *vali);
};
[
uuid(d665e9d0-71a9-4e23-a1b4-abe3376d5c58),
version(1.0),
helpstring("ImtGroup 1.0 Type Library")
]
library IMTGROUPLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
importlib("msado15.dll");
[
uuid(ced66424-93fb-4307-9062-7bee76d3d8eb),
helpstring("ImtGroupApp Class")
]
coclass ImtGroupApp {
[default] interface IImtGroupApp;
};
};
Suivant le code Python - maintenant cela devient un peu difficile parce que quand je distribuerai cela, je ne veux pas pour créer le .tlb - donc je ne distribue pas le .idy - assurez-vous juste que vous avez le .tbl pour vous inscrire. Utilisez une invite cmd admin en cas de besoin.
imtg_server.py
import sys, os
import pythoncom
import win32com
import winerror
# importers check was old py2exe current uses frozen
if hasattr(sys, 'frozen'):
# we are running as py2exe-packed executable
print "is an exe"
pythoncom.frozen = 1
else:
print "not an exe"
class CImtg:
_reg_clsctx_ = pythoncom.CLSCTX_LOCAL_SERVER
#
# COM declarations
#
_reg_clsid_ = "{24c0e3fe-58e7-4485-87dc-9f9e823b85e1}"
_reg_desc_ = "IMTGroup Python test object"
_reg_progid_ = "ImtGroup.Test"
if hasattr(sys, 'frozen'):
# In the py2exe-packed version, specify the module.class
# to use. In the python script version, python is able
# to figure it out itself.
_reg_class_spec_ = "__main__.CImtg"
print "set reg_class_spec"
print _reg_class_spec_
###
### Link to typelib - uuid matches uuid for type library in idl file
_typelib_guid_ = '{d665e9d0-71a9-4e23-a1b4-abe3376d5c58}'
_typelib_version_ = 1, 0
_com_interfaces_ = ['IImtGroupApp']
def __init__(self):
### initialize something here if necessary
### The item below is not used in this example
self.MyProp1 = 10
def EchoString(self,in1):
return "Echoing " + in1
def AddNumbers(self, in1, in2):
return in1 + in2
def BuildTypelib():
from distutils.dep_util import newer
this_dir = os.path.dirname(__file__)
idl = os.path.abspath(os.path.join(this_dir, "imtg.idl"))
tlb=os.path.splitext(idl)[0] + '.tlb'
if os.path.isfile(idl):
# test for idl - if no idl don't create tlb assume its there
# Comment below for building exe as we will have type library
if newer(idl, tlb):
print "Compiling %s" % (idl,)
rc = os.system ('midl "%s"' % (idl,))
if rc:
raise RuntimeError("Compiling MIDL failed!")
# Can't work out how to prevent MIDL from generating the stubs.
# just nuke them
for fname in "dlldata.c imtg_i.c imtg_p.c imtg.h".split():
os.remove(os.path.join(this_dir, fname))
print "Registering %s" % (tlb,)
tli=pythoncom.LoadTypeLib(tlb)
pythoncom.RegisterTypeLib(tli,tlb)
def UnregisterTypelib():
k = CImtg
try:
pythoncom.UnRegisterTypeLib(k._typelib_guid_,
k._typelib_version_[0],
k._typelib_version_[1],
0,
pythoncom.SYS_WIN32)
print "Unregistered typelib"
except pythoncom.error, details:
if details[0]==winerror.TYPE_E_REGISTRYACCESS:
pass
else:
raise
if __name__=='__main__':
print "checking frozen"
if hasattr(sys, 'frozen'):
# running as packed executable
if '--unregister' in sys.argv or '--register' in sys.argv:
if '--unregister' in sys.argv:
# Unregister the type-libraries.
UnregisterTypelib()
import win32com.server.register
win32com.server.register.UseCommandLine(CImtg)
else:
# Build and register the type-libraries.
BuildTypelib()
import win32com.server.register
win32com.server.register.UseCommandLine(CImtg)
else:
import win32com.server
from win32com.server import localserver
print "starting the server"
localserver.main()
else:
if '--unregister' in sys.argv:
# Unregister the type-libraries.
UnregisterTypelib()
import win32com.server.register
win32com.server.register.UseCommandLine(CImtg)
else:
if '--register' in sys.argv:
# Build and register the type-libraries.
BuildTypelib()
import win32com.server.register
win32com.server.register.UseCommandLine(CImtg)
Suivant la configuration de py2exe
je devais ajouter l'importation funky de la modulefinder parce win32com.shell n'a pas été inclus dans l'exécutable emballé
setup_imtg .py
# This setup script builds a single-file Python inprocess COM server.
#
import modulefinder
import win32com, sys
for p in win32com.__path__[1:]:
modulefinder.AddPackagePath("win32com",p)
for extra in ["win32com.shell"]:
__import__(extra)
m = sys.modules[extra]
for p in m.__path__[1:]:
modulefinder.AddPackagePath(extra, p)
from distutils.core import setup
import py2exe
import sys
# If run without args, build executables, in quiet mode.
if len(sys.argv) == 1:
sys.argv.append("py2exe")
sys.argv.append("-q")
class Target:
def __init__(self, **kw):
self.__dict__.update(kw)
# for the versioninfo resources
self.name = "IMTG Server"
################################################################
# pywin32 COM pulls in a lot of stuff which we don't want or need.
CImtg = Target(
description = "Sample COM server",
# what to build. For COM servers, the module name (not the
# filename) must be specified!
modules = ["imtg_server"],
# we only want the inproc server.
)
excludes = ["pywin", "pywin.debugger", "pywin.debugger.dbgcon",
"pywin.dialogs", "pywin.dialogs.list"]
options = {
"bundle_files": 1, # create singlefile exe
"compressed": 1, # compress the library archive
"excludes": excludes,
"dll_excludes": ["w9xpopen.exe"] # we don't need this
}
setup(
options = {"py2exe": options},
zipfile = None, # append zip-archive to the executable.
com_server = [CImtg]
)
Lorsque vous exécutez l'EXE généré un registre avec
imtg_server --register
mais vous ne verrez pas abou sortie
--unregister désinscrit
Vous pouvez utiliser ce fichier vbs pour le tester.
t.vbs
dim MD
set MD = CreateObject("ImtGroup.Test")
dim response
response = MD.EchoString("Really")
MsgBox(response)
Lorsque vous exécutez il y aura un .log créé qui ressemble à ceci:
pythoncom error: ERROR: server.policy could not create an instance.
Traceback (most recent call last):
File "win32com\server\policy.pyc", line 136, in CreateInstance
File "win32com\server\policy.pyc", line 194, in _CreateInstance_
File "win32com\server\policy.pyc", line 727, in call_func
File "win32com\server\policy.pyc", line 717, in resolve_func
AttributeError: 'module' object has no attribute 'CImtg'
pythoncom error: Unexpected gateway error
Traceback (most recent call last):
File "win32com\server\policy.pyc", line 136, in CreateInstance
File "win32com\server\policy.pyc", line 194, in _CreateInstance_
File "win32com\server\policy.pyc", line 727, in call_func
File "win32com\server\policy.pyc", line 717, in resolve_func
AttributeError: 'module' object has no attribute 'CImtg'
pythoncom error: CPyFactory::CreateInstance failed to create instance. (80004005)
Alors, que j'ai besoin est de contourner cette erreur. Cette classe est certainement dans mon objet. Je suis préoccupé que la valeur que j'ai spécifié dans mon serveur comme:
_reg_class_spec_ = "__main__.CImtg"
Est incorrect. Le principal peut se référer à l'exe enveloppé et pas mon propre serveur qui n'a pas de principal spécifié. J'ai essayé de créer le principal aussi sans meilleurs résultats. Je ne sais pas comment py2exe représente les classes. J'ai essayé d'utiliser mon nom de fichier imtg_server.CImtg et cela échoue avec le module non trouvé. J'ai essayé juste CImtg et cela échoue. J'ai essayé d'utiliser des variantes de win32com et de pythoncom - mais ça ne marche tout simplement pas.Ce que j'ai semble "juste" alors peut-être que j'ai besoin d'un tag supplémentaire reg ou quelque chose? Toute aide est grandement appréciée. Je vous remercie.
Le fait que la configuration de py2exe utiliser CImtg pour le nom du serveur com est hors de propos. J'ai essayé foo avec le même résultat. – user2709214