On 23/03/2012 3:54 AM, Jan Wedel wrote:
I've actually managed to patch the policy.py to allow multiple
typelibraries.

Instead of having a definition for interfaces, type library id,
version etc i've build this into one tuple. I've created a new
attribute that can have multiple of these tuples. The head of my
server class now looks like this:


class EttexOPCServer: _reg_progid_ = "Ettex.OPC.Automation"
_reg_desc_ = "ettex OPC DA Server" _reg_clsid_ =
"{13B51E8D-4BC2-4DED-8D4E-4614692F88E6}" _reg_catids_ = [
'{63D5F432-CFE4-11D1-B2C8-0060083BA1FB}' ]

_typelib_interfaces_ = [ ("{3B540B51-0378-4551-ADCC-EA9B104302BF}",
3, 0, 0, [ 'IOPCServer', 'IOPCItemProperties', ] ),
("{B28EEDB1-AC6F-11D1-84D5-00608CB8A7E9}", 1, 0, 0, [ 'IOPCCommon',
'IConnectionPointContainer' ] ), ] _reg_clsctx_ =
pythoncom.CLSCTX_LOCAL_SERVER

I had to patch three locations in policy.py so far and I would be
happy to send you my changes if you like.

That would be great - a patch on sourceforge would be best. However, it might be better to wait until we are sure it is working OK :)


However it still doesn't
work but I'm not sure if I have missed something in my patch or if it
is a general problem in my server code or a bug in the framework.

At least, the client successfully creates the object and tries to
call a method of the interface but I get the following debug output:

GetStatus() pythoncom error: Failed to call the universal dispatcher

Traceback (most recent call last): File "C:\Program Files
(x86)\Python\lib\site-packages\win32com\universal.py", line 195, in
dispatch WriteFromOutTuple(retVal, meth._gw_out_args, argPtr)
TypeError: The VARIANT type is unknown (0x4024). pythoncom error:
Unexpected gateway error

Traceback (most recent call last): File "C:\Program Files
(x86)\Python\lib\site-packages\win32com\universal.py", line 195, in
dispatch WriteFromOutTuple(retVal, meth._gw_out_args, argPtr)
TypeError: The VARIANT type is unknown (0x4024). GetErrorString
-2147467259 0 pythoncom error: Failed to call the universal
dispatcher

(...)

I've hat a lookat the definition of GetStatus. It requires a pointer
to a pointer of type "tagOPCSERVERSTATUS" which is a record
definition in the type library. But when I look at what has been
generated by makepy, the record map looks pretty empty to me:

RecordMap = { u'tagOPCITEMVQT':
'{00000000-0000-0000-0000-000000000000}', }

The type lib defines 10 records! I tried to import the typelib using
comtypes and get that generated (excerpt):

class tagOPCSERVERSTATUS(Structure): pass

# values for enumeration 'tagOPCSERVERSTATE' OPC_STATUS_RUNNING = 1
OPC_STATUS_FAILED = 2 OPC_STATUS_NOCONFIG = 3 OPC_STATUS_SUSPENDED =
4 OPC_STATUS_TEST = 5 OPC_STATUS_COMM_FAULT = 6 tagOPCSERVERSTATE =
c_int # enum tagOPCSERVERSTATUS._fields_ = [ ('ftStartTime',
_FILETIME), ('ftCurrentTime', _FILETIME), ('ftLastUpdateTime',
_FILETIME), ('dwServerState', tagOPCSERVERSTATE), ('dwGroupCount',
c_ulong), ('dwBandWidth', c_ulong), ('wMajorVersion', c_ushort),
('wMinorVersion', c_ushort), ('wBuildNumber', c_ushort),
('wReserved', c_ushort), ('szVendorInfo', WSTRING), ]

Is there a bug in makepy that prevents creating these records?

It would seem so :)

If
yes, can I fix it or can I manually change the generated file to
support the records?

I'm really not sure - you probably need to look at the existing Record tests. The "PyCOMTest" test object (which is in the source tree and needs you to build it using MSVC) has some structs for testing.


If not, how would I create and return such a
pointer of a pointer in pythoncom? Is comtypes compatible with
pythoncom so I could use the comtypes generated files?

Unfortunately there isn't any compatibility between the 2.

Cheers,

Mark

Thanks!

//Jan

----- Originalnachricht ----- Von: "Jan Wedel"<jan.we...@ettex.de>
Gesendet: Don, 3/22/2012 1:51pm An: mhamm...@skippinet.com.au Cc:
python-win32@python.org Betreff: Re: [python-win32] How to write a
COM Server implementing interfaces from type lib?

