comtypes 1.4.9__zip → 1.4.11__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.9 → comtypes-1.4.11}/CHANGES.txt +41 -0
- {comtypes-1.4.9/comtypes.egg-info → comtypes-1.4.11}/PKG-INFO +4 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/GUID.py +34 -13
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/__init__.py +25 -16
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_comobject.py +92 -39
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_memberspec.py +112 -78
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_meta.py +2 -1
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_post_coinit/_cominterface_meta_patcher.py +3 -6
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_post_coinit/bstr.py +12 -5
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_post_coinit/instancemethod.py +1 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_post_coinit/misc.py +59 -24
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_post_coinit/unknwn.py +30 -25
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_safearray.py +2 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_vtbl.py +52 -55
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/automation.py +19 -14
- comtypes-1.4.11/comtypes/client/__init__.py +42 -0
- comtypes-1.4.11/comtypes/client/_activeobj.py +46 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/client/_code_cache.py +15 -24
- comtypes-1.4.11/comtypes/client/_create.py +147 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/client/_events.py +140 -57
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/client/_generate.py +3 -5
- comtypes-1.4.11/comtypes/client/_managing.py +114 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/client/dynamic.py +2 -3
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/client/lazybind.py +10 -11
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/connectionpoints.py +38 -3
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/errorinfo.py +72 -21
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/git.py +4 -3
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/hints.pyi +15 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/hresult.py +16 -6
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/logutil.py +15 -3
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/messageloop.py +15 -13
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/persist.py +3 -5
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/safearray.py +8 -6
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/server/__init__.py +22 -4
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/server/automation.py +1 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/server/connectionpoints.py +71 -70
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/server/inprocserver.py +14 -8
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/server/localserver.py +28 -16
- comtypes-1.4.11/comtypes/server/register.py +478 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/shelllink.py +13 -7
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/stream.py +7 -4
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/TestComServer.py +6 -7
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/TestDispServer.py +4 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/__init__.py +1 -1
- comtypes-1.4.11/comtypes/test/find_memleak.py +72 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/runtests.py +1 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/setup.py +2 -1
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_BSTR.py +7 -17
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_GUID.py +7 -7
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_QueryService.py +1 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_agilent.py +4 -3
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_basic.py +18 -9
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_clear_cache.py +1 -1
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_client.py +2 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_client_dynamic.py +2 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_client_regenerate_modules.py +2 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_collections.py +7 -4
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_comobject.py +22 -9
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_comserver.py +56 -3
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_dict.py +2 -1
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_dispifc_records.py +1 -1
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_dispifc_safearrays.py +1 -1
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_dyndispatch.py +5 -2
- comtypes-1.4.11/comtypes/test/test_errorinfo.py +115 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_findgendir.py +1 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_getactiveobj.py +4 -4
- comtypes-1.4.11/comtypes/test/test_hresult.py +48 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_ie.py +19 -6
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_ienum.py +2 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_imfattributes.py +13 -3
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_inout_args.py +10 -3
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_midl_safearray_create.py +6 -4
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_monikers.py +23 -9
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_msscript.py +2 -1
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_npsupport.py +4 -4
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_outparam.py +22 -6
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_persist.py +2 -4
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_recordinfo.py +1 -1
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_safearray.py +2 -1
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_sapi.py +4 -1
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_server_register.py +114 -125
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_shelllink.py +2 -3
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_storage.py +12 -6
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_stream.py +16 -5
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_subinterface.py +4 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_typeannotator.py +1 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_typeinfo.py +36 -7
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_urlhistory.py +7 -4
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_variant.py +5 -3
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_w_getopt.py +4 -4
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_word.py +1 -1
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/tools/codegenerator/codegenerator.py +167 -435
- comtypes-1.4.11/comtypes/tools/codegenerator/comments.py +79 -0
- comtypes-1.4.11/comtypes/tools/codegenerator/heads.py +192 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/tools/codegenerator/helpers.py +3 -6
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/tools/codegenerator/namespaces.py +13 -5
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/tools/codegenerator/typeannotator.py +13 -3
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/tools/tlbparser.py +25 -25
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/tools/typedesc.py +3 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/tools/typedesc_base.py +2 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/typeinfo.py +163 -51
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/viewobject.py +2 -4
- {comtypes-1.4.9 → comtypes-1.4.11/comtypes.egg-info}/PKG-INFO +4 -2
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes.egg-info/SOURCES.txt +7 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/pyproject.toml +10 -23
- comtypes-1.4.9/comtypes/client/__init__.py +0 -323
- comtypes-1.4.9/comtypes/server/register.py +0 -419
- comtypes-1.4.9/comtypes/test/find_memleak.py +0 -76
- {comtypes-1.4.9 → comtypes-1.4.11}/LICENSE.txt +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/MANIFEST.in +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/README.md +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_npsupport.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_post_coinit/__init__.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/_tlib_version_checker.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/clear_cache.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/client/_constants.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/patcher.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/server/w_getopt.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/TestComServer.idl +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/TestComServer.tlb +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/TestDispServer.idl +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/TestDispServer.tlb +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/mylib.idl +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/mylib.tlb +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/mytypelib.idl +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_DISPPARAMS.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_avmc.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_casesensitivity.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_createwrappers.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_dispinterface.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_excel.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_jscript.js +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_pump_events.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_server.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_showevents.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_win32com_interop.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/test_wmi.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/test/urlhist.tlb +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/tools/__init__.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/tools/codegenerator/__init__.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/tools/codegenerator/modulenamer.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/tools/codegenerator/packing.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes/util.py +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes.egg-info/dependency_links.txt +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes.egg-info/entry_points.txt +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/comtypes.egg-info/top_level.txt +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/setup.cfg +0 -0
- {comtypes-1.4.9 → comtypes-1.4.11}/setup.py +0 -0
|
@@ -1,419 +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 logging
|
|
40
|
-
import os
|
|
41
|
-
import sys
|
|
42
|
-
import winreg
|
|
43
|
-
from ctypes import WinError, c_ulong, c_wchar_p, create_string_buffer, sizeof, windll
|
|
44
|
-
from typing import Iterator, Tuple
|
|
45
|
-
|
|
46
|
-
import comtypes
|
|
47
|
-
import comtypes.server.inprocserver
|
|
48
|
-
from comtypes.hresult import *
|
|
49
|
-
from comtypes.server import w_getopt
|
|
50
|
-
from comtypes.typeinfo import REGKIND_REGISTER, LoadTypeLibEx, UnRegisterTypeLib
|
|
51
|
-
|
|
52
|
-
_debug = logging.getLogger(__name__).debug
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def get_winerror(exception):
|
|
56
|
-
try:
|
|
57
|
-
return exception.winerror
|
|
58
|
-
except AttributeError:
|
|
59
|
-
return exception.errno
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# a SHDeleteKey function, will remove a registry key with all subkeys.
|
|
63
|
-
def _non_zero(retval, func, args):
|
|
64
|
-
if retval:
|
|
65
|
-
raise WinError(retval)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
SHDeleteKey = windll.shlwapi.SHDeleteKeyW
|
|
69
|
-
SHDeleteKey.errcheck = _non_zero
|
|
70
|
-
SHDeleteKey.argtypes = c_ulong, c_wchar_p
|
|
71
|
-
|
|
72
|
-
Set = set
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
_KEYS = {
|
|
76
|
-
winreg.HKEY_CLASSES_ROOT: "HKCR",
|
|
77
|
-
winreg.HKEY_LOCAL_MACHINE: "HKLM",
|
|
78
|
-
winreg.HKEY_CURRENT_USER: "HKCU",
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def _explain(hkey):
|
|
83
|
-
return _KEYS.get(hkey, hkey)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
class Registrar(object):
|
|
87
|
-
"""COM class registration.
|
|
88
|
-
|
|
89
|
-
The COM class can override what this does by implementing
|
|
90
|
-
_register and/or _unregister class methods. These methods will be
|
|
91
|
-
called with the calling instance of Registrar, and so can call the
|
|
92
|
-
Registrars _register and _unregister methods which do the actual
|
|
93
|
-
work.
|
|
94
|
-
"""
|
|
95
|
-
|
|
96
|
-
def nodebug(self, cls):
|
|
97
|
-
"""Delete logging entries from the registry."""
|
|
98
|
-
clsid = cls._reg_clsid_
|
|
99
|
-
try:
|
|
100
|
-
_debug(
|
|
101
|
-
'DeleteKey( %s\\CLSID\\%s\\Logging"'
|
|
102
|
-
% (_explain(winreg.HKEY_CLASSES_ROOT), clsid)
|
|
103
|
-
)
|
|
104
|
-
hkey = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, rf"CLSID\{clsid}")
|
|
105
|
-
winreg.DeleteKey(hkey, "Logging")
|
|
106
|
-
except WindowsError as detail:
|
|
107
|
-
if get_winerror(detail) != 2:
|
|
108
|
-
raise
|
|
109
|
-
|
|
110
|
-
def debug(self, cls, levels, format):
|
|
111
|
-
"""Write entries in the registry to setup logging for this clsid."""
|
|
112
|
-
# handlers
|
|
113
|
-
# format
|
|
114
|
-
clsid = cls._reg_clsid_
|
|
115
|
-
_debug(
|
|
116
|
-
'CreateKey( %s\\CLSID\\%s\\Logging"'
|
|
117
|
-
% (_explain(winreg.HKEY_CLASSES_ROOT), clsid)
|
|
118
|
-
)
|
|
119
|
-
hkey = winreg.CreateKey(winreg.HKEY_CLASSES_ROOT, rf"CLSID\{clsid}\Logging")
|
|
120
|
-
for item in levels:
|
|
121
|
-
name, value = item.split("=")
|
|
122
|
-
v = getattr(logging, value)
|
|
123
|
-
assert isinstance(v, int)
|
|
124
|
-
_debug("SetValueEx(levels, %s)" % levels)
|
|
125
|
-
winreg.SetValueEx(hkey, "levels", None, winreg.REG_MULTI_SZ, levels)
|
|
126
|
-
if format:
|
|
127
|
-
_debug("SetValueEx(format, %s)" % format)
|
|
128
|
-
winreg.SetValueEx(hkey, "format", None, winreg.REG_SZ, format)
|
|
129
|
-
else:
|
|
130
|
-
_debug("DeleteValue(format)")
|
|
131
|
-
try:
|
|
132
|
-
winreg.DeleteValue(hkey, "format")
|
|
133
|
-
except WindowsError as detail:
|
|
134
|
-
if get_winerror(detail) != 2:
|
|
135
|
-
raise
|
|
136
|
-
|
|
137
|
-
def register(self, cls, executable=None):
|
|
138
|
-
"""Register the COM server class."""
|
|
139
|
-
# First, we unregister the object with force=True, to force removal
|
|
140
|
-
# of all registry entries, even if we would not write them.
|
|
141
|
-
# Second, we create new entries.
|
|
142
|
-
# It seems ATL does the same.
|
|
143
|
-
mth = getattr(cls, "_register", None)
|
|
144
|
-
if mth is not None:
|
|
145
|
-
mth(self)
|
|
146
|
-
else:
|
|
147
|
-
self._unregister(cls, force=True)
|
|
148
|
-
self._register(cls, executable)
|
|
149
|
-
|
|
150
|
-
def _register(self, cls, executable=None):
|
|
151
|
-
table = sorted(RegistryEntries(cls))
|
|
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 = _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 RegistryEntries(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
|
-
|
|
218
|
-
def _get_serverdll():
|
|
219
|
-
"""Return the pathname of the dll hosting the COM object."""
|
|
220
|
-
handle = getattr(sys, "frozendllhandle", None)
|
|
221
|
-
if handle is not None:
|
|
222
|
-
buf = create_string_buffer(260)
|
|
223
|
-
windll.kernel32.GetModuleFileNameA(handle, buf, sizeof(buf))
|
|
224
|
-
return buf[:]
|
|
225
|
-
import _ctypes
|
|
226
|
-
|
|
227
|
-
return _ctypes.__file__
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
class RegistryEntries(object):
|
|
231
|
-
def __init__(self, cls):
|
|
232
|
-
self._cls = cls
|
|
233
|
-
|
|
234
|
-
def _get_full_classname(self, cls):
|
|
235
|
-
"""Return <modulename>.<classname> for 'cls'."""
|
|
236
|
-
modname = cls.__module__
|
|
237
|
-
if modname == "__main__":
|
|
238
|
-
modname = os.path.splitext(os.path.basename(sys.argv[0]))[0]
|
|
239
|
-
return f"{modname}.{cls.__name__}"
|
|
240
|
-
|
|
241
|
-
def _get_pythonpath(self, cls):
|
|
242
|
-
"""Return the filesystem path of the module containing 'cls'."""
|
|
243
|
-
modname = cls.__module__
|
|
244
|
-
dirname = os.path.dirname(sys.modules[modname].__file__)
|
|
245
|
-
return os.path.abspath(dirname)
|
|
246
|
-
|
|
247
|
-
def __iter__(self) -> Iterator[Tuple[int, str, str, str]]:
|
|
248
|
-
"""Return a iterator of tuples containing registry entries.
|
|
249
|
-
|
|
250
|
-
The tuples must be (key, subkey, name, value).
|
|
251
|
-
|
|
252
|
-
Required entries:
|
|
253
|
-
=================
|
|
254
|
-
_reg_clsid_ - a string or GUID instance
|
|
255
|
-
_reg_clsctx_ - server type(s) to register
|
|
256
|
-
|
|
257
|
-
Optional entries:
|
|
258
|
-
=================
|
|
259
|
-
_reg_desc_ - a string
|
|
260
|
-
_reg_progid_ - a string naming the progid, typically 'MyServer.MyObject.1'
|
|
261
|
-
_reg_novers_progid_ - version independend progid, typically 'MyServer.MyObject'
|
|
262
|
-
_reg_typelib_ - an tuple (libid, majorversion, minorversion) specifying a typelib.
|
|
263
|
-
_reg_threading_ - a string specifying the threading model
|
|
264
|
-
|
|
265
|
-
Note that the first part of the progid string is typically the
|
|
266
|
-
IDL library name of the type library containing the coclass.
|
|
267
|
-
"""
|
|
268
|
-
cls = self._cls
|
|
269
|
-
HKCR = winreg.HKEY_CLASSES_ROOT
|
|
270
|
-
|
|
271
|
-
# basic entry - names the comobject
|
|
272
|
-
|
|
273
|
-
# that's the only required attribute for registration
|
|
274
|
-
reg_clsid = str(cls._reg_clsid_)
|
|
275
|
-
reg_desc = getattr(cls, "_reg_desc_", "")
|
|
276
|
-
if not reg_desc:
|
|
277
|
-
# Simple minded algorithm to construct a description from
|
|
278
|
-
# the progid:
|
|
279
|
-
reg_desc = getattr(cls, "_reg_novers_progid_", "") or getattr(
|
|
280
|
-
cls, "_reg_progid_", ""
|
|
281
|
-
)
|
|
282
|
-
if reg_desc:
|
|
283
|
-
reg_desc = reg_desc.replace(".", " ")
|
|
284
|
-
yield (HKCR, f"CLSID\\{reg_clsid}", "", reg_desc)
|
|
285
|
-
|
|
286
|
-
reg_progid = getattr(cls, "_reg_progid_", None)
|
|
287
|
-
if reg_progid:
|
|
288
|
-
# for ProgIDFromCLSID:
|
|
289
|
-
yield (HKCR, f"CLSID\\{reg_clsid}\\ProgID", "", reg_progid) # 1
|
|
290
|
-
|
|
291
|
-
# for CLSIDFromProgID
|
|
292
|
-
if reg_desc:
|
|
293
|
-
yield (HKCR, reg_progid, "", reg_desc) # 2
|
|
294
|
-
yield (HKCR, f"{reg_progid}\\CLSID", "", reg_clsid) # 3
|
|
295
|
-
|
|
296
|
-
reg_novers_progid = getattr(cls, "_reg_novers_progid_", None)
|
|
297
|
-
if reg_novers_progid:
|
|
298
|
-
yield (
|
|
299
|
-
HKCR,
|
|
300
|
-
f"CLSID\\{reg_clsid}\\VersionIndependentProgID", # 1a
|
|
301
|
-
"",
|
|
302
|
-
reg_novers_progid,
|
|
303
|
-
)
|
|
304
|
-
if reg_desc:
|
|
305
|
-
yield (HKCR, reg_novers_progid, "", reg_desc) # 2a
|
|
306
|
-
yield (HKCR, f"{reg_novers_progid}\\CurVer", "", reg_progid) #
|
|
307
|
-
yield (HKCR, f"{reg_novers_progid}\\CLSID", "", reg_clsid) # 3a
|
|
308
|
-
|
|
309
|
-
clsctx: int = getattr(cls, "_reg_clsctx_", 0)
|
|
310
|
-
localsvr_ctx = bool(clsctx & comtypes.CLSCTX_LOCAL_SERVER)
|
|
311
|
-
inprocsvr_ctx = bool(clsctx & comtypes.CLSCTX_INPROC_SERVER)
|
|
312
|
-
|
|
313
|
-
if localsvr_ctx and not hasattr(sys, "frozendllhandle"):
|
|
314
|
-
exe = sys.executable
|
|
315
|
-
if " " in exe:
|
|
316
|
-
exe = f'"{exe}"'
|
|
317
|
-
if not hasattr(sys, "frozen"):
|
|
318
|
-
if not __debug__:
|
|
319
|
-
exe = f"{exe} -O"
|
|
320
|
-
script = os.path.abspath(sys.modules[cls.__module__].__file__)
|
|
321
|
-
if " " in script:
|
|
322
|
-
script = f'"{script}"'
|
|
323
|
-
yield (HKCR, rf"CLSID\{reg_clsid}\LocalServer32", "", f"{exe} {script}")
|
|
324
|
-
else:
|
|
325
|
-
yield (HKCR, rf"CLSID\{reg_clsid}\LocalServer32", "", f"{exe}")
|
|
326
|
-
|
|
327
|
-
# Register InprocServer32 only when run from script or from
|
|
328
|
-
# py2exe dll server, not from py2exe exe server.
|
|
329
|
-
if inprocsvr_ctx and getattr(sys, "frozen", None) in (None, "dll"):
|
|
330
|
-
yield (HKCR, rf"CLSID\{reg_clsid}\InprocServer32", "", _get_serverdll())
|
|
331
|
-
# only for non-frozen inproc servers the PythonPath/PythonClass is needed.
|
|
332
|
-
if (
|
|
333
|
-
not hasattr(sys, "frozendllhandle")
|
|
334
|
-
or not comtypes.server.inprocserver._clsid_to_class
|
|
335
|
-
):
|
|
336
|
-
yield (
|
|
337
|
-
HKCR,
|
|
338
|
-
rf"CLSID\{reg_clsid}\InprocServer32",
|
|
339
|
-
"PythonClass",
|
|
340
|
-
self._get_full_classname(cls),
|
|
341
|
-
)
|
|
342
|
-
yield (
|
|
343
|
-
HKCR,
|
|
344
|
-
rf"CLSID\{reg_clsid}\InprocServer32",
|
|
345
|
-
"PythonPath",
|
|
346
|
-
self._get_pythonpath(cls),
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
reg_threading = getattr(cls, "_reg_threading_", None)
|
|
350
|
-
if reg_threading is not None:
|
|
351
|
-
yield (
|
|
352
|
-
HKCR,
|
|
353
|
-
rf"CLSID\{reg_clsid}\InprocServer32",
|
|
354
|
-
"ThreadingModel",
|
|
355
|
-
reg_threading,
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
reg_tlib = getattr(cls, "_reg_typelib_", None)
|
|
359
|
-
if reg_tlib is not None:
|
|
360
|
-
yield (HKCR, rf"CLSID\{reg_clsid}\Typelib", "", reg_tlib[0])
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
################################################################
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
def register(cls):
|
|
367
|
-
Registrar().register(cls)
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
def unregister(cls):
|
|
371
|
-
Registrar().unregister(cls)
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
def UseCommandLine(*classes):
|
|
375
|
-
usage = f"""Usage: {sys.argv[0]} [-regserver] [-unregserver] [-nodebug] [-f logformat] [-l loggername=level]"""
|
|
376
|
-
opts, args = w_getopt.w_getopt(
|
|
377
|
-
sys.argv[1:], "regserver unregserver embedding l: f: nodebug"
|
|
378
|
-
)
|
|
379
|
-
if not opts:
|
|
380
|
-
sys.stderr.write(usage + "\n")
|
|
381
|
-
return 0 # nothing for us to do
|
|
382
|
-
|
|
383
|
-
levels = []
|
|
384
|
-
format = None
|
|
385
|
-
nodebug = False
|
|
386
|
-
runit = False
|
|
387
|
-
for option, value in opts:
|
|
388
|
-
if option == "regserver":
|
|
389
|
-
for cls in classes:
|
|
390
|
-
register(cls)
|
|
391
|
-
elif option == "unregserver":
|
|
392
|
-
for cls in classes:
|
|
393
|
-
unregister(cls)
|
|
394
|
-
elif option == "embedding":
|
|
395
|
-
runit = True
|
|
396
|
-
elif option == "f":
|
|
397
|
-
format = value
|
|
398
|
-
elif option == "l":
|
|
399
|
-
levels.append(value)
|
|
400
|
-
elif option == "nodebug":
|
|
401
|
-
nodebug = True
|
|
402
|
-
|
|
403
|
-
if levels or format is not None:
|
|
404
|
-
for cls in classes:
|
|
405
|
-
Registrar().debug(cls, levels, format)
|
|
406
|
-
if nodebug:
|
|
407
|
-
for cls in classes:
|
|
408
|
-
Registrar().nodebug(cls)
|
|
409
|
-
|
|
410
|
-
if runit:
|
|
411
|
-
import comtypes.server.localserver
|
|
412
|
-
|
|
413
|
-
comtypes.server.localserver.run(classes)
|
|
414
|
-
|
|
415
|
-
return 1 # we have done something
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
if __name__ == "__main__":
|
|
419
|
-
UseCommandLine()
|
|
@@ -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)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|