comtypes 1.4.8__zip → 1.4.10__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {comtypes-1.4.8 → comtypes-1.4.10}/CHANGES.txt +40 -0
- {comtypes-1.4.8/comtypes.egg-info → comtypes-1.4.10}/PKG-INFO +4 -3
- {comtypes-1.4.8 → comtypes-1.4.10}/README.md +1 -1
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/GUID.py +38 -16
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/__init__.py +36 -16
- comtypes-1.4.10/comtypes/_comobject.py +562 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/_memberspec.py +93 -13
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/_meta.py +1 -0
- comtypes-1.4.10/comtypes/_post_coinit/_cominterface_meta_patcher.py +152 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/_post_coinit/bstr.py +12 -5
- comtypes-1.4.8/comtypes/_py_instance_method.py → comtypes-1.4.10/comtypes/_post_coinit/instancemethod.py +1 -2
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/_post_coinit/misc.py +60 -25
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/_post_coinit/unknwn.py +26 -176
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/_safearray.py +3 -4
- comtypes-1.4.10/comtypes/_vtbl.py +448 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/automation.py +46 -49
- comtypes-1.4.10/comtypes/client/__init__.py +42 -0
- comtypes-1.4.10/comtypes/client/_activeobj.py +46 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/client/_code_cache.py +10 -5
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/client/_constants.py +1 -1
- comtypes-1.4.10/comtypes/client/_create.py +147 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/client/_events.py +58 -13
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/client/_generate.py +7 -11
- comtypes-1.4.10/comtypes/client/_managing.py +114 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/client/dynamic.py +2 -3
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/client/lazybind.py +12 -13
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/connectionpoints.py +2 -1
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/errorinfo.py +22 -9
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/git.py +5 -5
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/hints.pyi +7 -15
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/logutil.py +15 -3
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/messageloop.py +1 -1
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/persist.py +3 -5
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/safearray.py +17 -5
- comtypes-1.4.10/comtypes/server/__init__.py +104 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/server/automation.py +1 -2
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/server/connectionpoints.py +5 -5
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/server/inprocserver.py +25 -17
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/server/localserver.py +49 -19
- comtypes-1.4.10/comtypes/server/register.py +478 -0
- comtypes-1.4.10/comtypes/server/w_getopt.py +48 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/shelllink.py +16 -33
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/stream.py +7 -4
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/TestComServer.py +6 -7
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/TestDispServer.py +4 -2
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/__init__.py +10 -12
- comtypes-1.4.10/comtypes/test/find_memleak.py +72 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/runtests.py +1 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/setup.py +2 -1
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_BSTR.py +10 -23
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_GUID.py +1 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_QueryService.py +1 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_agilent.py +4 -3
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_avmc.py +1 -1
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_basic.py +12 -6
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_casesensitivity.py +3 -5
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_clear_cache.py +1 -1
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_client.py +2 -2
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_client_dynamic.py +2 -2
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_client_regenerate_modules.py +2 -2
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_collections.py +4 -4
- comtypes-1.4.10/comtypes/test/test_comobject.py +146 -0
- comtypes-1.4.10/comtypes/test/test_comserver.py +349 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_createwrappers.py +2 -4
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_dispifc_records.py +1 -1
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_dispifc_safearrays.py +1 -1
- comtypes-1.4.10/comtypes/test/test_dispinterface.py +153 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_dyndispatch.py +1 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_excel.py +22 -12
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_findgendir.py +1 -2
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_getactiveobj.py +4 -4
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_ie.py +19 -9
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_ienum.py +2 -2
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_imfattributes.py +13 -3
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_inout_args.py +8 -5
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_midl_safearray_create.py +14 -4
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_monikers.py +23 -9
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_msscript.py +2 -1
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_npsupport.py +4 -4
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_outparam.py +37 -14
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_persist.py +2 -4
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_recordinfo.py +1 -1
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_safearray.py +1 -90
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_sapi.py +4 -1
- comtypes-1.4.10/comtypes/test/test_server.py +350 -0
- comtypes-1.4.10/comtypes/test/test_server_register.py +524 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_shelllink.py +2 -3
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_showevents.py +7 -17
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_storage.py +12 -6
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_stream.py +16 -5
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_subinterface.py +4 -2
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_typeannotator.py +1 -2
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_typeinfo.py +19 -7
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_urlhistory.py +7 -4
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_variant.py +3 -19
- comtypes-1.4.10/comtypes/test/test_w_getopt.py +29 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_win32com_interop.py +80 -36
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_wmi.py +0 -3
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_word.py +1 -1
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/tools/codegenerator/codegenerator.py +166 -440
- comtypes-1.4.10/comtypes/tools/codegenerator/comments.py +79 -0
- comtypes-1.4.10/comtypes/tools/codegenerator/heads.py +192 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/tools/codegenerator/helpers.py +11 -14
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/tools/codegenerator/namespaces.py +13 -5
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/tools/codegenerator/packing.py +4 -4
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/tools/codegenerator/typeannotator.py +19 -9
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/tools/tlbparser.py +22 -23
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/tools/typedesc.py +4 -8
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/tools/typedesc_base.py +2 -2
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/typeinfo.py +159 -63
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/viewobject.py +3 -9
- {comtypes-1.4.8 → comtypes-1.4.10/comtypes.egg-info}/PKG-INFO +4 -3
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes.egg-info/SOURCES.txt +11 -3
- {comtypes-1.4.8 → comtypes-1.4.10}/pyproject.toml +12 -19
- comtypes-1.4.8/comtypes/_comobject.py +0 -833
- comtypes-1.4.8/comtypes/_idl_stuff.py +0 -67
- comtypes-1.4.8/comtypes/client/__init__.py +0 -323
- comtypes-1.4.8/comtypes/server/__init__.py +0 -70
- comtypes-1.4.8/comtypes/server/register.py +0 -431
- comtypes-1.4.8/comtypes/server/w_getopt.py +0 -75
- comtypes-1.4.8/comtypes/test/find_memleak.py +0 -76
- comtypes-1.4.8/comtypes/test/test_comserver.py +0 -239
- comtypes-1.4.8/comtypes/test/test_dispinterface.py +0 -137
- comtypes-1.4.8/comtypes/test/test_propputref.py +0 -40
- comtypes-1.4.8/comtypes/test/test_server.py +0 -354
- {comtypes-1.4.8 → comtypes-1.4.10}/LICENSE.txt +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/MANIFEST.in +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/_npsupport.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/_post_coinit/__init__.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/_tlib_version_checker.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/clear_cache.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/hresult.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/patcher.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/TestComServer.idl +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/TestComServer.tlb +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/TestDispServer.idl +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/TestDispServer.tlb +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/mylib.idl +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/mylib.tlb +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/mytypelib.idl +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_DISPPARAMS.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_dict.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_jscript.js +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/test_pump_events.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/test/urlhist.tlb +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/tools/__init__.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/tools/codegenerator/__init__.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/tools/codegenerator/modulenamer.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes/util.py +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes.egg-info/dependency_links.txt +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes.egg-info/entry_points.txt +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/comtypes.egg-info/top_level.txt +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/setup.cfg +0 -0
- {comtypes-1.4.8 → comtypes-1.4.10}/setup.py +0 -0
|
@@ -1,431 +0,0 @@
|
|
|
1
|
-
"""comtypes.server.register - register and unregister a COM object.
|
|
2
|
-
|
|
3
|
-
Exports the UseCommandLine function. UseCommandLine is called with
|
|
4
|
-
the COM object classes that a module exposes. It parses the Windows
|
|
5
|
-
command line and takes the appropriate actions.
|
|
6
|
-
These command line options are supported:
|
|
7
|
-
|
|
8
|
-
/regserver - register the classes with COM.
|
|
9
|
-
/unregserver - unregister the classes with COM.
|
|
10
|
-
|
|
11
|
-
/nodebug - remove all logging configuration from the registry.
|
|
12
|
-
|
|
13
|
-
/l <name>=<level> - configure the logging level for the standard Python loggind module,
|
|
14
|
-
this option may be used several times.
|
|
15
|
-
|
|
16
|
-
/f <formatter> - specify the formatter string.
|
|
17
|
-
|
|
18
|
-
Note: Registering and unregistering the objects does remove logging
|
|
19
|
-
entries. Configuring the logging does not change other registry
|
|
20
|
-
entries, so it is possible to freeze a comobject with py2exe, register
|
|
21
|
-
it, then configure logging afterwards to debug it, and delete the
|
|
22
|
-
logging config afterwards.
|
|
23
|
-
|
|
24
|
-
Sample usage:
|
|
25
|
-
|
|
26
|
-
Register the COM object:
|
|
27
|
-
|
|
28
|
-
python mycomobj.py /regserver
|
|
29
|
-
|
|
30
|
-
Configure logging info:
|
|
31
|
-
|
|
32
|
-
python mycomobj.py /l comtypes=INFO /l comtypes.server=DEBUG /f %(message)s
|
|
33
|
-
|
|
34
|
-
Now, debug the object, and when done delete logging info:
|
|
35
|
-
|
|
36
|
-
python mycomobj.py /nodebug
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
import sys
|
|
40
|
-
import os
|
|
41
|
-
import winreg
|
|
42
|
-
import logging
|
|
43
|
-
|
|
44
|
-
import comtypes
|
|
45
|
-
from comtypes.typeinfo import LoadTypeLibEx, UnRegisterTypeLib, REGKIND_REGISTER
|
|
46
|
-
from comtypes.hresult import *
|
|
47
|
-
from comtypes.server import w_getopt
|
|
48
|
-
import comtypes.server.inprocserver
|
|
49
|
-
from ctypes import windll, c_ulong, c_wchar_p, WinError, sizeof, create_string_buffer
|
|
50
|
-
|
|
51
|
-
_debug = logging.getLogger(__name__).debug
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def get_winerror(exception):
|
|
55
|
-
try:
|
|
56
|
-
return exception.winerror
|
|
57
|
-
except AttributeError:
|
|
58
|
-
return exception.errno
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# a SHDeleteKey function, will remove a registry key with all subkeys.
|
|
62
|
-
def _non_zero(retval, func, args):
|
|
63
|
-
if retval:
|
|
64
|
-
raise WinError(retval)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
SHDeleteKey = windll.shlwapi.SHDeleteKeyW
|
|
68
|
-
SHDeleteKey.errcheck = _non_zero
|
|
69
|
-
SHDeleteKey.argtypes = c_ulong, c_wchar_p
|
|
70
|
-
|
|
71
|
-
Set = set
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
_KEYS = {
|
|
75
|
-
winreg.HKEY_CLASSES_ROOT: "HKCR",
|
|
76
|
-
winreg.HKEY_LOCAL_MACHINE: "HKLM",
|
|
77
|
-
winreg.HKEY_CURRENT_USER: "HKCU",
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def _explain(hkey):
|
|
82
|
-
return _KEYS.get(hkey, hkey)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
class Registrar(object):
|
|
86
|
-
"""COM class registration.
|
|
87
|
-
|
|
88
|
-
The COM class can override what this does by implementing
|
|
89
|
-
_register and/or _unregister class methods. These methods will be
|
|
90
|
-
called with the calling instance of Registrar, and so can call the
|
|
91
|
-
Registrars _register and _unregister methods which do the actual
|
|
92
|
-
work.
|
|
93
|
-
"""
|
|
94
|
-
|
|
95
|
-
def nodebug(self, cls):
|
|
96
|
-
"""Delete logging entries from the registry."""
|
|
97
|
-
clsid = cls._reg_clsid_
|
|
98
|
-
try:
|
|
99
|
-
_debug(
|
|
100
|
-
'DeleteKey( %s\\CLSID\\%s\\Logging"'
|
|
101
|
-
% (_explain(winreg.HKEY_CLASSES_ROOT), clsid)
|
|
102
|
-
)
|
|
103
|
-
hkey = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s" % clsid)
|
|
104
|
-
winreg.DeleteKey(hkey, "Logging")
|
|
105
|
-
except WindowsError as detail:
|
|
106
|
-
if get_winerror(detail) != 2:
|
|
107
|
-
raise
|
|
108
|
-
|
|
109
|
-
def debug(self, cls, levels, format):
|
|
110
|
-
"""Write entries in the registry to setup logging for this clsid."""
|
|
111
|
-
# handlers
|
|
112
|
-
# format
|
|
113
|
-
clsid = cls._reg_clsid_
|
|
114
|
-
_debug(
|
|
115
|
-
'CreateKey( %s\\CLSID\\%s\\Logging"'
|
|
116
|
-
% (_explain(winreg.HKEY_CLASSES_ROOT), clsid)
|
|
117
|
-
)
|
|
118
|
-
hkey = winreg.CreateKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s\Logging" % clsid)
|
|
119
|
-
for item in levels:
|
|
120
|
-
name, value = item.split("=")
|
|
121
|
-
v = getattr(logging, value)
|
|
122
|
-
assert isinstance(v, int)
|
|
123
|
-
_debug("SetValueEx(levels, %s)" % levels)
|
|
124
|
-
winreg.SetValueEx(hkey, "levels", None, winreg.REG_MULTI_SZ, levels)
|
|
125
|
-
if format:
|
|
126
|
-
_debug("SetValueEx(format, %s)" % format)
|
|
127
|
-
winreg.SetValueEx(hkey, "format", None, winreg.REG_SZ, format)
|
|
128
|
-
else:
|
|
129
|
-
_debug("DeleteValue(format)")
|
|
130
|
-
try:
|
|
131
|
-
winreg.DeleteValue(hkey, "format")
|
|
132
|
-
except WindowsError as detail:
|
|
133
|
-
if get_winerror(detail) != 2:
|
|
134
|
-
raise
|
|
135
|
-
|
|
136
|
-
def register(self, cls, executable=None):
|
|
137
|
-
"""Register the COM server class."""
|
|
138
|
-
# First, we unregister the object with force=True, to force removal
|
|
139
|
-
# of all registry entries, even if we would not write them.
|
|
140
|
-
# Second, we create new entries.
|
|
141
|
-
# It seems ATL does the same.
|
|
142
|
-
mth = getattr(cls, "_register", None)
|
|
143
|
-
if mth is not None:
|
|
144
|
-
mth(self)
|
|
145
|
-
else:
|
|
146
|
-
self._unregister(cls, force=True)
|
|
147
|
-
self._register(cls, executable)
|
|
148
|
-
|
|
149
|
-
def _register(self, cls, executable=None):
|
|
150
|
-
table = self._registry_entries(cls)
|
|
151
|
-
table.sort()
|
|
152
|
-
_debug("Registering %s", cls)
|
|
153
|
-
for hkey, subkey, valuename, value in table:
|
|
154
|
-
_debug("[%s\\%s]", _explain(hkey), subkey)
|
|
155
|
-
_debug('%s="%s"', valuename or "@", value)
|
|
156
|
-
k = winreg.CreateKey(hkey, subkey)
|
|
157
|
-
winreg.SetValueEx(k, valuename, None, winreg.REG_SZ, str(value))
|
|
158
|
-
|
|
159
|
-
tlib = getattr(cls, "_reg_typelib_", None)
|
|
160
|
-
if tlib is not None:
|
|
161
|
-
if hasattr(sys, "frozendllhandle"):
|
|
162
|
-
dll = self._get_serverdll()
|
|
163
|
-
_debug("LoadTypeLibEx(%s, REGKIND_REGISTER)", dll)
|
|
164
|
-
LoadTypeLibEx(dll, REGKIND_REGISTER)
|
|
165
|
-
else:
|
|
166
|
-
if executable:
|
|
167
|
-
path = executable
|
|
168
|
-
elif hasattr(sys, "frozen"):
|
|
169
|
-
path = sys.executable
|
|
170
|
-
else:
|
|
171
|
-
path = cls._typelib_path_
|
|
172
|
-
_debug("LoadTypeLibEx(%s, REGKIND_REGISTER)", path)
|
|
173
|
-
LoadTypeLibEx(path, REGKIND_REGISTER)
|
|
174
|
-
_debug("Done")
|
|
175
|
-
|
|
176
|
-
def unregister(self, cls, force=False):
|
|
177
|
-
"""Unregister the COM server class."""
|
|
178
|
-
mth = getattr(cls, "_unregister", None)
|
|
179
|
-
if mth is not None:
|
|
180
|
-
mth(self)
|
|
181
|
-
else:
|
|
182
|
-
self._unregister(cls, force=force)
|
|
183
|
-
|
|
184
|
-
def _unregister(self, cls, force=False):
|
|
185
|
-
# If force==False, we only remove those entries that we
|
|
186
|
-
# actually would have written. It seems ATL does the same.
|
|
187
|
-
table = [t[:2] for t in self._registry_entries(cls)]
|
|
188
|
-
# only unique entries
|
|
189
|
-
table = list(set(table))
|
|
190
|
-
table.sort()
|
|
191
|
-
table.reverse()
|
|
192
|
-
_debug("Unregister %s", cls)
|
|
193
|
-
for hkey, subkey in table:
|
|
194
|
-
try:
|
|
195
|
-
if force:
|
|
196
|
-
_debug("SHDeleteKey %s\\%s", _explain(hkey), subkey)
|
|
197
|
-
SHDeleteKey(hkey, subkey)
|
|
198
|
-
else:
|
|
199
|
-
_debug("DeleteKey %s\\%s", _explain(hkey), subkey)
|
|
200
|
-
winreg.DeleteKey(hkey, subkey)
|
|
201
|
-
except WindowsError as detail:
|
|
202
|
-
if get_winerror(detail) != 2:
|
|
203
|
-
raise
|
|
204
|
-
tlib = getattr(cls, "_reg_typelib_", None)
|
|
205
|
-
if tlib is not None:
|
|
206
|
-
try:
|
|
207
|
-
_debug("UnRegisterTypeLib(%s, %s, %s)", *tlib)
|
|
208
|
-
UnRegisterTypeLib(*tlib)
|
|
209
|
-
except WindowsError as detail:
|
|
210
|
-
if not get_winerror(detail) in (
|
|
211
|
-
TYPE_E_REGISTRYACCESS,
|
|
212
|
-
TYPE_E_CANTLOADLIBRARY,
|
|
213
|
-
):
|
|
214
|
-
raise
|
|
215
|
-
_debug("Done")
|
|
216
|
-
|
|
217
|
-
def _get_serverdll(self):
|
|
218
|
-
"""Return the pathname of the dll hosting the COM object."""
|
|
219
|
-
handle = getattr(sys, "frozendllhandle", None)
|
|
220
|
-
if handle is not None:
|
|
221
|
-
buf = create_string_buffer(260)
|
|
222
|
-
windll.kernel32.GetModuleFileNameA(handle, buf, sizeof(buf))
|
|
223
|
-
return buf[:]
|
|
224
|
-
import _ctypes
|
|
225
|
-
|
|
226
|
-
return _ctypes.__file__
|
|
227
|
-
|
|
228
|
-
def _get_full_classname(self, cls):
|
|
229
|
-
"""Return <modulename>.<classname> for 'cls'."""
|
|
230
|
-
modname = cls.__module__
|
|
231
|
-
if modname == "__main__":
|
|
232
|
-
modname = os.path.splitext(os.path.basename(sys.argv[0]))[0]
|
|
233
|
-
return "%s.%s" % (modname, cls.__name__)
|
|
234
|
-
|
|
235
|
-
def _get_pythonpath(self, cls):
|
|
236
|
-
"""Return the filesystem path of the module containing 'cls'."""
|
|
237
|
-
modname = cls.__module__
|
|
238
|
-
dirname = os.path.dirname(sys.modules[modname].__file__)
|
|
239
|
-
return os.path.abspath(dirname)
|
|
240
|
-
|
|
241
|
-
def _registry_entries(self, cls):
|
|
242
|
-
"""Return a sequence of tuples containing registry entries.
|
|
243
|
-
|
|
244
|
-
The tuples must be (key, subkey, name, value).
|
|
245
|
-
|
|
246
|
-
Required entries:
|
|
247
|
-
=================
|
|
248
|
-
_reg_clsid_ - a string or GUID instance
|
|
249
|
-
_reg_clsctx_ - server type(s) to register
|
|
250
|
-
|
|
251
|
-
Optional entries:
|
|
252
|
-
=================
|
|
253
|
-
_reg_desc_ - a string
|
|
254
|
-
_reg_progid_ - a string naming the progid, typically 'MyServer.MyObject.1'
|
|
255
|
-
_reg_novers_progid_ - version independend progid, typically 'MyServer.MyObject'
|
|
256
|
-
_reg_typelib_ - an tuple (libid, majorversion, minorversion) specifying a typelib.
|
|
257
|
-
_reg_threading_ - a string specifying the threading model
|
|
258
|
-
|
|
259
|
-
Note that the first part of the progid string is typically the
|
|
260
|
-
IDL library name of the type library containing the coclass.
|
|
261
|
-
"""
|
|
262
|
-
HKCR = winreg.HKEY_CLASSES_ROOT
|
|
263
|
-
|
|
264
|
-
# table format: rootkey, subkey, valuename, value
|
|
265
|
-
table = []
|
|
266
|
-
append = lambda *args: table.append(args)
|
|
267
|
-
|
|
268
|
-
# basic entry - names the comobject
|
|
269
|
-
reg_clsid = str(
|
|
270
|
-
cls._reg_clsid_
|
|
271
|
-
) # that's the only required attribute for registration
|
|
272
|
-
reg_desc = getattr(cls, "_reg_desc_", "")
|
|
273
|
-
if not reg_desc:
|
|
274
|
-
# Simple minded algorithm to construct a description from
|
|
275
|
-
# the progid:
|
|
276
|
-
reg_desc = getattr(cls, "_reg_novers_progid_", "") or getattr(
|
|
277
|
-
cls, "_reg_progid_", ""
|
|
278
|
-
)
|
|
279
|
-
if reg_desc:
|
|
280
|
-
reg_desc = reg_desc.replace(".", " ")
|
|
281
|
-
append(HKCR, "CLSID\\%s" % reg_clsid, "", reg_desc)
|
|
282
|
-
|
|
283
|
-
reg_progid = getattr(cls, "_reg_progid_", None)
|
|
284
|
-
if reg_progid:
|
|
285
|
-
# for ProgIDFromCLSID:
|
|
286
|
-
append(HKCR, "CLSID\\%s\\ProgID" % reg_clsid, "", reg_progid) # 1
|
|
287
|
-
|
|
288
|
-
# for CLSIDFromProgID
|
|
289
|
-
if reg_desc:
|
|
290
|
-
append(HKCR, reg_progid, "", reg_desc) # 2
|
|
291
|
-
append(HKCR, "%s\\CLSID" % reg_progid, "", reg_clsid) # 3
|
|
292
|
-
|
|
293
|
-
reg_novers_progid = getattr(cls, "_reg_novers_progid_", None)
|
|
294
|
-
if reg_novers_progid:
|
|
295
|
-
append(
|
|
296
|
-
HKCR,
|
|
297
|
-
"CLSID\\%s\\VersionIndependentProgID" % reg_clsid, # 1a
|
|
298
|
-
"",
|
|
299
|
-
reg_novers_progid,
|
|
300
|
-
)
|
|
301
|
-
if reg_desc:
|
|
302
|
-
append(HKCR, reg_novers_progid, "", reg_desc) # 2a
|
|
303
|
-
append(HKCR, "%s\\CurVer" % reg_novers_progid, "", reg_progid) #
|
|
304
|
-
append(HKCR, "%s\\CLSID" % reg_novers_progid, "", reg_clsid) # 3a
|
|
305
|
-
|
|
306
|
-
clsctx = getattr(cls, "_reg_clsctx_", 0)
|
|
307
|
-
|
|
308
|
-
if clsctx & comtypes.CLSCTX_LOCAL_SERVER and not hasattr(
|
|
309
|
-
sys, "frozendllhandle"
|
|
310
|
-
):
|
|
311
|
-
exe = sys.executable
|
|
312
|
-
if " " in exe:
|
|
313
|
-
exe = '"%s"' % exe
|
|
314
|
-
if not hasattr(sys, "frozen"):
|
|
315
|
-
if not __debug__:
|
|
316
|
-
exe = "%s -O" % exe
|
|
317
|
-
script = os.path.abspath(sys.modules[cls.__module__].__file__)
|
|
318
|
-
if " " in script:
|
|
319
|
-
script = '"%s"' % script
|
|
320
|
-
append(
|
|
321
|
-
HKCR,
|
|
322
|
-
"CLSID\\%s\\LocalServer32" % reg_clsid,
|
|
323
|
-
"",
|
|
324
|
-
"%s %s" % (exe, script),
|
|
325
|
-
)
|
|
326
|
-
else:
|
|
327
|
-
append(HKCR, "CLSID\\%s\\LocalServer32" % reg_clsid, "", "%s" % exe)
|
|
328
|
-
|
|
329
|
-
# Register InprocServer32 only when run from script or from
|
|
330
|
-
# py2exe dll server, not from py2exe exe server.
|
|
331
|
-
if clsctx & comtypes.CLSCTX_INPROC_SERVER and getattr(sys, "frozen", None) in (
|
|
332
|
-
None,
|
|
333
|
-
"dll",
|
|
334
|
-
):
|
|
335
|
-
append(
|
|
336
|
-
HKCR, "CLSID\\%s\\InprocServer32" % reg_clsid, "", self._get_serverdll()
|
|
337
|
-
)
|
|
338
|
-
# only for non-frozen inproc servers the PythonPath/PythonClass is needed.
|
|
339
|
-
if (
|
|
340
|
-
not hasattr(sys, "frozendllhandle")
|
|
341
|
-
or not comtypes.server.inprocserver._clsid_to_class
|
|
342
|
-
):
|
|
343
|
-
append(
|
|
344
|
-
HKCR,
|
|
345
|
-
"CLSID\\%s\\InprocServer32" % reg_clsid,
|
|
346
|
-
"PythonClass",
|
|
347
|
-
self._get_full_classname(cls),
|
|
348
|
-
)
|
|
349
|
-
append(
|
|
350
|
-
HKCR,
|
|
351
|
-
"CLSID\\%s\\InprocServer32" % reg_clsid,
|
|
352
|
-
"PythonPath",
|
|
353
|
-
self._get_pythonpath(cls),
|
|
354
|
-
)
|
|
355
|
-
|
|
356
|
-
reg_threading = getattr(cls, "_reg_threading_", None)
|
|
357
|
-
if reg_threading is not None:
|
|
358
|
-
append(
|
|
359
|
-
HKCR,
|
|
360
|
-
"CLSID\\%s\\InprocServer32" % reg_clsid,
|
|
361
|
-
"ThreadingModel",
|
|
362
|
-
reg_threading,
|
|
363
|
-
)
|
|
364
|
-
|
|
365
|
-
reg_tlib = getattr(cls, "_reg_typelib_", None)
|
|
366
|
-
if reg_tlib is not None:
|
|
367
|
-
append(HKCR, "CLSID\\%s\\Typelib" % reg_clsid, "", reg_tlib[0])
|
|
368
|
-
|
|
369
|
-
return table
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
################################################################
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
def register(cls):
|
|
376
|
-
Registrar().register(cls)
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
def unregister(cls):
|
|
380
|
-
Registrar().unregister(cls)
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
def UseCommandLine(*classes):
|
|
384
|
-
usage = (
|
|
385
|
-
"""Usage: %s [-regserver] [-unregserver] [-nodebug] [-f logformat] [-l loggername=level]"""
|
|
386
|
-
% sys.argv[0]
|
|
387
|
-
)
|
|
388
|
-
opts, args = w_getopt.w_getopt(
|
|
389
|
-
sys.argv[1:], "regserver unregserver embedding l: f: nodebug"
|
|
390
|
-
)
|
|
391
|
-
if not opts:
|
|
392
|
-
sys.stderr.write(usage + "\n")
|
|
393
|
-
return 0 # nothing for us to do
|
|
394
|
-
|
|
395
|
-
levels = []
|
|
396
|
-
format = None
|
|
397
|
-
nodebug = False
|
|
398
|
-
runit = False
|
|
399
|
-
for option, value in opts:
|
|
400
|
-
if option == "regserver":
|
|
401
|
-
for cls in classes:
|
|
402
|
-
register(cls)
|
|
403
|
-
elif option == "unregserver":
|
|
404
|
-
for cls in classes:
|
|
405
|
-
unregister(cls)
|
|
406
|
-
elif option == "embedding":
|
|
407
|
-
runit = True
|
|
408
|
-
elif option == "f":
|
|
409
|
-
format = value
|
|
410
|
-
elif option == "l":
|
|
411
|
-
levels.append(value)
|
|
412
|
-
elif option == "nodebug":
|
|
413
|
-
nodebug = True
|
|
414
|
-
|
|
415
|
-
if levels or format is not None:
|
|
416
|
-
for cls in classes:
|
|
417
|
-
Registrar().debug(cls, levels, format)
|
|
418
|
-
if nodebug:
|
|
419
|
-
for cls in classes:
|
|
420
|
-
Registrar().nodebug(cls)
|
|
421
|
-
|
|
422
|
-
if runit:
|
|
423
|
-
import comtypes.server.localserver
|
|
424
|
-
|
|
425
|
-
comtypes.server.localserver.run(classes)
|
|
426
|
-
|
|
427
|
-
return 1 # we have done something
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
if __name__ == "__main__":
|
|
431
|
-
UseCommandLine()
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
class GetoptError(Exception):
|
|
2
|
-
pass
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def w_getopt(args, options):
|
|
6
|
-
"""A getopt for Windows.
|
|
7
|
-
|
|
8
|
-
Options may start with either '-' or '/', the option names may
|
|
9
|
-
have more than one letter (/tlb or -RegServer), and option names
|
|
10
|
-
are case insensitive.
|
|
11
|
-
|
|
12
|
-
Returns two elements, just as getopt.getopt. The first is a list
|
|
13
|
-
of (option, value) pairs in the same way getopt.getopt does, but
|
|
14
|
-
there is no '-' or '/' prefix to the option name, and the option
|
|
15
|
-
name is always lower case. The second is the list of arguments
|
|
16
|
-
which do not belong to an option.
|
|
17
|
-
|
|
18
|
-
Different from getopt.getopt, a single argument not belonging to an option
|
|
19
|
-
does not terminate parsing.
|
|
20
|
-
"""
|
|
21
|
-
opts = []
|
|
22
|
-
arguments = []
|
|
23
|
-
while args:
|
|
24
|
-
if args[0][:1] in "/-":
|
|
25
|
-
arg = args[0][1:] # strip the '-' or '/'
|
|
26
|
-
arg = arg.lower()
|
|
27
|
-
|
|
28
|
-
if arg + ":" in options:
|
|
29
|
-
try:
|
|
30
|
-
opts.append((arg, args[1]))
|
|
31
|
-
except IndexError:
|
|
32
|
-
raise GetoptError("option '%s' requires an argument" % args[0])
|
|
33
|
-
args = args[1:]
|
|
34
|
-
elif arg in options:
|
|
35
|
-
opts.append((arg, ""))
|
|
36
|
-
else:
|
|
37
|
-
raise GetoptError("invalid option '%s'" % args[0])
|
|
38
|
-
args = args[1:]
|
|
39
|
-
else:
|
|
40
|
-
arguments.append(args[0])
|
|
41
|
-
args = args[1:]
|
|
42
|
-
|
|
43
|
-
return opts, arguments
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if __debug__:
|
|
47
|
-
if __name__ == "__main__":
|
|
48
|
-
import unittest
|
|
49
|
-
|
|
50
|
-
class TestCase(unittest.TestCase):
|
|
51
|
-
def test_1(self):
|
|
52
|
-
args = "-embedding spam /RegServer foo /UnregSERVER blabla".split()
|
|
53
|
-
opts, args = w_getopt(args, "regserver unregserver embedding".split())
|
|
54
|
-
self.assertEqual(
|
|
55
|
-
opts, [("embedding", ""), ("regserver", ""), ("unregserver", "")]
|
|
56
|
-
)
|
|
57
|
-
self.assertEqual(args, ["spam", "foo", "blabla"])
|
|
58
|
-
|
|
59
|
-
def test_2(self):
|
|
60
|
-
args = "/TLB Hello.Tlb HELLO.idl".split()
|
|
61
|
-
opts, args = w_getopt(args, ["tlb:"])
|
|
62
|
-
self.assertEqual(opts, [("tlb", "Hello.Tlb")])
|
|
63
|
-
self.assertEqual(args, ["HELLO.idl"])
|
|
64
|
-
|
|
65
|
-
def test_3(self):
|
|
66
|
-
# Invalid option
|
|
67
|
-
self.assertRaises(
|
|
68
|
-
GetoptError, w_getopt, "/TLIB hello.tlb hello.idl".split(), ["tlb:"]
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
def test_4(self):
|
|
72
|
-
# Missing argument
|
|
73
|
-
self.assertRaises(GetoptError, w_getopt, "/TLB".split(), ["tlb:"])
|
|
74
|
-
|
|
75
|
-
unittest.main()
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import unittest, gc
|
|
2
|
-
from ctypes import *
|
|
3
|
-
from ctypes.wintypes import *
|
|
4
|
-
|
|
5
|
-
################################################################
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class PROCESS_MEMORY_COUNTERS(Structure):
|
|
9
|
-
_fields_ = [
|
|
10
|
-
("cb", DWORD),
|
|
11
|
-
("PageFaultCount", DWORD),
|
|
12
|
-
("PeakWorkingSetSize", c_size_t),
|
|
13
|
-
("WorkingSetSize", c_size_t),
|
|
14
|
-
("QuotaPeakPagedPoolUsage", c_size_t),
|
|
15
|
-
("QuotaPagedPoolUsage", c_size_t),
|
|
16
|
-
("QuotaPeakNonPagedPoolUsage", c_size_t),
|
|
17
|
-
("QuotaNonPagedPoolUsage", c_size_t),
|
|
18
|
-
("PagefileUsage", c_size_t),
|
|
19
|
-
("PeakPagefileUsage", c_size_t),
|
|
20
|
-
]
|
|
21
|
-
|
|
22
|
-
def __init__(self):
|
|
23
|
-
self.cb = sizeof(self)
|
|
24
|
-
|
|
25
|
-
def dump(self):
|
|
26
|
-
for n, _ in self._fields_[2:]:
|
|
27
|
-
print(n, getattr(self, n) / 1e6)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
try:
|
|
31
|
-
windll.psapi.GetProcessMemoryInfo.argtypes = (
|
|
32
|
-
HANDLE,
|
|
33
|
-
POINTER(PROCESS_MEMORY_COUNTERS),
|
|
34
|
-
DWORD,
|
|
35
|
-
)
|
|
36
|
-
except WindowsError:
|
|
37
|
-
# cannot search for memory leaks on Windows CE
|
|
38
|
-
def find_memleak(func, loops=None):
|
|
39
|
-
return 0
|
|
40
|
-
|
|
41
|
-
else:
|
|
42
|
-
|
|
43
|
-
def wss():
|
|
44
|
-
# Return the working set size (memory used by process)
|
|
45
|
-
pmi = PROCESS_MEMORY_COUNTERS()
|
|
46
|
-
if not windll.psapi.GetProcessMemoryInfo(-1, byref(pmi), sizeof(pmi)):
|
|
47
|
-
raise WinError()
|
|
48
|
-
return pmi.WorkingSetSize
|
|
49
|
-
|
|
50
|
-
LOOPS = 10, 1000
|
|
51
|
-
|
|
52
|
-
def find_memleak(func, loops=LOOPS):
|
|
53
|
-
# call 'func' several times, so that memory consumption
|
|
54
|
-
# stabilizes:
|
|
55
|
-
for j in range(loops[0]):
|
|
56
|
-
for k in range(loops[1]):
|
|
57
|
-
func()
|
|
58
|
-
gc.collect()
|
|
59
|
-
gc.collect()
|
|
60
|
-
gc.collect()
|
|
61
|
-
bytes = wss()
|
|
62
|
-
# call 'func' several times, recording the difference in
|
|
63
|
-
# memory consumption before and after the call. Repeat this a
|
|
64
|
-
# few times, and return a list containing the memory
|
|
65
|
-
# consumption differences.
|
|
66
|
-
for j in range(loops[0]):
|
|
67
|
-
for k in range(loops[1]):
|
|
68
|
-
func()
|
|
69
|
-
gc.collect()
|
|
70
|
-
gc.collect()
|
|
71
|
-
gc.collect()
|
|
72
|
-
# return the increased in process size
|
|
73
|
-
result = wss() - bytes
|
|
74
|
-
# Sometimes the process size did decrease, we do not report leaks
|
|
75
|
-
# in this case:
|
|
76
|
-
return max(result, 0)
|