Hi Mark,

thanks for your reply.

That's E_FAIL which is pretty generic.  Doesn't sound like a
simple failure to QI for the correct interface.

Yeah. The client says something like "Unknown Error" which makes it
hard to tell what the problem actually is.

win32com should be able to do this given there is a tlb - see the
"pippo" samples.  Further, using the debug facilities and
win32traceutil, you should be able to see the creation of the
object, the QIs on the object and any methods actually called.  But
as mentioned, I doubt it is a QI failure.

Yeah, there is a type library (OPC DA). Actually there are even two
type libraries, each of them contains two Interface which my server
needs to implement.

I've had a look into policy.py and found that:

def _build_typeinfos_(self): # Can only ever be one for now. (...)

which means using _typelib_guid_ allows only one type lib, right? I
could try to patch your code or do you think there is a general
problem that would make it impossible having more than one typelib in
your framework?

Have you tried contacting the author of the object?

I am the author... I only use the 3rd party typelibs. I am writing
the server that must support the interfaces so that other 3rd party
clients can access the server component.

I can reproduce the error using python the COMView tool trying to
instanciate the Server. The problem is, that I don't see why. I've
enabled debugging mode when registering the server. When using one of
the 3rd party clients, rhe python trace collector shows the
following:

Object with win32trace dispatcher created (object=None) Entering
constructor in<PyOPCComServer.EttexOPCServer instance at
0x0213B058>._QueryInterface_ with unsupported IID
{00000003-0000-0000-C000-000000000046}
({00000003-0000-0000-C000-000000000046})
in<PyOPCComServer.EttexOPCServer instance at
0x0213B058>._QueryInterface_ with unsupported IID
{0000001B-0000-0000-C000-000000000046}
({0000001B-0000-0000-C000-000000000046})
in<PyOPCComServer.EttexOPCServer instance at
0x0213B058>._QueryInterface_ with unsupported IID
{00000018-0000-0000-C000-000000000046}
({00000018-0000-0000-C000-000000000046})
in<PyOPCComServer.EttexOPCServer instance at
0x0213B058>._QueryInterface_ with unsupported IID
{4C1E39E1-E3E3-4296-AA86-EC938D896E92}
({4C1E39E1-E3E3-4296-AA86-EC938D896E92})
in<PyOPCComServer.EttexOPCServer instance at
0x0213B058>._InvokeEx_-AddConnection(1, 0) [1,0,None] Connection
added. Active connections: 1 in<PyOPCComServer.EttexOPCServer
instance at 0x0213B058>._InvokeEx_-ReleaseConnection(1, 0, 1)
[1,0,None] Connection released. Active connections: 0

The QI calls are standard COM calls, not application specific
(AFAIK). You can see the "Entering constructor" message which is in
my python constructor of the server. Just for fun, I implemented the
IExternalConnection interface to see if the methods are called.
"Connection added. ..." is my output. But I can't see an further
requests that shows what the problem is. Are there any calls in
pythoncom that could fail and does not give debug output?

My pythoncom server starts like that:

class EttexOPCServer: _reg_progid_ = "Ettex.OPC.Automation"
_reg_desc_ = "ettex OPC DA Server" _reg_clsid_ =
"{13B51E8D-4BC2-4DED-8D4E-4614692F88E6}" _reg_catids_ = [
'{63D5F432-CFE4-11D1-B2C8-0060083BA1FB}' ] _com_interfaces_ = [
'{00000019-0000-0000-C000-000000000046}', # IExternalConnection (Is
it really mandatory?) '{39C13A4D-011E-11D0-9675-0020AFD8ADB3}', #
IOPCServer '{F31DFDE2-07B6-11D2-B2D8-0060083BA1FB}', # IOPCCommon
'{39C13A72-011E-11D0-9675-0020AFD8ADB3}', # IOPCItemProperties
'{B196B284-BAB4-101A-B69C-00AA00341D07}'  #
IConnectionPointContainer ] _typelib_guid_ =
"{3B540B51-0378-4551-ADCC-EA9B104302BF}" _typelib_version_ = (3, 0)
_reg_clsctx_ = pythoncom.CLSCTX_LOCAL_SERVER

_public_methods_ =  [ 'Connect', 'Disconnect', 'GetErrorString' ] ##
IExternalConnection methods _public_methods_ += [ 'AddConnection',
'ReleaseConnection' ]

################################################################# ##
COM Class Attributes
#################################################################
_public_attrs_ = [ 'ClientName', 'OPCGroups' ]

################################################################# ##
COM Class Read-Only Attributes
#################################################################
_readonly_attrs_ = [ 'OPCGroups' ]

I don't have all interface methods implemented at the time but I
guess that doesn't matter as long as not all type libs have been
loaded, does it?

If its not possible with pythoncom, is it possible with comtypes?
I've tried that as well with nearly the same result ("Unknown
error"):

# OPC Data Access 3.00 Type Library opc_da_tl =
comtypes.GUID("{3B540B51-0378-4551-ADCC-EA9B104302BF}") # OPC Common
1.10 Type Library opc_com_tl =
comtypes.GUID("{B28EEDB1-AC6F-11D1-84D5-00608CB8A7E9}")

GetModule((opc_da_tl, 3, 0)) GetModule((opc_com_tl, 1, 0))

import comtypes.gen.OPCDA as OpcDa import comtypes.gen.OPCCOMN as
OpcCommon

class EttexOPCServer2(OpcCommon.IOPCCommon,
OpcCommon.IConnectionPointContainer, OpcDa.IOPCServer,
OpcDa.IOPCItemProperties): _reg_progid_ = "Ettex.OPC.Automation2"
_reg_desc_ = "ettex OPC DA Server 2" _reg_novers_progid_ =
_reg_progid_ _reg_clsid_ = "{80A2B8F7-792E-43F4-95F8-CD6BB4B413AD}"
_reg_catids_ = [ '{63D5F432-CFE4-11D1-B2C8-0060083BA1FB}' ]
_reg_clsctx_ = comtypes.CLSCTX_LOCAL_SERVER _regcls_ =
comtypes.server.localserver.REGCLS_MULTIPLEUSE

_com_interfaces_ = [OpcCommon.IOPCCommon,
OpcCommon.IConnectionPointContainer, OpcDa.IOPCServer,
OpcDa.IOPCItemProperties]

I don't know what to do. Is there anything more I can do to debug to
find out WHAT exactly causes the error? Because as you can see, the
pythoncom debug output doesn't show this error that is returned by
the client.

Thanks a lot!

//Jan

----- Originalnachricht ----- Von: "Mark
Hammond"<skippy.hamm...@gmail.com> Gesendet: Don, 3/22/2012 12:29pm
An: "Jan Wedel"<jan.we...@ettex.de> Cc: python-win32@python.org
Betreff: Re: [python-win32] How to write a COM Server implementing
interfaces from type lib?

On 22/03/2012 2:53 AM, Jan Wedel wrote:
Hi,

I'm currently having trouble to write a COM-Server that has some
special requirements: - It needs to derive from IUnknown - It needs
to implement multiple interface from two different proprietary
typelibs (dlls) - It needs to implement a custom category

At first I started with pythoncom. I used the attribute
_reg_catids_ to specify the category and _com_interfaces_ to
specify the interfaces I want to implement. The client (proprietary
3rd party sw, no source) sees the server but throws some 0x80004005
error on CoCreateInstance.

That's E_FAIL which is pretty generic.  Doesn't sound like a simple
failure to QI for the correct interface.

win32com should be able to do this given there is a tlb - see the
"pippo" samples.  Further, using the debug facilities and
win32traceutil, you should be able to see the creation of the
object, the QIs on the object and any methods actually called.  But
as mentioned, I doubt it is a QI failure.

I was hoping that I can just tell the COM dispatcher, "yes, I have
these interface implemented" and implement the methods without
really having the interface classes available.

I read, that pythoncom can only create components that use
IDispatch so I guess the _com_interfaces_ idea won't work, will
it?

As above, you should be able to fully implement them so long as
makepy has been run.

Then I did some further research and found comtypes. I tried to
write a server stub again. I used GetModule to load the type
library containing the Interfaces, importing the generated
interface classes and let the main server class extend these
interfaces.

The first problem was, that comtypes did not support the
_reg_catids_ attribute or anything similar so I had to add the
Implemented Categories key manually to the registry. Then, I was
able to see the server through the client, which obviously filters
by categories, but it still shows the same error as before.

So, what is the correct/best way to implement a server that needs
to implement custom interfaces and categories? Or is it possible at
all using python?

The fact you get the same error there implies something else is
going wrong, but it is impossible to guess what.  Have you tried
contacting the author of the object?

Mark


Thanks!

//Jan



_______________________________________________ python-win32
mailing list python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32

_______________________________________________ python-win32 mailing
list python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32

_______________________________________________
python-win32 mailing list
python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32

Reply via email to