Uploaded Test files

This commit is contained in:
Batuhan Berk Başoğlu 2020-11-12 11:05:57 -05:00
parent f584ad9d97
commit 2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions

View file

@ -0,0 +1,102 @@
import win32com
import win32com.client
if type(__path__)==type(''):
# For freeze to work!
import sys
try:
from . import adsi
sys.modules['win32com.adsi.adsi'] = adsi
except ImportError:
pass
else:
# See if we have a special directory for the binaries (for developers)
win32com.__PackageSupportBuildPath__(__path__)
# Some helpers
# We want to _look_ like the ADSI module, but provide some additional
# helpers.
# Of specific note - most of the interfaces supported by ADSI
# derive from IDispatch - thus, you get the custome methods from the
# interface, as well as via IDispatch.
import pythoncom
from .adsi import *
LCID = 0
IDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]
IADsContainerType = pythoncom.TypeIIDs[adsi.IID_IADsContainer]
def _get_good_ret(ob,
# Named arguments used internally
resultCLSID = None):
assert resultCLSID is None, "Now have type info for ADSI objects - fix me!"
# See if the object supports IDispatch
if hasattr(ob, "Invoke"):
import win32com.client.dynamic
name = "Dispatch wrapper around %r" % ob
return win32com.client.dynamic.Dispatch(ob, name, ADSIDispatch)
return ob
class ADSIEnumerator:
def __init__(self, ob):
# Query the object for the container interface.
self._cont_ = ob.QueryInterface(IID_IADsContainer)
self._oleobj_ = ADsBuildEnumerator(self._cont_) # a PyIADsEnumVARIANT
self.index = -1
def __getitem__(self, index):
return self.__GetIndex(index)
def __call__(self, index):
return self.__GetIndex(index)
def __GetIndex(self, index):
if type(index)!=type(0): raise TypeError("Only integer indexes are supported for enumerators")
if index != self.index + 1:
# Index requested out of sequence.
raise ValueError("You must index this object sequentially")
self.index = index
result = ADsEnumerateNext(self._oleobj_, 1)
if len(result):
return _get_good_ret(result[0])
# Failed - reset for next time around.
self.index = -1
self._oleobj_ = ADsBuildEnumerator(self._cont_) # a PyIADsEnumVARIANT
raise IndexError("list index out of range")
class ADSIDispatch(win32com.client.CDispatch):
def _wrap_dispatch_(self, ob, userName = None, returnCLSID = None, UnicodeToString=None):
assert UnicodeToString is None, "this is deprectated and will be removed"
if not userName:
userName = "ADSI-object"
olerepr = win32com.client.dynamic.MakeOleRepr(ob, None, None)
return ADSIDispatch(ob, olerepr, userName)
def _NewEnum(self):
try:
return ADSIEnumerator(self)
except pythoncom.com_error:
# doesnt support it - let our base try!
return win32com.client.CDispatch._NewEnum(self)
def __getattr__(self, attr):
try:
return getattr(self._oleobj_, attr)
except AttributeError:
return win32com.client.CDispatch.__getattr__(self, attr)
def QueryInterface(self, iid):
ret = self._oleobj_.QueryInterface(iid)
return _get_good_ret(ret)
# We override the global methods to do the right thing.
_ADsGetObject = ADsGetObject # The one in the .pyd
def ADsGetObject(path, iid = pythoncom.IID_IDispatch):
ret = _ADsGetObject(path, iid)
return _get_good_ret(ret)
_ADsOpenObject = ADsOpenObject
def ADsOpenObject(path, username, password, reserved = 0, iid = pythoncom.IID_IDispatch):
ret = _ADsOpenObject(path, username, password, reserved, iid)
return _get_good_ret(ret)

Binary file not shown.

View file

@ -0,0 +1,336 @@
ADS_ATTR_CLEAR = ( 1 )
ADS_ATTR_UPDATE = ( 2 )
ADS_ATTR_APPEND = ( 3 )
ADS_ATTR_DELETE = ( 4 )
ADS_EXT_MINEXTDISPID = ( 1 )
ADS_EXT_MAXEXTDISPID = ( 16777215 )
ADS_EXT_INITCREDENTIALS = ( 1 )
ADS_EXT_INITIALIZE_COMPLETE = ( 2 )
ADS_SEARCHPREF_ASYNCHRONOUS = 0
ADS_SEARCHPREF_DEREF_ALIASES = 1
ADS_SEARCHPREF_SIZE_LIMIT = 2
ADS_SEARCHPREF_TIME_LIMIT = 3
ADS_SEARCHPREF_ATTRIBTYPES_ONLY = 4
ADS_SEARCHPREF_SEARCH_SCOPE = 5
ADS_SEARCHPREF_TIMEOUT = 6
ADS_SEARCHPREF_PAGESIZE = 7
ADS_SEARCHPREF_PAGED_TIME_LIMIT = 8
ADS_SEARCHPREF_CHASE_REFERRALS = 9
ADS_SEARCHPREF_SORT_ON = 10
ADS_SEARCHPREF_CACHE_RESULTS = 11
ADS_SEARCHPREF_DIRSYNC = 12
ADS_SEARCHPREF_TOMBSTONE = 13
ADS_SCOPE_BASE = 0
ADS_SCOPE_ONELEVEL = 1
ADS_SCOPE_SUBTREE = 2
ADS_SECURE_AUTHENTICATION = 0x1
ADS_USE_ENCRYPTION = 0x2
ADS_USE_SSL = 0x2
ADS_READONLY_SERVER = 0x4
ADS_PROMPT_CREDENTIALS = 0x8
ADS_NO_AUTHENTICATION = 0x10
ADS_FAST_BIND = 0x20
ADS_USE_SIGNING = 0x40
ADS_USE_SEALING = 0x80
ADS_USE_DELEGATION = 0x100
ADS_SERVER_BIND = 0x200
ADSTYPE_INVALID = 0
ADSTYPE_DN_STRING = ADSTYPE_INVALID + 1
ADSTYPE_CASE_EXACT_STRING = ADSTYPE_DN_STRING + 1
ADSTYPE_CASE_IGNORE_STRING = ADSTYPE_CASE_EXACT_STRING + 1
ADSTYPE_PRINTABLE_STRING = ADSTYPE_CASE_IGNORE_STRING + 1
ADSTYPE_NUMERIC_STRING = ADSTYPE_PRINTABLE_STRING + 1
ADSTYPE_BOOLEAN = ADSTYPE_NUMERIC_STRING + 1
ADSTYPE_INTEGER = ADSTYPE_BOOLEAN + 1
ADSTYPE_OCTET_STRING = ADSTYPE_INTEGER + 1
ADSTYPE_UTC_TIME = ADSTYPE_OCTET_STRING + 1
ADSTYPE_LARGE_INTEGER = ADSTYPE_UTC_TIME + 1
ADSTYPE_PROV_SPECIFIC = ADSTYPE_LARGE_INTEGER + 1
ADSTYPE_OBJECT_CLASS = ADSTYPE_PROV_SPECIFIC + 1
ADSTYPE_CASEIGNORE_LIST = ADSTYPE_OBJECT_CLASS + 1
ADSTYPE_OCTET_LIST = ADSTYPE_CASEIGNORE_LIST + 1
ADSTYPE_PATH = ADSTYPE_OCTET_LIST + 1
ADSTYPE_POSTALADDRESS = ADSTYPE_PATH + 1
ADSTYPE_TIMESTAMP = ADSTYPE_POSTALADDRESS + 1
ADSTYPE_BACKLINK = ADSTYPE_TIMESTAMP + 1
ADSTYPE_TYPEDNAME = ADSTYPE_BACKLINK + 1
ADSTYPE_HOLD = ADSTYPE_TYPEDNAME + 1
ADSTYPE_NETADDRESS = ADSTYPE_HOLD + 1
ADSTYPE_REPLICAPOINTER = ADSTYPE_NETADDRESS + 1
ADSTYPE_FAXNUMBER = ADSTYPE_REPLICAPOINTER + 1
ADSTYPE_EMAIL = ADSTYPE_FAXNUMBER + 1
ADSTYPE_NT_SECURITY_DESCRIPTOR = ADSTYPE_EMAIL + 1
ADSTYPE_UNKNOWN = ADSTYPE_NT_SECURITY_DESCRIPTOR + 1
ADSTYPE_DN_WITH_BINARY = ADSTYPE_UNKNOWN + 1
ADSTYPE_DN_WITH_STRING = ADSTYPE_DN_WITH_BINARY + 1
ADS_PROPERTY_CLEAR = 1
ADS_PROPERTY_UPDATE = 2
ADS_PROPERTY_APPEND = 3
ADS_PROPERTY_DELETE = 4
ADS_SYSTEMFLAG_DISALLOW_DELETE = -2147483648
ADS_SYSTEMFLAG_CONFIG_ALLOW_RENAME = 0x40000000
ADS_SYSTEMFLAG_CONFIG_ALLOW_MOVE = 0x20000000
ADS_SYSTEMFLAG_CONFIG_ALLOW_LIMITED_MOVE = 0x10000000
ADS_SYSTEMFLAG_DOMAIN_DISALLOW_RENAME = -2147483648
ADS_SYSTEMFLAG_DOMAIN_DISALLOW_MOVE = 0x4000000
ADS_SYSTEMFLAG_CR_NTDS_NC = 0x1
ADS_SYSTEMFLAG_CR_NTDS_DOMAIN = 0x2
ADS_SYSTEMFLAG_ATTR_NOT_REPLICATED = 0x1
ADS_SYSTEMFLAG_ATTR_IS_CONSTRUCTED = 0x4
ADS_GROUP_TYPE_GLOBAL_GROUP = 0x2
ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP = 0x4
ADS_GROUP_TYPE_LOCAL_GROUP = 0x4
ADS_GROUP_TYPE_UNIVERSAL_GROUP = 0x8
ADS_GROUP_TYPE_SECURITY_ENABLED = -2147483648
ADS_UF_SCRIPT = 0x1
ADS_UF_ACCOUNTDISABLE = 0x2
ADS_UF_HOMEDIR_REQUIRED = 0x8
ADS_UF_LOCKOUT = 0x10
ADS_UF_PASSWD_NOTREQD = 0x20
ADS_UF_PASSWD_CANT_CHANGE = 0x40
ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x80
ADS_UF_TEMP_DUPLICATE_ACCOUNT = 0x100
ADS_UF_NORMAL_ACCOUNT = 0x200
ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 0x800
ADS_UF_WORKSTATION_TRUST_ACCOUNT = 0x1000
ADS_UF_SERVER_TRUST_ACCOUNT = 0x2000
ADS_UF_DONT_EXPIRE_PASSWD = 0x10000
ADS_UF_MNS_LOGON_ACCOUNT = 0x20000
ADS_UF_SMARTCARD_REQUIRED = 0x40000
ADS_UF_TRUSTED_FOR_DELEGATION = 0x80000
ADS_UF_NOT_DELEGATED = 0x100000
ADS_UF_USE_DES_KEY_ONLY = 0x200000
ADS_UF_DONT_REQUIRE_PREAUTH = 0x400000
ADS_UF_PASSWORD_EXPIRED = 0x800000
ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x1000000
ADS_RIGHT_DELETE = 0x10000
ADS_RIGHT_READ_CONTROL = 0x20000
ADS_RIGHT_WRITE_DAC = 0x40000
ADS_RIGHT_WRITE_OWNER = 0x80000
ADS_RIGHT_SYNCHRONIZE = 0x100000
ADS_RIGHT_ACCESS_SYSTEM_SECURITY = 0x1000000
ADS_RIGHT_GENERIC_READ = -2147483648
ADS_RIGHT_GENERIC_WRITE = 0x40000000
ADS_RIGHT_GENERIC_EXECUTE = 0x20000000
ADS_RIGHT_GENERIC_ALL = 0x10000000
ADS_RIGHT_DS_CREATE_CHILD = 0x1
ADS_RIGHT_DS_DELETE_CHILD = 0x2
ADS_RIGHT_ACTRL_DS_LIST = 0x4
ADS_RIGHT_DS_SELF = 0x8
ADS_RIGHT_DS_READ_PROP = 0x10
ADS_RIGHT_DS_WRITE_PROP = 0x20
ADS_RIGHT_DS_DELETE_TREE = 0x40
ADS_RIGHT_DS_LIST_OBJECT = 0x80
ADS_RIGHT_DS_CONTROL_ACCESS = 0x100
ADS_ACETYPE_ACCESS_ALLOWED = 0
ADS_ACETYPE_ACCESS_DENIED = 0x1
ADS_ACETYPE_SYSTEM_AUDIT = 0x2
ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = 0x5
ADS_ACETYPE_ACCESS_DENIED_OBJECT = 0x6
ADS_ACETYPE_SYSTEM_AUDIT_OBJECT = 0x7
ADS_ACETYPE_SYSTEM_ALARM_OBJECT = 0x8
ADS_ACETYPE_ACCESS_ALLOWED_CALLBACK = 0x9
ADS_ACETYPE_ACCESS_DENIED_CALLBACK = 0xa
ADS_ACETYPE_ACCESS_ALLOWED_CALLBACK_OBJECT = 0xb
ADS_ACETYPE_ACCESS_DENIED_CALLBACK_OBJECT = 0xc
ADS_ACETYPE_SYSTEM_AUDIT_CALLBACK = 0xd
ADS_ACETYPE_SYSTEM_ALARM_CALLBACK = 0xe
ADS_ACETYPE_SYSTEM_AUDIT_CALLBACK_OBJECT = 0xf
ADS_ACETYPE_SYSTEM_ALARM_CALLBACK_OBJECT = 0x10
ADS_ACEFLAG_INHERIT_ACE = 0x2
ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE = 0x4
ADS_ACEFLAG_INHERIT_ONLY_ACE = 0x8
ADS_ACEFLAG_INHERITED_ACE = 0x10
ADS_ACEFLAG_VALID_INHERIT_FLAGS = 0x1f
ADS_ACEFLAG_SUCCESSFUL_ACCESS = 0x40
ADS_ACEFLAG_FAILED_ACCESS = 0x80
ADS_FLAG_OBJECT_TYPE_PRESENT = 0x1
ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT = 0x2
ADS_SD_CONTROL_SE_OWNER_DEFAULTED = 0x1
ADS_SD_CONTROL_SE_GROUP_DEFAULTED = 0x2
ADS_SD_CONTROL_SE_DACL_PRESENT = 0x4
ADS_SD_CONTROL_SE_DACL_DEFAULTED = 0x8
ADS_SD_CONTROL_SE_SACL_PRESENT = 0x10
ADS_SD_CONTROL_SE_SACL_DEFAULTED = 0x20
ADS_SD_CONTROL_SE_DACL_AUTO_INHERIT_REQ = 0x100
ADS_SD_CONTROL_SE_SACL_AUTO_INHERIT_REQ = 0x200
ADS_SD_CONTROL_SE_DACL_AUTO_INHERITED = 0x400
ADS_SD_CONTROL_SE_SACL_AUTO_INHERITED = 0x800
ADS_SD_CONTROL_SE_DACL_PROTECTED = 0x1000
ADS_SD_CONTROL_SE_SACL_PROTECTED = 0x2000
ADS_SD_CONTROL_SE_SELF_RELATIVE = 0x8000
ADS_SD_REVISION_DS = 4
ADS_NAME_TYPE_1779 = 1
ADS_NAME_TYPE_CANONICAL = 2
ADS_NAME_TYPE_NT4 = 3
ADS_NAME_TYPE_DISPLAY = 4
ADS_NAME_TYPE_DOMAIN_SIMPLE = 5
ADS_NAME_TYPE_ENTERPRISE_SIMPLE = 6
ADS_NAME_TYPE_GUID = 7
ADS_NAME_TYPE_UNKNOWN = 8
ADS_NAME_TYPE_USER_PRINCIPAL_NAME = 9
ADS_NAME_TYPE_CANONICAL_EX = 10
ADS_NAME_TYPE_SERVICE_PRINCIPAL_NAME = 11
ADS_NAME_TYPE_SID_OR_SID_HISTORY_NAME = 12
ADS_NAME_INITTYPE_DOMAIN = 1
ADS_NAME_INITTYPE_SERVER = 2
ADS_NAME_INITTYPE_GC = 3
ADS_OPTION_SERVERNAME = 0
ADS_OPTION_REFERRALS = ADS_OPTION_SERVERNAME + 1
ADS_OPTION_PAGE_SIZE = ADS_OPTION_REFERRALS + 1
ADS_OPTION_SECURITY_MASK = ADS_OPTION_PAGE_SIZE + 1
ADS_OPTION_MUTUAL_AUTH_STATUS = ADS_OPTION_SECURITY_MASK + 1
ADS_OPTION_QUOTA = ADS_OPTION_MUTUAL_AUTH_STATUS + 1
ADS_OPTION_PASSWORD_PORTNUMBER = ADS_OPTION_QUOTA + 1
ADS_OPTION_PASSWORD_METHOD = ADS_OPTION_PASSWORD_PORTNUMBER + 1
ADS_SECURITY_INFO_OWNER = 0x1
ADS_SECURITY_INFO_GROUP = 0x2
ADS_SECURITY_INFO_DACL = 0x4
ADS_SECURITY_INFO_SACL = 0x8
ADS_SETTYPE_FULL = 1
ADS_SETTYPE_PROVIDER = 2
ADS_SETTYPE_SERVER = 3
ADS_SETTYPE_DN = 4
ADS_FORMAT_WINDOWS = 1
ADS_FORMAT_WINDOWS_NO_SERVER = 2
ADS_FORMAT_WINDOWS_DN = 3
ADS_FORMAT_WINDOWS_PARENT = 4
ADS_FORMAT_X500 = 5
ADS_FORMAT_X500_NO_SERVER = 6
ADS_FORMAT_X500_DN = 7
ADS_FORMAT_X500_PARENT = 8
ADS_FORMAT_SERVER = 9
ADS_FORMAT_PROVIDER = 10
ADS_FORMAT_LEAF = 11
ADS_DISPLAY_FULL = 1
ADS_DISPLAY_VALUE_ONLY = 2
ADS_ESCAPEDMODE_DEFAULT = 1
ADS_ESCAPEDMODE_ON = 2
ADS_ESCAPEDMODE_OFF = 3
ADS_ESCAPEDMODE_OFF_EX = 4
ADS_PATH_FILE = 1
ADS_PATH_FILESHARE = 2
ADS_PATH_REGISTRY = 3
ADS_SD_FORMAT_IID = 1
ADS_SD_FORMAT_RAW = 2
ADS_SD_FORMAT_HEXSTRING = 3
# Generated by h2py from AdsErr.h
def _HRESULT_TYPEDEF_(_sc): return _sc
E_ADS_BAD_PATHNAME = _HRESULT_TYPEDEF_((-2147463168))
E_ADS_INVALID_DOMAIN_OBJECT = _HRESULT_TYPEDEF_((-2147463167))
E_ADS_INVALID_USER_OBJECT = _HRESULT_TYPEDEF_((-2147463166))
E_ADS_INVALID_COMPUTER_OBJECT = _HRESULT_TYPEDEF_((-2147463165))
E_ADS_UNKNOWN_OBJECT = _HRESULT_TYPEDEF_((-2147463164))
E_ADS_PROPERTY_NOT_SET = _HRESULT_TYPEDEF_((-2147463163))
E_ADS_PROPERTY_NOT_SUPPORTED = _HRESULT_TYPEDEF_((-2147463162))
E_ADS_PROPERTY_INVALID = _HRESULT_TYPEDEF_((-2147463161))
E_ADS_BAD_PARAMETER = _HRESULT_TYPEDEF_((-2147463160))
E_ADS_OBJECT_UNBOUND = _HRESULT_TYPEDEF_((-2147463159))
E_ADS_PROPERTY_NOT_MODIFIED = _HRESULT_TYPEDEF_((-2147463158))
E_ADS_PROPERTY_MODIFIED = _HRESULT_TYPEDEF_((-2147463157))
E_ADS_CANT_CONVERT_DATATYPE = _HRESULT_TYPEDEF_((-2147463156))
E_ADS_PROPERTY_NOT_FOUND = _HRESULT_TYPEDEF_((-2147463155))
E_ADS_OBJECT_EXISTS = _HRESULT_TYPEDEF_((-2147463154))
E_ADS_SCHEMA_VIOLATION = _HRESULT_TYPEDEF_((-2147463153))
E_ADS_COLUMN_NOT_SET = _HRESULT_TYPEDEF_((-2147463152))
S_ADS_ERRORSOCCURRED = _HRESULT_TYPEDEF_(0x00005011)
S_ADS_NOMORE_ROWS = _HRESULT_TYPEDEF_(0x00005012)
S_ADS_NOMORE_COLUMNS = _HRESULT_TYPEDEF_(0x00005013)
E_ADS_INVALID_FILTER = _HRESULT_TYPEDEF_((-2147463148))
# ADS_DEREFENUM enum
ADS_DEREF_NEVER = 0
ADS_DEREF_SEARCHING = 1
ADS_DEREF_FINDING = 2
ADS_DEREF_ALWAYS = 3
# ADS_PREFERENCES_ENUM
ADSIPROP_ASYNCHRONOUS = 0
ADSIPROP_DEREF_ALIASES = 0x1
ADSIPROP_SIZE_LIMIT = 0x2
ADSIPROP_TIME_LIMIT = 0x3
ADSIPROP_ATTRIBTYPES_ONLY = 0x4
ADSIPROP_SEARCH_SCOPE = 0x5
ADSIPROP_TIMEOUT = 0x6
ADSIPROP_PAGESIZE = 0x7
ADSIPROP_PAGED_TIME_LIMIT = 0x8
ADSIPROP_CHASE_REFERRALS = 0x9
ADSIPROP_SORT_ON = 0xa
ADSIPROP_CACHE_RESULTS = 0xb
ADSIPROP_ADSIFLAG = 0xc
# ADSI_DIALECT_ENUM
ADSI_DIALECT_LDAP = 0
ADSI_DIALECT_SQL = 0x1
# ADS_CHASE_REFERRALS_ENUM
ADS_CHASE_REFERRALS_NEVER = 0
ADS_CHASE_REFERRALS_SUBORDINATE = 0x20
ADS_CHASE_REFERRALS_EXTERNAL = 0x40
ADS_CHASE_REFERRALS_ALWAYS = ADS_CHASE_REFERRALS_SUBORDINATE | ADS_CHASE_REFERRALS_EXTERNAL
# Generated by h2py from ObjSel.h
DSOP_SCOPE_TYPE_TARGET_COMPUTER = 0x00000001
DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN = 0x00000002
DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN = 0x00000004
DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN = 0x00000008
DSOP_SCOPE_TYPE_GLOBAL_CATALOG = 0x00000010
DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN = 0x00000020
DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN = 0x00000040
DSOP_SCOPE_TYPE_WORKGROUP = 0x00000080
DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE = 0x00000100
DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE = 0x00000200
DSOP_SCOPE_FLAG_STARTING_SCOPE = 0x00000001
DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT = 0x00000002
DSOP_SCOPE_FLAG_WANT_PROVIDER_LDAP = 0x00000004
DSOP_SCOPE_FLAG_WANT_PROVIDER_GC = 0x00000008
DSOP_SCOPE_FLAG_WANT_SID_PATH = 0x00000010
DSOP_SCOPE_FLAG_WANT_DOWNLEVEL_BUILTIN_PATH = 0x00000020
DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS = 0x00000040
DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS = 0x00000080
DSOP_SCOPE_FLAG_DEFAULT_FILTER_COMPUTERS = 0x00000100
DSOP_SCOPE_FLAG_DEFAULT_FILTER_CONTACTS = 0x00000200
DSOP_FILTER_INCLUDE_ADVANCED_VIEW = 0x00000001
DSOP_FILTER_USERS = 0x00000002
DSOP_FILTER_BUILTIN_GROUPS = 0x00000004
DSOP_FILTER_WELL_KNOWN_PRINCIPALS = 0x00000008
DSOP_FILTER_UNIVERSAL_GROUPS_DL = 0x00000010
DSOP_FILTER_UNIVERSAL_GROUPS_SE = 0x00000020
DSOP_FILTER_GLOBAL_GROUPS_DL = 0x00000040
DSOP_FILTER_GLOBAL_GROUPS_SE = 0x00000080
DSOP_FILTER_DOMAIN_LOCAL_GROUPS_DL = 0x00000100
DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE = 0x00000200
DSOP_FILTER_CONTACTS = 0x00000400
DSOP_FILTER_COMPUTERS = 0x00000800
DSOP_DOWNLEVEL_FILTER_USERS = (-2147483647)
DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS = (-2147483646)
DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS = (-2147483644)
DSOP_DOWNLEVEL_FILTER_COMPUTERS = (-2147483640)
DSOP_DOWNLEVEL_FILTER_WORLD = (-2147483632)
DSOP_DOWNLEVEL_FILTER_AUTHENTICATED_USER = (-2147483616)
DSOP_DOWNLEVEL_FILTER_ANONYMOUS = (-2147483584)
DSOP_DOWNLEVEL_FILTER_BATCH = (-2147483520)
DSOP_DOWNLEVEL_FILTER_CREATOR_OWNER = (-2147483392)
DSOP_DOWNLEVEL_FILTER_CREATOR_GROUP = (-2147483136)
DSOP_DOWNLEVEL_FILTER_DIALUP = (-2147482624)
DSOP_DOWNLEVEL_FILTER_INTERACTIVE = (-2147481600)
DSOP_DOWNLEVEL_FILTER_NETWORK = (-2147479552)
DSOP_DOWNLEVEL_FILTER_SERVICE = (-2147475456)
DSOP_DOWNLEVEL_FILTER_SYSTEM = (-2147467264)
DSOP_DOWNLEVEL_FILTER_EXCLUDE_BUILTIN_GROUPS = (-2147450880)
DSOP_DOWNLEVEL_FILTER_TERMINAL_SERVER = (-2147418112)
DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS = (-2147352576)
DSOP_DOWNLEVEL_FILTER_LOCAL_SERVICE = (-2147221504)
DSOP_DOWNLEVEL_FILTER_NETWORK_SERVICE = (-2146959360)
DSOP_DOWNLEVEL_FILTER_REMOTE_LOGON = (-2146435072)
DSOP_FLAG_MULTISELECT = 0x00000001
DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK = 0x00000002
CFSTR_DSOP_DS_SELECTION_LIST = "CFSTR_DSOP_DS_SELECTION_LIST"

View file

@ -0,0 +1,58 @@
# A demo for the IDsObjectPicker interface.
import win32clipboard
import pythoncom
from win32com.adsi import adsi
from win32com.adsi.adsicon import *
cf_objectpicker = win32clipboard.RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST)
def main():
hwnd = 0
# Create an instance of the object picker.
picker = pythoncom.CoCreateInstance(adsi.CLSID_DsObjectPicker,
None,
pythoncom.CLSCTX_INPROC_SERVER,
adsi.IID_IDsObjectPicker)
# Create our scope init info.
siis = adsi.DSOP_SCOPE_INIT_INFOs(1)
sii = siis[0]
# Combine multiple scope types in a single array entry.
sii.type = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN | \
DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN
# Set uplevel and downlevel filters to include only computer objects.
# Uplevel filters apply to both mixed and native modes.
# Notice that the uplevel and downlevel flags are different.
sii.filterFlags.uplevel.bothModes = DSOP_FILTER_COMPUTERS
sii.filterFlags.downlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS
# Initialize the interface.
picker.Initialize(
None, # Target is the local computer.
siis, # scope infos
DSOP_FLAG_MULTISELECT, # options
('objectGUID','displayName') ) # attributes to fetch
do = picker.InvokeDialog(hwnd)
# Extract the data from the IDataObject.
format_etc = (cf_objectpicker, None,
pythoncom.DVASPECT_CONTENT, -1,
pythoncom.TYMED_HGLOBAL)
medium = do.GetData(format_etc)
data = adsi.StringAsDS_SELECTION_LIST(medium.data)
for item in data:
name, klass, adspath, upn, attrs, flags = item
print("Item", name)
print(" Class:", klass)
print(" AdsPath:", adspath)
print(" UPN:", upn)
print(" Attrs:", attrs)
print(" Flags:", flags)
if __name__=='__main__':
main()

View file

@ -0,0 +1,492 @@
"""A re-implementation of the MS DirectoryService samples related to services.
* Adds and removes an ActiveDirectory "Service Connection Point",
including managing the security on the object.
* Creates and registers Service Principal Names.
* Changes the username for a domain user.
Some of these functions are likely to become move to a module - but there
is also a little command-line-interface to try these functions out.
For example:
scp.py --account-name=domain\\user --service-class=PythonScpTest \\
--keyword=foo --keyword=bar --binding-string=bind_info \\
ScpCreate SpnCreate SpnRegister
would:
* Attempt to delete a Service Connection Point for the service class
'PythonScpTest'
* Attempt to create a Service Connection Point for that class, with 2
keywords and a binding string of 'bind_info'
* Create a Service Principal Name for the service and register it
to undo those changes, you could execute:
scp.py --account-name=domain\\user --service-class=PythonScpTest \\
SpnCreate SpnUnregister ScpDelete
which will:
* Create a SPN
* Unregister that SPN from the Active Directory.
* Delete the Service Connection Point
Executing with --test will create and remove one of everything.
"""
from win32com.adsi.adsicon import *
from win32com.adsi import adsi
import win32api, win32con, winerror
from win32com.client import Dispatch
import ntsecuritycon as dscon
import win32security
import optparse, textwrap
import traceback
verbose = 1
g_createdSCP = None
g_createdSPNs = []
g_createdSPNLast = None
import logging
logger = logging # use logging module global methods for now.
# still a bit confused about log(n, ...) vs logger.info/debug()
# Returns distinguished name of SCP.
def ScpCreate(
service_binding_info,
service_class_name, # Service class string to store in SCP.
account_name = None, # Logon account that needs access to SCP.
container_name = None,
keywords = None,
object_class = "serviceConnectionPoint",
dns_name_type = "A",
dn = None,
dns_name = None,
):
container_name = container_name or service_class_name
if not dns_name:
# Get the DNS name of the local computer
dns_name = win32api.GetComputerNameEx(win32con.ComputerNameDnsFullyQualified)
# Get the distinguished name of the computer object for the local computer
if dn is None:
dn = win32api.GetComputerObjectName(win32con.NameFullyQualifiedDN)
# Compose the ADSpath and bind to the computer object for the local computer
comp = adsi.ADsGetObject("LDAP://" + dn, adsi.IID_IDirectoryObject)
# Publish the SCP as a child of the computer object
keywords = keywords or []
# Fill in the attribute values to be stored in the SCP.
attrs = [
("cn", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (container_name,)),
("objectClass", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (object_class,)),
("keywords", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, keywords),
("serviceDnsName", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (dns_name,)),
("serviceDnsNameType", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (dns_name_type,)),
("serviceClassName", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (service_class_name,)),
("serviceBindingInformation", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (service_binding_info,)),
]
new = comp.CreateDSObject("cn=" + container_name, attrs)
logger.info("New connection point is at %s", container_name)
# Wrap in a usable IDispatch object.
new = Dispatch(new)
# And allow access to the SCP for the specified account name
AllowAccessToScpProperties(account_name, new)
return new
def ScpDelete(container_name, dn = None):
if dn is None:
dn = win32api.GetComputerObjectName(win32con.NameFullyQualifiedDN)
logger.debug("Removing connection point '%s' from %s", container_name, dn)
# Compose the ADSpath and bind to the computer object for the local computer
comp = adsi.ADsGetObject("LDAP://" + dn, adsi.IID_IDirectoryObject)
comp.DeleteDSObject("cn=" + container_name)
logger.info("Deleted service connection point '%s'", container_name)
# This function is described in detail in the MSDN article titled
# "Enabling Service Account to Access SCP Properties"
# From that article:
# The following sample code sets a pair of ACEs on a service connection point
# (SCP) object. The ACEs grant read/write access to the user or computer account
# under which the service instance will be running. Your service installation
# program calls this code to ensure that the service will be allowed to update
# its properties at run time. If you don't set ACEs like these, your service
# will get access-denied errors if it tries to modify the SCP's properties.
#
# The code uses the IADsSecurityDescriptor, IADsAccessControlList, and
# IADsAccessControlEntry interfaces to do the following:
# * Get the SCP object's security descriptor.
# * Set ACEs in the DACL of the security descriptor.
# * Set the security descriptor back on the SCP object.
def AllowAccessToScpProperties(
accountSAM, #Service account to allow access.
scpObject, # The IADs SCP object.
schemaIDGUIDs = # Attributes to allow write-access to.
("{28630eb8-41d5-11d1-a9c1-0000f80367c1}", # serviceDNSName
"{b7b1311c-b82e-11d0-afee-0000f80367c1}", # serviceBindingInformation
)
):
# If no service account is specified, service runs under LocalSystem.
# So allow access to the computer account of the service's host.
if accountSAM:
trustee = accountSAM
else:
# Get the SAM account name of the computer object for the server.
trustee = win32api.GetComputerObjectName(win32con.NameSamCompatible)
# Get the nTSecurityDescriptor attribute
attribute = "nTSecurityDescriptor"
sd = getattr(scpObject, attribute)
acl = sd.DiscretionaryAcl
for sguid in schemaIDGUIDs:
ace = Dispatch(adsi.CLSID_AccessControlEntry)
# Set the properties of the ACE.
# Allow read and write access to the property.
ace.AccessMask = ADS_RIGHT_DS_READ_PROP | ADS_RIGHT_DS_WRITE_PROP
# Set the trustee, which is either the service account or the
# host computer account.
ace.Trustee = trustee
# Set the ACE type.
ace.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
# Set AceFlags to zero because ACE is not inheritable.
ace.AceFlags = 0
# Set Flags to indicate an ACE that protects a specified object.
ace.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
# Set ObjectType to the schemaIDGUID of the attribute.
ace.ObjectType = sguid
# Add the ACEs to the DACL.
acl.AddAce(ace)
# Write the modified DACL back to the security descriptor.
sd.DiscretionaryAcl = acl
# Write the ntSecurityDescriptor property to the property cache.
setattr(scpObject, attribute, sd)
# SetInfo updates the SCP object in the directory.
scpObject.SetInfo()
logger.info("Set security on object for account '%s'" % (trustee,))
# Service Principal Names functions from the same sample.
# The example calls the DsWriteAccountSpn function, which stores the SPNs in
# Microsoft Active Directory under the servicePrincipalName attribute of the
# account object specified by the serviceAcctDN parameter. The account object
# corresponds to the logon account specified in the CreateService call for this
# service instance. If the logon account is a domain user account,
# serviceAcctDN must be the distinguished name of the account object in
# Active Directory for that user account. If the service's logon account is the
# LocalSystem account, serviceAcctDN must be the distinguished name of the
# computer account object for the host computer on which the service is
# installed. win32api.TranslateNames and win32security.DsCrackNames can
# be used to convert a domain\account format name to a distinguished name.
def SpnRegister(
serviceAcctDN, # DN of the service's logon account
spns, # List of SPNs to register
operation, # Add, replace, or delete SPNs
):
assert type(spns) not in [str, str] and hasattr(spns, "__iter__"), \
"spns must be a sequence of strings (got %r)" % spns
# Bind to a domain controller.
# Get the domain for the current user.
samName = win32api.GetUserNameEx(win32api.NameSamCompatible)
samName = samName.split('\\', 1)[0]
if not serviceAcctDN:
# Get the SAM account name of the computer object for the server.
serviceAcctDN = win32api.GetComputerObjectName(win32con.NameFullyQualifiedDN)
logger.debug("SpnRegister using DN '%s'", serviceAcctDN)
# Get the name of a domain controller in that domain.
info = win32security.DsGetDcName(
domainName=samName,
flags=dscon.DS_IS_FLAT_NAME |
dscon.DS_RETURN_DNS_NAME |
dscon.DS_DIRECTORY_SERVICE_REQUIRED)
# Bind to the domain controller.
handle = win32security.DsBind( info['DomainControllerName'] )
# Write the SPNs to the service account or computer account.
logger.debug("DsWriteAccountSpn with spns %s")
win32security.DsWriteAccountSpn(
handle, # handle to the directory
operation, # Add or remove SPN from account's existing SPNs
serviceAcctDN, # DN of service account or computer account
spns) # names
# Unbind the DS in any case (but Python would do it anyway)
handle.Close()
def UserChangePassword(username_dn, new_password):
# set the password on the account.
# Use the distinguished name to bind to the account object.
accountPath = "LDAP://" + username_dn
user = adsi.ADsGetObject(accountPath, adsi.IID_IADsUser)
# Set the password on the account.
user.SetPassword(new_password)
# functions related to the command-line interface
def log(level, msg, *args):
if verbose >= level:
print(msg % args)
class _NoDefault: pass
def _get_option(po, opt_name, default = _NoDefault):
parser, options = po
ret = getattr(options, opt_name, default)
if not ret and default is _NoDefault:
parser.error("The '%s' option must be specified for this operation" % opt_name)
if not ret:
ret = default
return ret
def _option_error(po, why):
parser = po[0]
parser.error(why)
def do_ScpCreate(po):
"""Create a Service Connection Point"""
global g_createdSCP
scp = ScpCreate(_get_option(po, "binding_string"),
_get_option(po, "service_class"),
_get_option(po, "account_name_sam", None),
keywords=_get_option(po, "keywords", None))
g_createdSCP = scp
return scp.distinguishedName
def do_ScpDelete(po):
"""Delete a Service Connection Point"""
sc = _get_option(po, "service_class")
try:
ScpDelete(sc)
except adsi.error as details:
if details[0] != winerror.ERROR_DS_OBJ_NOT_FOUND:
raise
log(2, "ScpDelete ignoring ERROR_DS_OBJ_NOT_FOUND for service-class '%s'",
sc)
return sc
def do_SpnCreate(po):
"""Create a Service Principal Name"""
# The 'service name' is the dn of our scp.
if g_createdSCP is None:
# Could accept an arg to avoid this?
_option_error(po, "ScpCreate must have been specified before SpnCreate")
# Create a Service Principal Name"
spns = win32security.DsGetSpn(dscon.DS_SPN_SERVICE,
_get_option(po, "service_class"),
g_createdSCP.distinguishedName,
_get_option(po, "port", 0),
None, None)
spn = spns[0]
log(2, "Created SPN: %s", spn)
global g_createdSPNLast
g_createdSPNLast = spn
g_createdSPNs.append(spn)
return spn
def do_SpnRegister(po):
"""Register a previously created Service Principal Name"""
if not g_createdSPNLast:
_option_error(po, "SpnCreate must appear before SpnRegister")
SpnRegister(_get_option(po, "account_name_dn", None),
(g_createdSPNLast,),
dscon.DS_SPN_ADD_SPN_OP)
return g_createdSPNLast
def do_SpnUnregister(po):
"""Unregister a previously created Service Principal Name"""
if not g_createdSPNLast:
_option_error(po, "SpnCreate must appear before SpnUnregister")
SpnRegister(_get_option(po, "account_name_dn", None),
(g_createdSPNLast,),
dscon.DS_SPN_DELETE_SPN_OP)
return g_createdSPNLast
def do_UserChangePassword(po):
"""Change the password for a specified user"""
UserChangePassword(_get_option(po, "account_name_dn"),
_get_option(po, "password"))
return "Password changed OK"
handlers = (
('ScpCreate', do_ScpCreate),
('ScpDelete', do_ScpDelete),
('SpnCreate', do_SpnCreate),
('SpnRegister', do_SpnRegister),
('SpnUnregister', do_SpnUnregister),
('UserChangePassword', do_UserChangePassword),
)
class HelpFormatter(optparse.IndentedHelpFormatter):
def format_description(self, description):
return description
def main():
global verbose
_handlers_dict = {}
arg_descs = []
for arg, func in handlers:
this_desc = "\n".join(textwrap.wrap(func.__doc__,
subsequent_indent = " " * 8))
arg_descs.append(" %s: %s" % (arg, this_desc))
_handlers_dict[arg.lower()] = func
description = __doc__ + "\ncommands:\n" + "\n".join(arg_descs) + "\n"
parser = optparse.OptionParser(usage = "%prog [options] command ...",
description=description,
formatter=HelpFormatter())
parser.add_option("-v", action="count",
dest="verbose", default=1,
help="increase the verbosity of status messages")
parser.add_option("-q", "--quiet", action="store_true",
help="Don't print any status messages")
parser.add_option("-t", "--test", action="store_true",
help="Execute a mini-test suite, providing defaults for most options and args"),
parser.add_option("", "--show-tracebacks", action="store_true",
help="Show the tracebacks for any exceptions")
parser.add_option("", "--service-class",
help="The service class name to use")
parser.add_option("", "--port", default=0,
help="The port number to associate with the SPN")
parser.add_option("", "--binding-string",
help="The binding string to use for SCP creation")
parser.add_option("", "--account-name",
help="The account name to use (default is LocalSystem)")
parser.add_option("", "--password",
help="The password to set.")
parser.add_option("", "--keyword", action="append", dest="keywords",
help="""A keyword to add to the SCP. May be specified
multiple times""")
parser.add_option("", "--log-level",
help="""The log-level to use - may be a number or a logging
module constant""", default=str(logging.WARNING))
options, args = parser.parse_args()
po = (parser, options)
# fixup misc
try:
options.port = int(options.port)
except (TypeError, ValueError):
parser.error("--port must be numeric")
# fixup log-level
try:
log_level = int(options.log_level)
except (TypeError, ValueError):
try:
log_level = int(getattr(logging, options.log_level.upper()))
except (ValueError, TypeError, AttributeError):
parser.error("Invalid --log-level value")
try:
sl = logger.setLevel
# logger is a real logger
except AttributeError:
# logger is logging module
sl = logging.getLogger().setLevel
sl(log_level)
# Check -q/-v
if options.quiet and options.verbose:
parser.error("Can't specify --quiet and --verbose")
if options.quiet:
options.verbose -= 1
verbose = options.verbose
# --test
if options.test:
if args:
parser.error("Can't specify args with --test")
args = "ScpDelete ScpCreate SpnCreate SpnRegister SpnUnregister ScpDelete"
log(1, "--test - pretending args are:\n %s", args)
args = args.split()
if not options.service_class:
options.service_class = "PythonScpTest"
log(2, "--test: --service-class=%s", options.service_class)
if not options.keywords:
options.keywords = "Python Powered".split()
log(2, "--test: --keyword=%s", options.keywords)
if not options.binding_string:
options.binding_string = "test binding string"
log(2, "--test: --binding-string=%s", options.binding_string)
# check args
if not args:
parser.error("No command specified (use --help for valid commands)")
for arg in args:
if arg.lower() not in _handlers_dict:
parser.error("Invalid command '%s' (use --help for valid commands)" % arg)
# Patch up account-name.
if options.account_name:
log(2, "Translating account name '%s'", options.account_name)
options.account_name_sam = win32security.TranslateName(options.account_name,
win32api.NameUnknown,
win32api.NameSamCompatible)
log(2, "NameSamCompatible is '%s'",options.account_name_sam)
options.account_name_dn = win32security.TranslateName(options.account_name,
win32api.NameUnknown,
win32api.NameFullyQualifiedDN)
log(2, "NameFullyQualifiedDNis '%s'",options.account_name_dn)
# do it.
for arg in args:
handler = _handlers_dict[arg.lower()] # already been validated
if handler is None:
parser.error("Invalid command '%s'" % arg)
err_msg = None
try:
try:
log(2, "Executing '%s'...", arg)
result = handler(po)
log(1, "%s: %s", arg, result)
except:
if options.show_tracebacks:
print("--show-tracebacks specified - dumping exception")
traceback.print_exc()
raise
except adsi.error as xxx_todo_changeme:
(hr, desc, exc, argerr) = xxx_todo_changeme.args
if exc:
extra_desc = exc[2]
else:
extra_desc = ""
err_msg = desc
if extra_desc:
err_msg += "\n\t" + extra_desc
except win32api.error as xxx_todo_changeme1:
(hr, func, msg) = xxx_todo_changeme1.args
err_msg = msg
if err_msg:
log(1, "Command '%s' failed: %s", arg, err_msg)
if __name__=='__main__':
try:
main()
except KeyboardInterrupt:
print("*** Interrupted")

View file

@ -0,0 +1,132 @@
from win32com.adsi import adsi
from win32com.adsi.adsicon import *
from win32com.adsi import adsicon
import pythoncom, pywintypes, win32security
options = None # set to optparse options object
ADsTypeNameMap = {}
def getADsTypeName(type_val):
# convert integer type to the 'typename' as known in the headerfiles.
if not ADsTypeNameMap:
for n, v in adsicon.__dict__.items():
if n.startswith("ADSTYPE_"):
ADsTypeNameMap[v] = n
return ADsTypeNameMap.get(type_val, hex(type_val))
def _guid_from_buffer(b):
return pywintypes.IID(b, True)
def _sid_from_buffer(b):
return str(pywintypes.SID(b))
_null_converter = lambda x: x
converters = {
'objectGUID' : _guid_from_buffer,
'objectSid' : _sid_from_buffer,
'instanceType' : getADsTypeName,
}
def log(level, msg, *args):
if options.verbose >= level:
print("log:", msg % args)
def getGC():
cont = adsi.ADsOpenObject("GC:", options.user, options.password, 0, adsi.IID_IADsContainer)
enum = adsi.ADsBuildEnumerator(cont)
# Only 1 child of the global catalog.
for e in enum:
gc = e.QueryInterface(adsi.IID_IDirectorySearch)
return gc
return None
def print_attribute(col_data):
prop_name, prop_type, values = col_data
if values is not None:
log(2, "property '%s' has type '%s'", prop_name, getADsTypeName(prop_type))
value = [converters.get(prop_name, _null_converter)(v[0]) for v in values]
if len(value) == 1:
value = value[0]
print(" %s=%r" % (prop_name, value))
else:
print(" %s is None" % (prop_name,))
def search():
gc = getGC()
if gc is None:
log(0, "Can't find the global catalog")
return
prefs = [(ADS_SEARCHPREF_SEARCH_SCOPE, (ADS_SCOPE_SUBTREE,))]
hr, statuses = gc.SetSearchPreference(prefs)
log(3, "SetSearchPreference returned %d/%r", hr, statuses)
if options.attributes:
attributes = options.attributes.split(",")
else:
attributes = None
h = gc.ExecuteSearch(options.filter, attributes)
hr = gc.GetNextRow(h)
while hr != S_ADS_NOMORE_ROWS:
print("-- new row --")
if attributes is None:
# Loop over all columns returned
while 1:
col_name = gc.GetNextColumnName(h)
if col_name is None:
break
data = gc.GetColumn(h, col_name)
print_attribute(data)
else:
# loop over attributes specified.
for a in attributes:
try:
data = gc.GetColumn(h, a)
print_attribute(data)
except adsi.error as details:
if details[0] != E_ADS_COLUMN_NOT_SET:
raise
print_attribute( (a, None, None) )
hr = gc.GetNextRow(h)
gc.CloseSearchHandle(h)
def main():
global options
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
help="write report to FILE", metavar="FILE")
parser.add_option("-v", "--verbose",
action="count", default=1,
help="increase verbosity of output")
parser.add_option("-q", "--quiet",
action="store_true",
help="suppress output messages")
parser.add_option("-U", "--user",
help="specify the username used to connect")
parser.add_option("-P", "--password",
help="specify the password used to connect")
parser.add_option("", "--filter",
default = "(&(objectCategory=person)(objectClass=User))",
help="specify the search filter")
parser.add_option("", "--attributes",
help="comma sep'd list of attribute names to print")
options, args = parser.parse_args()
if options.quiet:
if options.verbose != 1:
parser.error("Can not use '--verbose' and '--quiet'")
options.verbose = 0
if args:
parser.error("You need not specify args")
search()
if __name__=='__main__':
main()

View file

@ -0,0 +1,247 @@
import sys, string
import pythoncom
import win32api
from win32com.adsi import *
verbose_level = 0
server = '' # Must have trailing /
local_name = win32api.GetComputerName()
def DumpRoot():
"Dumps the root DSE"
path = "LDAP://%srootDSE" % server
rootdse = ADsGetObject(path)
for item in rootdse.Get("SupportedLDAPVersion"):
print("%s supports ldap version %s" % (path, item))
attributes = ["CurrentTime", "defaultNamingContext"]
for attr in attributes:
val = rootdse.Get(attr)
print(" %s=%s" % (attr, val))
###############################################
#
# Code taken from article titled:
# Reading attributeSchema and classSchema Objects
def _DumpClass(child):
attrs = "Abstract lDAPDisplayName schemaIDGUID schemaNamingContext attributeSyntax oMSyntax"
_DumpTheseAttributes(child, string.split(attrs))
def _DumpAttribute(child):
attrs = "lDAPDisplayName schemaIDGUID adminDescription adminDisplayName rDNAttID defaultHidingValue defaultObjectCategory systemOnly defaultSecurityDescriptor"
_DumpTheseAttributes(child, string.split(attrs))
def _DumpTheseAttributes(child, attrs):
for attr in attrs:
try:
val = child.Get(attr)
except pythoncom.com_error as details:
continue
# ###
(hr, msg, exc, arg) = details
if exc and exc[2]: msg = exc[2]
val = "<Error: %s>" % (msg,)
if verbose_level >= 2:
print(" %s: %s=%s" % (child.Class, attr, val))
def DumpSchema():
"Dumps the default DSE schema"
# Bind to rootDSE to get the schemaNamingContext property.
path = "LDAP://%srootDSE" % server
rootdse = ADsGetObject(path)
name = rootdse.Get("schemaNamingContext")
# Bind to the actual schema container.
path= "LDAP://" + server + name
print("Binding to", path)
ob = ADsGetObject(path)
nclasses = nattr = nsub = nunk = 0
# Enumerate the attribute and class objects in the schema container.
for child in ob:
# Find out if this is a class, attribute, or subSchema object.
class_name = child.Class
if class_name == "classSchema":
_DumpClass(child)
nclasses = nclasses + 1
elif class_name == "attributeSchema":
_DumpAttribute(child)
nattr = nattr + 1
elif class_name == "subSchema":
nsub = nsub + 1
else:
print("Unknown class:", class_name)
nunk = nunk + 1
if verbose_level:
print("Processed", nclasses, "classes")
print("Processed", nattr, "attributes")
print("Processed", nsub, "sub-schema's")
print("Processed", nunk, "unknown types")
def _DumpObject(ob, level = 0):
prefix = " " * level
print("%s%s object: %s" % (prefix, ob.Class, ob.Name))
# Do the directory object thing
try:
dir_ob = ADsGetObject(ob.ADsPath, IID_IDirectoryObject)
except pythoncom.com_error:
dir_ob = None
if dir_ob is not None:
info = dir_ob.GetObjectInformation()
print("%s RDN='%s', ObjectDN='%s'" % (prefix, info.RDN, info.ObjectDN))
# Create a list of names to fetch
names = ["distinguishedName"]
attrs = dir_ob.GetObjectAttributes(names)
for attr in attrs:
for val, typ in attr.Values:
print("%s Attribute '%s' = %s" % (prefix, attr.AttrName, val))
for child in ob:
_DumpObject(child, level+1)
def DumpAllObjects():
"Recursively dump the entire directory!"
path = "LDAP://%srootDSE" % server
rootdse = ADsGetObject(path)
name = rootdse.Get("defaultNamingContext")
# Bind to the actual schema container.
path= "LDAP://" + server + name
print("Binding to", path)
ob = ADsGetObject(path)
# Enumerate the attribute and class objects in the schema container.
_DumpObject(ob)
##########################################################
#
# Code taken from article:
# Example Code for Enumerating Schema Classes, Attributes, and Syntaxes
# Fill a map with VT_ datatypes, to give us better names:
vt_map = {}
for name, val in pythoncom.__dict__.items():
if name[:3] == "VT_":
vt_map[val] = name
def DumpSchema2():
"Dumps the schema using an alternative technique"
path = "LDAP://%sschema" % (server,)
schema = ADsGetObject(path, IID_IADsContainer)
nclass = nprop = nsyntax = 0
for item in schema:
item_class = string.lower(item.Class)
if item_class == "class":
items = []
if item.Abstract: items.append("Abstract")
if item.Auxiliary: items.append("Auxiliary")
# if item.Structural: items.append("Structural")
desc = string.join(items, ", ")
import win32com.util
iid_name = win32com.util.IIDToInterfaceName(item.PrimaryInterface)
if verbose_level >= 2:
print("Class: Name=%s, Flags=%s, Primary Interface=%s" % (item.Name, desc, iid_name))
nclass = nclass + 1
elif item_class == "property":
if item.MultiValued:
val_type = "Multi-Valued"
else:
val_type = "Single-Valued"
if verbose_level >= 2:
print("Property: Name=%s, %s" % (item.Name, val_type))
nprop = nprop + 1
elif item_class == "syntax":
data_type = vt_map.get(item.OleAutoDataType, "<unknown type>")
if verbose_level >= 2:
print("Syntax: Name=%s, Datatype = %s" % (item.Name, data_type))
nsyntax = nsyntax + 1
if verbose_level >= 1:
print("Processed", nclass, "classes")
print("Processed", nprop, "properties")
print("Processed", nsyntax, "syntax items")
def DumpGC():
"Dumps the GC: object (whatever that is!)"
ob = ADsGetObject("GC:", IID_IADsContainer)
for sub_ob in ob:
print("GC ob: %s (%s)" % (sub_ob.Name, sub_ob.ADsPath))
def DumpLocalUsers():
"Dumps the local machine users"
path = "WinNT://%s,computer" % (local_name,)
ob = ADsGetObject(path, IID_IADsContainer)
ob.put_Filter(["User", "Group"])
for sub_ob in ob:
print("User/Group: %s (%s)" % (sub_ob.Name, sub_ob.ADsPath))
def DumpLocalGroups():
"Dumps the local machine groups"
path = "WinNT://%s,computer" % (local_name,)
ob = ADsGetObject(path, IID_IADsContainer)
ob.put_Filter(["Group"])
for sub_ob in ob:
print("Group: %s (%s)" % (sub_ob.Name, sub_ob.ADsPath))
# get the members
members = sub_ob.Members()
for member in members:
print(" Group member: %s (%s)" % (member.Name, member.ADsPath))
def usage(tests):
import os
print("Usage: %s [-s server ] [-v] [Test ...]" % os.path.basename(sys.argv[0]))
print(" -v : Verbose - print more information")
print(" -s : server - execute the tests against the named server")
print("where Test is one of:")
for t in tests:
print(t.__name__,":", t.__doc__)
print()
print("If not tests are specified, all tests are run")
sys.exit(1)
def main():
import getopt, traceback
tests = []
for ob in globals().values():
if type(ob)==type(main) and ob.__doc__:
tests.append(ob)
opts, args = getopt.getopt(sys.argv[1:], "s:hv")
for opt, val in opts:
if opt=="-s":
if val[-1] not in "\\/":
val = val + "/"
global server
server = val
if opt=="-h":
usage(tests)
if opt=="-v":
global verbose_level
verbose_level = verbose_level + 1
if len(args)==0:
print("Running all tests - use '-h' to see command-line options...")
dotests = tests
else:
dotests = []
for arg in args:
for t in tests:
if t.__name__==arg:
dotests.append(t)
break
else:
print("Test '%s' unknown - skipping" % arg)
if not len(dotests):
print("Nothing to do!")
usage(tests)
for test in dotests:
try:
test()
except:
print("Test %s failed" % test.__name__)
traceback.print_exc()
if __name__=='__main__':
main()

View file

@ -0,0 +1,6 @@
# This is a python package
# __PackageSupportBuildPath__ not needed for distutil based builds,
# but not everyone is there yet.
import win32com
win32com.__PackageSupportBuildPath__(__path__)

View file

@ -0,0 +1,140 @@
import os
import win32com.server.policy
import win32security, ntsecuritycon, win32con
import pythoncom, win32api
from win32com.authorization import authorization
from ntsecuritycon import FILE_READ_ATTRIBUTES, FILE_READ_DATA, FILE_READ_EA, SYNCHRONIZE,\
STANDARD_RIGHTS_READ, STANDARD_RIGHTS_WRITE, STANDARD_RIGHTS_EXECUTE, FILE_APPEND_DATA, \
FILE_WRITE_ATTRIBUTES, FILE_WRITE_DATA, FILE_WRITE_EA, WRITE_OWNER, WRITE_DAC, READ_CONTROL, \
SI_ADVANCED, SI_EDIT_AUDITS, SI_EDIT_PROPERTIES, SI_EDIT_ALL, SI_PAGE_TITLE, SI_RESET, \
SI_ACCESS_SPECIFIC, SI_ACCESS_GENERAL, SI_ACCESS_CONTAINER, SI_ACCESS_PROPERTY, \
FILE_ALL_ACCESS, FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, \
OBJECT_INHERIT_ACE, CONTAINER_INHERIT_ACE, INHERIT_ONLY_ACE, \
SI_PAGE_PERM, SI_PAGE_ADVPERM, SI_PAGE_AUDIT, SI_PAGE_OWNER, PSPCB_SI_INITDIALOG, \
SI_CONTAINER
from win32security import OBJECT_INHERIT_ACE, CONTAINER_INHERIT_ACE, INHERIT_ONLY_ACE
from win32com.shell.shellcon import PSPCB_RELEASE, PSPCB_CREATE ## Msg parameter to PropertySheetPageCallback
from pythoncom import IID_NULL
class SecurityInformation(win32com.server.policy.DesignatedWrapPolicy):
_com_interfaces_=[authorization.IID_ISecurityInformation]
_public_methods_=['GetObjectInformation','GetSecurity','SetSecurity','GetAccessRights',
'GetInheritTypes','MapGeneric','PropertySheetPageCallback']
def __init__(self, FileName):
self.FileName=FileName
self._wrap_(self)
def GetObjectInformation(self):
"""Identifies object whose security will be modified, and determines options available
to the end user"""
flags=SI_ADVANCED|SI_EDIT_ALL|SI_PAGE_TITLE|SI_RESET
if os.path.isdir(self.FileName):
flags|=SI_CONTAINER
hinstance=0 ## handle to module containing string resources
servername='' ## name of authenticating server if not local machine
objectname=os.path.split(self.FileName)[1]
pagetitle='Python ACL Editor'
if os.path.isdir(self.FileName):
pagetitle+=' (dir)'
else:
pagetitle+=' (file)'
objecttype=IID_NULL
return flags, hinstance, servername, objectname, pagetitle, objecttype
def GetSecurity(self, requestedinfo, bdefault):
"""Requests the existing permissions for object"""
if bdefault:
## This is invoked if the 'Default' button is pressed (only present if SI_RESET is passed
## with the flags in GetObjectInfo). Passing an empty SD with a NULL Dacl
## should cause inherited ACL from parent dir or default dacl from user's token to be used
return win32security.SECURITY_DESCRIPTOR()
else:
## GetFileSecurity sometimes fails to return flags indicating that an ACE is inherited
return win32security.GetNamedSecurityInfo(self.FileName, win32security.SE_FILE_OBJECT, requestedinfo)
def SetSecurity(self, requestedinfo, sd):
"""Applies permissions to the object"""
owner=sd.GetSecurityDescriptorOwner()
group=sd.GetSecurityDescriptorGroup()
dacl=sd.GetSecurityDescriptorDacl()
sacl=sd.GetSecurityDescriptorSacl()
win32security.SetNamedSecurityInfo(self.FileName, win32security.SE_FILE_OBJECT, requestedinfo,
owner, group, dacl, sacl)
## should also handle recursive operations here
def GetAccessRights(self, objecttype, flags):
"""Returns a tuple of (AccessRights, DefaultAccess), where AccessRights is a sequence of tuples representing
SI_ACCESS structs, containing (guid, access mask, Name, flags). DefaultAccess indicates which of the
AccessRights will be used initially when a new ACE is added (zero based).
Flags can contain SI_ACCESS_SPECIFIC,SI_ACCESS_GENERAL,SI_ACCESS_CONTAINER,SI_ACCESS_PROPERTY,
CONTAINER_INHERIT_ACE,INHERIT_ONLY_ACE,OBJECT_INHERIT_ACE
"""
## input flags: SI_ADVANCED,SI_EDIT_AUDITS,SI_EDIT_PROPERTIES indicating which property sheet is requesting the rights
if (objecttype is not None) and (objecttype!=IID_NULL):
## Should not be true for file objects. Usually only used with DS objects that support security for
## their properties
raise NotImplementedError("Object type is not supported")
if os.path.isdir(self.FileName):
file_append_data_desc='Create subfolders'
file_write_data_desc='Create Files'
else:
file_append_data_desc='Append data'
file_write_data_desc='Write data'
accessrights=[(IID_NULL, FILE_GENERIC_READ, 'Generic read', SI_ACCESS_GENERAL|SI_ACCESS_SPECIFIC|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
(IID_NULL, FILE_GENERIC_WRITE, 'Generic write', SI_ACCESS_GENERAL|SI_ACCESS_SPECIFIC|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
(IID_NULL, win32con.DELETE, 'Delete', SI_ACCESS_SPECIFIC|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
(IID_NULL, WRITE_OWNER, 'Change owner', SI_ACCESS_SPECIFIC|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
(IID_NULL, READ_CONTROL,'Read Permissions', SI_ACCESS_SPECIFIC|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
(IID_NULL, WRITE_DAC, 'Change permissions', SI_ACCESS_SPECIFIC|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
(IID_NULL, FILE_APPEND_DATA, file_append_data_desc, SI_ACCESS_SPECIFIC|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
(IID_NULL, FILE_WRITE_DATA, file_write_data_desc, SI_ACCESS_SPECIFIC|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE)
]
return (accessrights, 0)
def MapGeneric(self, guid, aceflags, mask):
""" Converts generic access rights to specific rights. This implementation uses standard file system rights,
but you can map them any way that suits your application.
"""
return win32security.MapGenericMask(mask, (FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS))
def GetInheritTypes(self):
"""Specifies which types of ACE inheritance are supported.
Returns a sequence of tuples representing SI_INHERIT_TYPE structs, containing
(object type guid, inheritance flags, display name). Guid is usually only used with
Directory Service objects.
"""
return ((IID_NULL, 0, 'Only current object'),
(IID_NULL, OBJECT_INHERIT_ACE, 'Files inherit permissions'),
(IID_NULL, CONTAINER_INHERIT_ACE, 'Sub Folders inherit permissions'),
(IID_NULL, CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE, 'Files and subfolders'),
)
def PropertySheetPageCallback(self, hwnd, msg, pagetype):
"""Invoked each time a property sheet page is created or destroyed."""
## page types from SI_PAGE_TYPE enum: SI_PAGE_PERM SI_PAGE_ADVPERM SI_PAGE_AUDIT SI_PAGE_OWNER
## msg: PSPCB_CREATE, PSPCB_RELEASE, PSPCB_SI_INITDIALOG
return None
def EditSecurity(self, owner_hwnd=0):
"""Creates an ACL editor dialog based on parameters returned by interface methods"""
isi=pythoncom.WrapObject(self, authorization.IID_ISecurityInformation, pythoncom.IID_IUnknown)
authorization.EditSecurity(owner_hwnd, isi)
## folder permissions
temp_dir=win32api.GetTempPath()
dir_name=win32api.GetTempFileName(temp_dir,'isi')[0]
print(dir_name)
os.remove(dir_name)
os.mkdir(dir_name)
si=SecurityInformation(dir_name)
si.EditSecurity()
## file permissions
fname=win32api.GetTempFileName(dir_name,'isi')[0]
si=SecurityInformation(fname)
si.EditSecurity()

View file

@ -0,0 +1,134 @@
"""
Implements a permissions editor for services.
Service can be specified as plain name for local machine,
or as a remote service of the form \\machinename\service
"""
import os
import win32com.server.policy
import win32security, ntsecuritycon, win32con
import pythoncom, win32api, win32service
from win32com.authorization import authorization
SERVICE_GENERIC_EXECUTE=win32service.SERVICE_START|win32service.SERVICE_STOP|win32service.SERVICE_PAUSE_CONTINUE|win32service.SERVICE_USER_DEFINED_CONTROL
SERVICE_GENERIC_READ=win32service.SERVICE_QUERY_CONFIG|win32service.SERVICE_QUERY_STATUS|win32service.SERVICE_INTERROGATE|win32service.SERVICE_ENUMERATE_DEPENDENTS
SERVICE_GENERIC_WRITE=win32service.SERVICE_CHANGE_CONFIG
from ntsecuritycon import STANDARD_RIGHTS_READ, STANDARD_RIGHTS_WRITE, STANDARD_RIGHTS_EXECUTE, \
WRITE_OWNER, WRITE_DAC, READ_CONTROL, \
SI_ADVANCED, SI_EDIT_AUDITS, SI_EDIT_PROPERTIES, SI_EDIT_ALL, SI_PAGE_TITLE, SI_RESET, \
SI_ACCESS_SPECIFIC, SI_ACCESS_GENERAL, SI_ACCESS_CONTAINER, SI_ACCESS_PROPERTY, \
OBJECT_INHERIT_ACE, CONTAINER_INHERIT_ACE, INHERIT_ONLY_ACE, \
SI_PAGE_PERM, SI_PAGE_ADVPERM, SI_PAGE_AUDIT, SI_PAGE_OWNER, PSPCB_SI_INITDIALOG, \
SI_CONTAINER
from win32security import OBJECT_INHERIT_ACE, CONTAINER_INHERIT_ACE, INHERIT_ONLY_ACE
from win32com.shell.shellcon import PSPCB_RELEASE, PSPCB_CREATE ## Msg parameter to PropertySheetPageCallback
from pythoncom import IID_NULL
class ServiceSecurity(win32com.server.policy.DesignatedWrapPolicy):
_com_interfaces_=[authorization.IID_ISecurityInformation]
_public_methods_=['GetObjectInformation','GetSecurity','SetSecurity','GetAccessRights',
'GetInheritTypes','MapGeneric','PropertySheetPageCallback']
def __init__(self, ServiceName):
self.ServiceName=ServiceName
self._wrap_(self)
def GetObjectInformation(self):
"""Identifies object whose security will be modified, and determines options available
to the end user"""
flags=SI_ADVANCED|SI_EDIT_ALL|SI_PAGE_TITLE|SI_RESET
hinstance=0 ## handle to module containing string resources
servername='' ## name of authenticating server if not local machine
## service name can contain remote machine name of the form \\Server\ServiceName
objectname=os.path.split(self.ServiceName)[1]
pagetitle='Service Permissions for '+self.ServiceName
objecttype=IID_NULL
return flags, hinstance, servername, objectname, pagetitle, objecttype
def GetSecurity(self, requestedinfo, bdefault):
"""Requests the existing permissions for object"""
if bdefault:
return win32security.SECURITY_DESCRIPTOR()
else:
return win32security.GetNamedSecurityInfo(self.ServiceName, win32security.SE_SERVICE, requestedinfo)
def SetSecurity(self, requestedinfo, sd):
"""Applies permissions to the object"""
owner=sd.GetSecurityDescriptorOwner()
group=sd.GetSecurityDescriptorGroup()
dacl=sd.GetSecurityDescriptorDacl()
sacl=sd.GetSecurityDescriptorSacl()
win32security.SetNamedSecurityInfo(self.ServiceName, win32security.SE_SERVICE, requestedinfo,
owner, group, dacl, sacl)
def GetAccessRights(self, objecttype, flags):
"""Returns a tuple of (AccessRights, DefaultAccess), where AccessRights is a sequence of tuples representing
SI_ACCESS structs, containing (guid, access mask, Name, flags). DefaultAccess indicates which of the
AccessRights will be used initially when a new ACE is added (zero based).
Flags can contain SI_ACCESS_SPECIFIC,SI_ACCESS_GENERAL,SI_ACCESS_CONTAINER,SI_ACCESS_PROPERTY,
CONTAINER_INHERIT_ACE,INHERIT_ONLY_ACE,OBJECT_INHERIT_ACE
"""
## input flags: SI_ADVANCED,SI_EDIT_AUDITS,SI_EDIT_PROPERTIES indicating which property sheet is requesting the rights
if (objecttype is not None) and (objecttype!=IID_NULL):
## Not relevent for services
raise NotImplementedError("Object type is not supported")
## ???? for some reason, the DACL for a service will not retain ACCESS_SYSTEM_SECURITY in an ACE ????
## (IID_NULL, win32con.ACCESS_SYSTEM_SECURITY, 'View/change audit settings', SI_ACCESS_SPECIFIC),
accessrights=[
(IID_NULL, win32service.SERVICE_ALL_ACCESS, 'Full control', SI_ACCESS_GENERAL),
(IID_NULL, SERVICE_GENERIC_READ, 'Generic read', SI_ACCESS_GENERAL),
(IID_NULL, SERVICE_GENERIC_WRITE, 'Generic write', SI_ACCESS_GENERAL),
(IID_NULL, SERVICE_GENERIC_EXECUTE, 'Start/Stop/Pause service', SI_ACCESS_GENERAL),
(IID_NULL, READ_CONTROL, 'Read Permissions', SI_ACCESS_GENERAL),
(IID_NULL, WRITE_DAC, 'Change permissions', SI_ACCESS_GENERAL),
(IID_NULL, WRITE_OWNER, 'Change owner', SI_ACCESS_GENERAL),
(IID_NULL, win32con.DELETE, 'Delete service', SI_ACCESS_GENERAL),
(IID_NULL, win32service.SERVICE_START, 'Start service', SI_ACCESS_SPECIFIC),
(IID_NULL, win32service.SERVICE_STOP, 'Stop service', SI_ACCESS_SPECIFIC),
(IID_NULL, win32service.SERVICE_PAUSE_CONTINUE, 'Pause/unpause service', SI_ACCESS_SPECIFIC),
(IID_NULL, win32service.SERVICE_USER_DEFINED_CONTROL, 'Execute user defined operations', SI_ACCESS_SPECIFIC),
(IID_NULL, win32service.SERVICE_QUERY_CONFIG, 'Read configuration', SI_ACCESS_SPECIFIC),
(IID_NULL, win32service.SERVICE_CHANGE_CONFIG, 'Change configuration', SI_ACCESS_SPECIFIC),
(IID_NULL, win32service.SERVICE_ENUMERATE_DEPENDENTS, 'List dependent services', SI_ACCESS_SPECIFIC),
(IID_NULL, win32service.SERVICE_QUERY_STATUS, 'Query status', SI_ACCESS_SPECIFIC),
(IID_NULL, win32service.SERVICE_INTERROGATE, 'Query status (immediate)', SI_ACCESS_SPECIFIC),
]
return (accessrights, 0)
def MapGeneric(self, guid, aceflags, mask):
""" Converts generic access rights to specific rights.
"""
return win32security.MapGenericMask(mask,
(SERVICE_GENERIC_READ, SERVICE_GENERIC_WRITE, SERVICE_GENERIC_EXECUTE, win32service.SERVICE_ALL_ACCESS))
def GetInheritTypes(self):
"""Specifies which types of ACE inheritance are supported.
Services don't use any inheritance
"""
return ((IID_NULL, 0, 'Only current object'),)
def PropertySheetPageCallback(self, hwnd, msg, pagetype):
"""Invoked each time a property sheet page is created or destroyed."""
## page types from SI_PAGE_TYPE enum: SI_PAGE_PERM SI_PAGE_ADVPERM SI_PAGE_AUDIT SI_PAGE_OWNER
## msg: PSPCB_CREATE, PSPCB_RELEASE, PSPCB_SI_INITDIALOG
return None
def EditSecurity(self, owner_hwnd=0):
"""Creates an ACL editor dialog based on parameters returned by interface methods"""
isi=pythoncom.WrapObject(self, authorization.IID_ISecurityInformation, pythoncom.IID_IUnknown)
authorization.EditSecurity(owner_hwnd, isi)
if __name__=='__main__':
# Find the first service on local machine and edit its permissions
scm = win32service.OpenSCManager(None, None, win32service.SC_MANAGER_ENUMERATE_SERVICE)
svcs=win32service.EnumServicesStatus(scm)
win32service.CloseServiceHandle(scm)
si=ServiceSecurity(svcs[0][0])
si.EditSecurity()

View file

@ -0,0 +1,4 @@
# See if we have a special directory for the binaries (for developers)
import win32com
win32com.__PackageSupportBuildPath__(__path__)

View file

@ -0,0 +1,3 @@
# See if we have a special directory for the binaries (for developers)
import win32com
win32com.__PackageSupportBuildPath__(__path__)

View file

@ -0,0 +1,416 @@
"""The glue between the Python debugger interface and the Active Debugger interface
"""
from win32com.axdebug.util import trace, _wrap, _wrap_remove
from win32com.server.util import unwrap
import win32com.client.connect
from . import gateways
import sys, bdb, traceback
from . import axdebug, stackframe
import win32api, pythoncom
import _thread, os
def fnull(*args):
pass
try:
os.environ["DEBUG_AXDEBUG"]
debugging = 1
except KeyError:
debugging = 0
traceenter = fnull # trace enter of functions
tracev = fnull # verbose trace
if debugging:
traceenter = trace # trace enter of functions
tracev = trace # verbose trace
class OutputReflector:
def __init__(self, file, writefunc):
self.writefunc = writefunc
self.file = file
def __getattr__(self,name):
return getattr(self.file, name)
def write(self,message):
self.writefunc(message)
self.file.write(message)
def _dumpf(frame):
if frame is None:
return "<None>"
else:
addn = "(with trace!)"
if frame.f_trace is None:
addn = " **No Trace Set **"
return "Frame at %d, file %s, line: %d%s" % (id(frame), frame.f_code.co_filename, frame.f_lineno, addn)
g_adb = None
def OnSetBreakPoint(codeContext, breakPointState, lineNo):
try:
fileName = codeContext.codeContainer.GetFileName()
# inject the code into linecache.
import linecache
linecache.cache[fileName] = 0, 0, codeContext.codeContainer.GetText(), fileName
g_adb._OnSetBreakPoint(fileName, codeContext, breakPointState, lineNo+1)
except:
traceback.print_exc()
class Adb(bdb.Bdb,gateways.RemoteDebugApplicationEvents):
def __init__(self):
self.debugApplication = None
self.debuggingThread = None
self.debuggingThreadStateHandle = None
self.stackSnifferCookie = self.stackSniffer = None
self.codeContainerProvider = None
self.debuggingThread = None
self.breakFlags = None
self.breakReason = None
self.appDebugger = None
self.appEventConnection = None
self.logicalbotframe = None # Anything at this level or below does not exist!
self.currentframe = None # The frame we are currently in.
self.recursiveData = [] # Data saved for each reentery on this thread.
bdb.Bdb.__init__(self)
self._threadprotectlock = _thread.allocate_lock()
self.reset()
def canonic(self, fname):
if fname[0]=='<':
return fname
return bdb.Bdb.canonic(self, fname)
def reset(self):
traceenter("adb.reset")
bdb.Bdb.reset(self)
def __xxxxx__set_break(self, filename, lineno, cond = None):
# As per standard one, except no linecache checking!
if filename not in self.breaks:
self.breaks[filename] = []
list = self.breaks[filename]
if lineno in list:
return 'There is already a breakpoint there!'
list.append(lineno)
if cond is not None: self.cbreaks[filename, lineno]=cond
def stop_here(self, frame):
traceenter("stop_here", _dumpf(frame), _dumpf(self.stopframe))
# As per bdb.stop_here, except for logicalbotframe
## if self.stopframe is None:
## return 1
if frame is self.stopframe:
return 1
tracev("stop_here said 'No'!")
return 0
def break_here(self, frame):
traceenter("break_here", self.breakFlags, _dumpf(frame))
self.breakReason = None
if self.breakFlags==axdebug.APPBREAKFLAG_DEBUGGER_HALT:
self.breakReason = axdebug.BREAKREASON_DEBUGGER_HALT
elif self.breakFlags==axdebug.APPBREAKFLAG_DEBUGGER_BLOCK:
self.breakReason = axdebug.BREAKREASON_DEBUGGER_BLOCK
elif self.breakFlags==axdebug.APPBREAKFLAG_STEP:
self.breakReason = axdebug.BREAKREASON_STEP
else:
print("Calling base 'break_here' with", self.breaks)
if bdb.Bdb.break_here(self, frame):
self.breakReason = axdebug.BREAKREASON_BREAKPOINT
return self.breakReason is not None
def break_anywhere(self, frame):
traceenter("break_anywhere", _dumpf(frame))
if self.breakFlags==axdebug.APPBREAKFLAG_DEBUGGER_HALT:
self.breakReason = axdebug.BREAKREASON_DEBUGGER_HALT
return 1
rc = bdb.Bdb.break_anywhere(self, frame)
tracev("break_anywhere",_dumpf(frame),"returning",rc)
return rc
def dispatch_return(self, frame, arg):
traceenter("dispatch_return", _dumpf(frame), arg)
if self.logicalbotframe is frame:
# We dont want to debug parent frames.
tracev("dispatch_return resetting sys.trace")
sys.settrace(None)
return
# self.bSetTrace = 0
self.currentframe = frame.f_back
return bdb.Bdb.dispatch_return(self, frame, arg)
def dispatch_line(self, frame):
traceenter("dispatch_line", _dumpf(frame), _dumpf(self.botframe))
# trace("logbotframe is", _dumpf(self.logicalbotframe), "botframe is", self.botframe)
if frame is self.logicalbotframe:
trace("dispatch_line", _dumpf(frame), "for bottom frame returing tracer")
# The next code executed in the frame above may be a builtin (eg, apply())
# in which sys.trace needs to be set.
sys.settrace(self.trace_dispatch)
# And return the tracer incase we are about to execute Python code,
# in which case sys tracer is ignored!
return self.trace_dispatch
if self.codeContainerProvider.FromFileName(frame.f_code.co_filename) is None:
trace("dispatch_line has no document for", _dumpf(frame), "- skipping trace!")
return None
self.currentframe = frame # So the stack sniffer knows our most recent, debuggable code.
return bdb.Bdb.dispatch_line(self, frame)
def dispatch_call(self, frame, arg):
traceenter("dispatch_call",_dumpf(frame))
frame.f_locals['__axstack_address__'] = axdebug.GetStackAddress()
if frame is self.botframe:
trace("dispatch_call is self.botframe - returning tracer")
return self.trace_dispatch
# Not our bottom frame. If we have a document for it,
# then trace it, otherwise run at full speed.
if self.codeContainerProvider.FromFileName(frame.f_code.co_filename) is None:
trace("dispatch_call has no document for", _dumpf(frame), "- skipping trace!")
## sys.settrace(None)
return None
return self.trace_dispatch
# rc = bdb.Bdb.dispatch_call(self, frame, arg)
# trace("dispatch_call", _dumpf(frame),"returned",rc)
# return rc
def trace_dispatch(self, frame, event, arg):
traceenter("trace_dispatch", _dumpf(frame), event, arg)
if self.debugApplication is None:
trace("trace_dispatch has no application!")
return # None
return bdb.Bdb.trace_dispatch(self, frame, event, arg)
#
# The user functions do bugger all!
#
# def user_call(self, frame, argument_list):
# traceenter("user_call",_dumpf(frame))
def user_line(self, frame):
traceenter("user_line",_dumpf(frame))
# Traces at line zero
if frame.f_lineno!=0:
breakReason = self.breakReason
if breakReason is None:
breakReason = axdebug.BREAKREASON_STEP
self._HandleBreakPoint(frame, None, breakReason)
def user_return(self, frame, return_value):
# traceenter("user_return",_dumpf(frame),return_value)
bdb.Bdb.user_return(self, frame, return_value)
def user_exception(self, frame, exc_info):
# traceenter("user_exception")
bdb.Bdb.user_exception(self, frame, exc_info)
def _HandleBreakPoint(self, frame, tb, reason):
traceenter("Calling HandleBreakPoint with reason", reason,"at frame", _dumpf(frame))
traceenter(" Current frame is", _dumpf(self.currentframe))
try:
resumeAction = self.debugApplication.HandleBreakPoint(reason)
tracev("HandleBreakPoint returned with ", resumeAction)
except pythoncom.com_error as details:
# Eeek - the debugger is dead, or something serious is happening.
# Assume we should continue
resumeAction = axdebug.BREAKRESUMEACTION_CONTINUE
trace("HandleBreakPoint FAILED with", details)
self.stack = []
self.curindex = 0
if resumeAction == axdebug.BREAKRESUMEACTION_ABORT:
self.set_quit()
elif resumeAction == axdebug.BREAKRESUMEACTION_CONTINUE:
tracev("resume action is continue")
self.set_continue()
elif resumeAction == axdebug.BREAKRESUMEACTION_STEP_INTO:
tracev("resume action is step")
self.set_step()
elif resumeAction == axdebug.BREAKRESUMEACTION_STEP_OVER:
tracev("resume action is next")
self.set_next(frame)
elif resumeAction == axdebug.BREAKRESUMEACTION_STEP_OUT:
tracev("resume action is stop out")
self.set_return(frame)
else:
raise ValueError("unknown resume action flags")
self.breakReason = None
def set_trace(self):
self.breakReason = axdebug.BREAKREASON_LANGUAGE_INITIATED
bdb.Bdb.set_trace(self)
def CloseApp(self):
traceenter("ClosingApp")
self.reset()
self.logicalbotframe = None
if self.stackSnifferCookie is not None:
try:
self.debugApplication.RemoveStackFrameSniffer(self.stackSnifferCookie)
except pythoncom.com_error:
trace("*** Could not RemoveStackFrameSniffer %d" % (self.stackSnifferCookie))
if self.stackSniffer:
_wrap_remove(self.stackSniffer)
self.stackSnifferCookie = self.stackSniffer = None
if self.appEventConnection is not None:
self.appEventConnection.Disconnect()
self.appEventConnection = None
self.debugApplication = None
self.appDebugger = None
if self.codeContainerProvider is not None:
self.codeContainerProvider.Close()
self.codeContainerProvider = None
def AttachApp(self, debugApplication, codeContainerProvider):
# traceenter("AttachApp", debugApplication, codeContainerProvider)
self.codeContainerProvider = codeContainerProvider
self.debugApplication = debugApplication
self.stackSniffer = _wrap(stackframe.DebugStackFrameSniffer(self), axdebug.IID_IDebugStackFrameSniffer)
self.stackSnifferCookie = debugApplication.AddStackFrameSniffer(self.stackSniffer)
# trace("StackFrameSniffer added (%d)" % self.stackSnifferCookie)
# Connect to the application events.
self.appEventConnection = win32com.client.connect.SimpleConnection(self.debugApplication, self, axdebug.IID_IRemoteDebugApplicationEvents)
def ResetAXDebugging(self):
traceenter("ResetAXDebugging", self, "with refcount", len(self.recursiveData))
if win32api.GetCurrentThreadId()!=self.debuggingThread:
trace("ResetAXDebugging called on other thread")
return
if len(self.recursiveData)==0:
# print "ResetAXDebugging called for final time."
self.logicalbotframe = None
self.debuggingThread = None
self.currentframe = None
self.debuggingThreadStateHandle = None
return
self.logbotframe, self.stopframe, self.currentframe, self.debuggingThreadStateHandle = self.recursiveData[0]
self.recursiveData = self.recursiveData[1:]
def SetupAXDebugging(self, baseFrame = None, userFrame = None):
"""Get ready for potential debugging. Must be called on the thread
that is being debugged.
"""
# userFrame is for non AXScript debugging. This is the first frame of the
# users code.
if userFrame is None:
userFrame = baseFrame
else:
# We have missed the "dispatch_call" function, so set this up now!
userFrame.f_locals['__axstack_address__'] = axdebug.GetStackAddress()
traceenter("SetupAXDebugging", self)
self._threadprotectlock.acquire()
try:
thisThread = win32api.GetCurrentThreadId()
if self.debuggingThread is None:
self.debuggingThread = thisThread
else:
if self.debuggingThread!=thisThread:
trace("SetupAXDebugging called on other thread - ignored!")
return
# push our context.
self.recursiveData.insert(0, (self.logicalbotframe,self.stopframe, self.currentframe,self.debuggingThreadStateHandle))
finally:
self._threadprotectlock.release()
trace("SetupAXDebugging has base frame as", _dumpf(baseFrame))
self.botframe = baseFrame
self.stopframe = userFrame
self.logicalbotframe = baseFrame
self.currentframe = None
self.debuggingThreadStateHandle = axdebug.GetThreadStateHandle()
self._BreakFlagsChanged()
# RemoteDebugApplicationEvents
def OnConnectDebugger(self, appDebugger):
traceenter("OnConnectDebugger", appDebugger)
self.appDebugger = appDebugger
# Reflect output to appDebugger
writefunc = lambda s: appDebugger.onDebugOutput(s)
sys.stdout = OutputReflector(sys.stdout, writefunc)
sys.stderr = OutputReflector(sys.stderr, writefunc)
def OnDisconnectDebugger(self):
traceenter("OnDisconnectDebugger")
# Stop reflecting output
if isinstance(sys.stdout, OutputReflector):
sys.stdout = sys.stdout.file
if isinstance(sys.stderr, OutputReflector):
sys.stderr = sys.stderr.file
self.appDebugger = None
self.set_quit()
def OnSetName(self, name):
traceenter("OnSetName", name)
def OnDebugOutput(self, string):
traceenter("OnDebugOutput", string)
def OnClose(self):
traceenter("OnClose")
def OnEnterBreakPoint(self, rdat):
traceenter("OnEnterBreakPoint", rdat)
def OnLeaveBreakPoint(self, rdat):
traceenter("OnLeaveBreakPoint", rdat)
def OnCreateThread(self, rdat):
traceenter("OnCreateThread", rdat)
def OnDestroyThread(self, rdat):
traceenter("OnDestroyThread", rdat)
def OnBreakFlagChange(self, abf, rdat):
traceenter("Debugger OnBreakFlagChange", abf, rdat)
self.breakFlags = abf
self._BreakFlagsChanged()
def _BreakFlagsChanged(self):
traceenter("_BreakFlagsChanged to %s with our thread = %s, and debugging thread = %s" % (self.breakFlags, self.debuggingThread, win32api.GetCurrentThreadId()))
trace("_BreakFlagsChanged has breaks", self.breaks)
# If a request comes on our debugging thread, then do it now!
# if self.debuggingThread!=win32api.GetCurrentThreadId():
# return
if len(self.breaks) or self.breakFlags:
if self.logicalbotframe:
trace("BreakFlagsChange with bot frame", _dumpf(self.logicalbotframe))
# We have frames not to be debugged (eg, Scripting engine frames
# (sys.settrace will be set when out logicalbotframe is hit -
# this may not be the right thing to do, as it may not cause the
# immediate break we desire.)
self.logicalbotframe.f_trace = self.trace_dispatch
else:
trace("BreakFlagsChanged, but no bottom frame")
if self.stopframe is not None:
self.stopframe.f_trace = self.trace_dispatch
# If we have the thread-state for the thread being debugged, then
# we dynamically set its trace function - it is possible that the thread
# being debugged is in a blocked call (eg, a message box) and we
# want to hit the debugger the instant we return
if self.debuggingThreadStateHandle is not None and \
self.breakFlags and \
self.debuggingThread != win32api.GetCurrentThreadId():
axdebug.SetThreadStateTrace(self.debuggingThreadStateHandle, self.trace_dispatch)
def _OnSetBreakPoint(self, key, codeContext, bps, lineNo):
traceenter("_OnSetBreakPoint", self, key, codeContext, bps, lineNo)
if bps==axdebug.BREAKPOINT_ENABLED:
problem = self.set_break(key, lineNo)
if problem:
print("*** set_break failed -", problem)
trace("_OnSetBreakPoint just set BP and has breaks", self.breaks)
else:
self.clear_break(key, lineNo)
self._BreakFlagsChanged()
trace("_OnSetBreakPoint leaving with breaks", self.breaks)
def Debugger():
global g_adb
if g_adb is None:
g_adb = Adb()
return g_adb

Binary file not shown.

View file

@ -0,0 +1,254 @@
"""A utility class for a code container.
A code container is a class which holds source code for a debugger. It knows how
to color the text, and also how to translate lines into offsets, and back.
"""
import sys
from win32com.axdebug import axdebug
import tokenize
from .util import RaiseNotImpl, _wrap
from win32com.server.exception import Exception
import win32api, winerror
from . import contexts
_keywords = {} # set of Python keywords
for name in """
and assert break class continue def del elif else except exec
finally for from global if import in is lambda not
or pass print raise return try while
""".split():
_keywords[name] = 1
class SourceCodeContainer:
def __init__(self, text, fileName = "<Remove Me!>", sourceContext = 0, startLineNumber = 0, site = None, debugDocument = None):
self.sourceContext = sourceContext # The source context added by a smart host.
self.text = text
if text:
self._buildlines()
self.nextLineNo = 0
self.fileName = fileName
self.codeContexts = {}
self.site = site
self.startLineNumber = startLineNumber
self.debugDocument = None
def _Close(self):
self.text = self.lines = self.lineOffsets = None
self.codeContexts = None
self.debugDocument = None
self.site = None
self.sourceContext = None
def GetText(self):
return self.text
def GetName(self, dnt):
assert 0, "You must subclass this"
def GetFileName(self):
return self.fileName
def GetPositionOfLine(self, cLineNumber):
self.GetText() # Prime us.
try:
return self.lineOffsets[cLineNumber]
except IndexError:
raise Exception(scode=winerror.S_FALSE)
def GetLineOfPosition(self, charPos):
self.GetText() # Prime us.
lastOffset = 0
lineNo = 0
for lineOffset in self.lineOffsets[1:]:
if lineOffset > charPos:
break
lastOffset = lineOffset
lineNo = lineNo + 1
else: # for not broken.
# print "Cant find", charPos, "in", self.lineOffsets
raise Exception(scode=winerror.S_FALSE)
# print "GLOP ret=",lineNo, (charPos-lastOffset)
return lineNo, (charPos-lastOffset)
def GetNextLine(self):
if self.nextLineNo>=len(self.lines):
self.nextLineNo = 0 # auto-reset.
return ""
rc = self.lines[self.nextLineNo]
self.nextLineNo = self.nextLineNo + 1
return rc
def GetLine(self, num):
self.GetText() # Prime us.
return self.lines[num]
def GetNumChars(self):
return len(self.GetText())
def GetNumLines(self):
self.GetText() # Prime us.
return len(self.lines)
def _buildline(self, pos):
i = self.text.find('\n', pos)
if i < 0:
newpos = len(self.text)
else:
newpos = i+1
r = self.text[pos:newpos]
return r, newpos
def _buildlines(self):
self.lines = []
self.lineOffsets = [0]
line, pos = self._buildline(0)
while line:
self.lines.append(line)
self.lineOffsets.append(pos)
line, pos = self._buildline(pos)
def _ProcessToken(self, type, token, spos, epos, line):
srow, scol = spos
erow, ecol = epos
self.GetText() # Prime us.
linenum = srow - 1 # Lines zero based for us too.
realCharPos = self.lineOffsets[linenum] + scol
numskipped = realCharPos - self.lastPos
if numskipped==0:
pass
elif numskipped==1:
self.attrs.append(axdebug.SOURCETEXT_ATTR_COMMENT)
else:
self.attrs.append((axdebug.SOURCETEXT_ATTR_COMMENT, numskipped))
kwSize = len(token)
self.lastPos = realCharPos + kwSize
attr = 0
if type==tokenize.NAME:
if token in _keywords:
attr = axdebug.SOURCETEXT_ATTR_KEYWORD
elif type==tokenize.STRING:
attr = axdebug.SOURCETEXT_ATTR_STRING
elif type==tokenize.NUMBER:
attr = axdebug.SOURCETEXT_ATTR_NUMBER
elif type==tokenize.OP:
attr = axdebug.SOURCETEXT_ATTR_OPERATOR
elif type==tokenize.COMMENT:
attr = axdebug.SOURCETEXT_ATTR_COMMENT
# else attr remains zero...
if kwSize==0:
pass
elif kwSize==1:
self.attrs.append(attr)
else:
self.attrs.append((attr, kwSize))
def GetSyntaxColorAttributes(self):
self.lastPos = 0
self.attrs = []
try:
tokenize.tokenize(self.GetNextLine, self._ProcessToken)
except tokenize.TokenError:
pass # Ignore - will cause all subsequent text to be commented.
numAtEnd = len(self.GetText()) - self.lastPos
if numAtEnd:
self.attrs.append((axdebug.SOURCETEXT_ATTR_COMMENT, numAtEnd))
return self.attrs
# We also provide and manage DebugDocumentContext objects
def _MakeDebugCodeContext(self, lineNo, charPos, len):
return _wrap(contexts.DebugCodeContext(lineNo, charPos, len, self, self.site), axdebug.IID_IDebugCodeContext)
# Make a context at the given position. It should take up the entire context.
def _MakeContextAtPosition(self, charPos):
lineNo, offset = self.GetLineOfPosition(charPos)
try:
endPos = self.GetPositionOfLine(lineNo+1)
except:
endPos = charPos
codecontext = self._MakeDebugCodeContext(lineNo, charPos, endPos-charPos)
return codecontext
# Returns a DebugCodeContext. debugDocument can be None for smart hosts.
def GetCodeContextAtPosition(self, charPos):
# trace("GetContextOfPos", charPos, maxChars)
# Convert to line number.
lineNo, offset = self.GetLineOfPosition(charPos)
charPos = self.GetPositionOfLine(lineNo)
try:
cc = self.codeContexts[charPos]
# trace(" GetContextOfPos using existing")
except KeyError:
cc = self._MakeContextAtPosition(charPos)
self.codeContexts[charPos] = cc
return cc
class SourceModuleContainer(SourceCodeContainer):
def __init__(self, module):
self.module = module
if hasattr(module, '__file__'):
fname = self.module.__file__
# Check for .pyc or .pyo or even .pys!
if fname[-1] in ['O','o','C','c', 'S', 's']: fname = fname[:-1]
try:
fname = win32api.GetFullPathName(fname)
except win32api.error:
pass
else:
if module.__name__=='__main__' and len(sys.argv)>0:
fname = sys.argv[0]
else:
fname = "<Unknown!>"
SourceCodeContainer.__init__(self, None, fname)
def GetText(self):
if self.text is None:
fname = self.GetFileName()
if fname:
try:
self.text = open(fname, "r").read()
except IOError as details:
self.text = "# Exception opening file\n# %s" % (repr(details))
else:
self.text = "# No file available for module '%s'" % (self.module)
self._buildlines()
return self.text
def GetName(self, dnt):
name = self.module.__name__
try:
fname = win32api.GetFullPathName(self.module.__file__)
except win32api.error:
fname = self.module.__file__
except AttributeError:
fname = name
if dnt==axdebug.DOCUMENTNAMETYPE_APPNODE:
return name.split(".")[-1]
elif dnt==axdebug.DOCUMENTNAMETYPE_TITLE:
return fname
elif dnt==axdebug.DOCUMENTNAMETYPE_FILE_TAIL:
return os.path.split(fname)[1]
elif dnt==axdebug.DOCUMENTNAMETYPE_URL:
return "file:%s" % fname
else:
raise Exception(scode=winerror.E_UNEXPECTED)
if __name__=='__main__':
import sys
sys.path.append(".")
import ttest
sc = SourceModuleContainer(ttest)
# sc = SourceCodeContainer(open(sys.argv[1], "rb").read(), sys.argv[1])
attrs = sc.GetSyntaxColorAttributes()
attrlen = 0
for attr in attrs:
if type(attr)==type(()):
attrlen = attrlen + attr[1]
else:
attrlen = attrlen + 1
text = sc.GetText()
if attrlen!=len(text):
print("Lengths dont match!!! (%d/%d)" % (attrlen, len(text)))
# print "Attributes:"
# print attrs
print("GetLineOfPos=", sc.GetLineOfPosition(0))
print("GetLineOfPos=", sc.GetLineOfPosition(4))
print("GetLineOfPos=", sc.GetLineOfPosition(10))

View file

@ -0,0 +1,56 @@
""" A module for managing the AXDebug I*Contexts
"""
from . import gateways, axdebug
import pythoncom, win32com.server.util
# Utility function for wrapping object created by this module.
from .util import _wrap, _wrap_remove, trace
from . import adb
class DebugCodeContext(gateways.DebugCodeContext, gateways.DebugDocumentContext):
# NOTE: We also implement the IDebugDocumentContext interface for Simple Hosts.
# Thus, debugDocument may be NULL when we have smart hosts - but in that case, we
# wont be called upon to provide it.
_public_methods_ = gateways.DebugCodeContext._public_methods_ + \
gateways.DebugDocumentContext._public_methods_
_com_interfaces_ = gateways.DebugCodeContext._com_interfaces_ + \
gateways.DebugDocumentContext._com_interfaces_
def __init__(self, lineNo, charPos, len, codeContainer, debugSite):
self.debugSite = debugSite
self.offset = charPos
self.length = len
self.breakPointState = 0
self.lineno = lineNo
gateways.DebugCodeContext.__init__(self)
self.codeContainer = codeContainer
def _Close(self):
self.debugSite = None
def GetDocumentContext(self):
if self.debugSite is not None:
# We have a smart host - let him give it to us.
return self.debugSite.GetDocumentContextFromPosition(
self.codeContainer.sourceContext,
self.offset,
self.length)
else:
# Simple host - Fine - Ill do it myself!
return _wrap(self, axdebug.IID_IDebugDocumentContext)
def SetBreakPoint(self, bps):
self.breakPointState = bps
adb.OnSetBreakPoint(self, bps, self.lineno)
# The DebugDocumentContext methods for simple hosts.
def GetDocument(self):
return self.codeContainer.debugDocument
def EnumCodeContexts(self):
return _wrap(EnumDebugCodeContexts([self]), axdebug.IID_IEnumDebugCodeContexts)
class EnumDebugCodeContexts(gateways.EnumDebugCodeContexts):
def _wrap(self, obj):
return _wrap(obj, axdebug.IID_IDebugCodeContext)

View file

@ -0,0 +1,203 @@
import sys, traceback, string
from win32com.axscript import axscript
from win32com.axdebug import codecontainer, axdebug, gateways, documents, contexts, adb, expressions
from win32com.axdebug.util import trace, _wrap, _wrap_remove
import pythoncom
import win32api, winerror
import os
currentDebugger = None
class ModuleTreeNode:
"""Helper class for building a module tree
"""
def __init__(self, module):
modName = module.__name__
self.moduleName = modName
self.module = module
self.realNode = None
self.cont = codecontainer.SourceModuleContainer(module)
def __repr__(self):
return "<ModuleTreeNode wrapping %s>" % (self.module)
def Attach(self, parentRealNode):
self.realNode.Attach(parentRealNode)
def Close(self):
self.module = None
self.cont = None
self.realNode = None
def BuildModule(module, built_nodes, rootNode, create_node_fn, create_node_args ):
if module:
keep = module.__name__
keep = keep and (built_nodes.get(module) is None)
if keep and hasattr(module, '__file__'):
keep = string.lower(os.path.splitext(module.__file__)[1]) not in [".pyd", ".dll"]
# keep = keep and module.__name__=='__main__'
if module and keep:
# print "keeping", module.__name__
node = ModuleTreeNode(module)
built_nodes[module] = node
realNode = create_node_fn(*(node,)+create_node_args)
node.realNode = realNode
# Split into parent nodes.
parts = string.split(module.__name__, '.')
if parts[-1][:8]=='__init__': parts = parts[:-1]
parent = string.join(parts[:-1], '.')
parentNode = rootNode
if parent:
parentModule = sys.modules[parent]
BuildModule(parentModule, built_nodes, rootNode, create_node_fn, create_node_args)
if parentModule in built_nodes:
parentNode = built_nodes[parentModule].realNode
node.Attach(parentNode)
def RefreshAllModules(builtItems, rootNode, create_node, create_node_args):
for module in list(sys.modules.values()):
BuildModule(module, builtItems, rootNode, create_node, create_node_args)
# realNode = pdm.CreateDebugDocumentHelper(None) # DebugDocumentHelper node?
# app.CreateApplicationNode() # doc provider node.
class CodeContainerProvider(documents.CodeContainerProvider):
def __init__(self, axdebugger):
self.axdebugger = axdebugger
documents.CodeContainerProvider.__init__(self)
self.currentNumModules = len(sys.modules)
self.nodes = {}
self.axdebugger.RefreshAllModules(self.nodes, self)
def FromFileName(self, fname):
### It appears we cant add modules during a debug session!
# if self.currentNumModules != len(sys.modules):
# self.axdebugger.RefreshAllModules(self.nodes, self)
# self.currentNumModules = len(sys.modules)
# for key in self.ccsAndNodes.keys():
# print "File:", key
return documents.CodeContainerProvider.FromFileName(self, fname)
def Close(self):
documents.CodeContainerProvider.Close(self)
self.axdebugger = None
print("Closing %d nodes" % (len(self.nodes)))
for node in self.nodes.values():
node.Close()
self.nodes = {}
class OriginalInterfaceMaker:
def MakeInterfaces(self, pdm):
app = self.pdm.CreateApplication()
self.cookie = pdm.AddApplication(app)
root = app.GetRootNode()
return app, root
def CloseInterfaces(self, pdm):
pdm.RemoveApplication(self.cookie)
class SimpleHostStyleInterfaceMaker:
def MakeInterfaces(self, pdm):
app = pdm.GetDefaultApplication()
root = app.GetRootNode()
return app, root
def CloseInterfaces(self, pdm):
pass
class AXDebugger:
def __init__(self, interfaceMaker = None, processName = None):
if processName is None: processName = "Python Process"
if interfaceMaker is None: interfaceMaker = SimpleHostStyleInterfaceMaker()
self.pydebugger = adb.Debugger()
self.pdm=pythoncom.CoCreateInstance(axdebug.CLSID_ProcessDebugManager,None,pythoncom.CLSCTX_ALL, axdebug.IID_IProcessDebugManager)
self.app, self.root = interfaceMaker.MakeInterfaces(self.pdm)
self.app.SetName(processName)
self.interfaceMaker = interfaceMaker
expressionProvider = _wrap(expressions.ProvideExpressionContexts(), axdebug.IID_IProvideExpressionContexts)
self.expressionCookie = self.app.AddGlobalExpressionContextProvider(expressionProvider)
contProvider = CodeContainerProvider(self)
self.pydebugger.AttachApp(self.app, contProvider)
def Break(self):
# Get the frame we start debugging from - this is the frame 1 level up
try:
1 + ''
except:
frame = sys.exc_info()[2].tb_frame.f_back
# Get/create the debugger, and tell it to break.
self.app.StartDebugSession()
# self.app.CauseBreak()
self.pydebugger.SetupAXDebugging(None, frame)
self.pydebugger.set_trace()
def Close(self):
self.pydebugger.ResetAXDebugging()
self.interfaceMaker.CloseInterfaces(self.pdm)
self.pydebugger.CloseApp()
self.app.RemoveGlobalExpressionContextProvider(self.expressionCookie)
self.expressionCookie = None
self.pdm = None
self.app = None
self.pydebugger = None
self.root = None
def RefreshAllModules(self, nodes, containerProvider):
RefreshAllModules(nodes, self.root, self.CreateApplicationNode, (containerProvider,))
def CreateApplicationNode(self, node, containerProvider):
realNode = self.app.CreateApplicationNode()
document = documents.DebugDocumentText(node.cont)
document = _wrap(document, axdebug.IID_IDebugDocument)
node.cont.debugDocument = document
provider = documents.DebugDocumentProvider(document)
provider = _wrap(provider, axdebug.IID_IDebugDocumentProvider)
realNode.SetDocumentProvider(provider)
containerProvider.AddCodeContainer(node.cont, realNode)
return realNode
def _GetCurrentDebugger():
global currentDebugger
if currentDebugger is None:
currentDebugger = AXDebugger()
return currentDebugger
def Break():
_GetCurrentDebugger().Break()
brk = Break
set_trace = Break
def dosomethingelse():
a=2
b = "Hi there"
def dosomething():
a=1
b=2
dosomethingelse()
def test():
Break()
input("Waiting...")
dosomething()
print("Done")
if __name__=='__main__':
print("About to test the debugging interfaces!")
test()
print(" %d/%d com objects still alive" % (pythoncom._GetInterfaceCount(), pythoncom._GetGatewayCount()))

View file

@ -0,0 +1,124 @@
""" Management of documents for AXDebugging.
"""
from . import axdebug, gateways
import pythoncom
from .util import _wrap, _wrap_remove, RaiseNotImpl, trace
from win32com.server.util import unwrap
from . import codecontainer
from . import contexts
from win32com.server.exception import Exception
import win32api, winerror, os, string, sys
#def trace(*args):
# pass
def GetGoodFileName(fname):
if fname[0] != "<":
return win32api.GetFullPathName(fname)
return fname
class DebugDocumentProvider(gateways.DebugDocumentProvider):
def __init__(self, doc):
self.doc = doc
def GetName(self, dnt):
return self.doc.GetName(dnt)
def GetDocumentClassId(self):
return self.doc.GetDocumentClassId()
def GetDocument(self):
return self.doc
class DebugDocumentText(gateways.DebugDocumentInfo, gateways.DebugDocumentText, gateways.DebugDocument):
_com_interfaces_ = gateways.DebugDocumentInfo._com_interfaces_ + \
gateways.DebugDocumentText._com_interfaces_ + \
gateways.DebugDocument._com_interfaces_
_public_methods_ = gateways.DebugDocumentInfo._public_methods_ + \
gateways.DebugDocumentText._public_methods_ + \
gateways.DebugDocument._public_methods_
# A class which implements a DebugDocumentText, using the functionality
# provided by a codeContainer
def __init__(self, codeContainer):
gateways.DebugDocumentText.__init__(self)
gateways.DebugDocumentInfo.__init__(self)
gateways.DebugDocument.__init__(self)
self.codeContainer = codeContainer
def _Close(self):
self.docContexts = None
# self.codeContainer._Close()
self.codeContainer = None
# IDebugDocumentInfo
def GetName(self, dnt):
return self.codeContainer.GetName(dnt)
def GetDocumentClassId(self):
return "{DF630910-1C1D-11d0-AE36-8C0F5E000000}"
# IDebugDocument has no methods!
#
# IDebugDocumentText methods.
# def GetDocumentAttributes
def GetSize(self):
# trace("GetSize")
return self.codeContainer.GetNumLines(), self.codeContainer.GetNumChars()
def GetPositionOfLine(self, cLineNumber):
return self.codeContainer.GetPositionOfLine(cLineNumber)
def GetLineOfPosition(self, charPos):
return self.codeContainer.GetLineOfPosition(charPos)
def GetText(self, charPos, maxChars, wantAttr):
# Get all the attributes, else the tokenizer will get upset.
# XXX - not yet!
# trace("GetText", charPos, maxChars, wantAttr)
cont = self.codeContainer
attr = cont.GetSyntaxColorAttributes()
return cont.GetText(), attr
def GetPositionOfContext(self, context):
trace("GetPositionOfContext", context)
context = unwrap(context)
return context.offset, context.length
# Return a DebugDocumentContext.
def GetContextOfPosition(self, charPos, maxChars):
# Make one
doc = _wrap(self, axdebug.IID_IDebugDocument)
rc = self.codeContainer.GetCodeContextAtPosition(charPos)
return rc.QueryInterface(axdebug.IID_IDebugDocumentContext)
class CodeContainerProvider:
"""An abstract Python class which provides code containers!
Given a Python file name (as the debugger knows it by) this will
return a CodeContainer interface suitable for use.
This provides a simple base imlpementation that simply supports
a dictionary of nodes and providers.
"""
def __init__(self):
self.ccsAndNodes = {}
def AddCodeContainer(self, cc, node = None):
fname = GetGoodFileName(cc.fileName)
self.ccsAndNodes[fname] = cc, node
def FromFileName(self, fname):
cc, node = self.ccsAndNodes.get(GetGoodFileName(fname), (None, None))
# if cc is None:
# print "FromFileName for %s returning None" % fname
return cc
def Close(self):
for cc, node in self.ccsAndNodes.values():
try:
# Must close the node before closing the provider
# as node may make calls on provider (eg Reset breakpoints etc)
if node is not None:
node.Close()
cc._Close()
except pythoncom.com_error:
pass
self.ccsAndNodes = {}

View file

@ -0,0 +1,48 @@
import sys, string
import traceback
from win32com.axdebug import axdebug
from win32com.client.util import Enumerator
import pythoncom
def DumpDebugApplicationNode(node, level = 0):
# Recursive dump of a DebugApplicationNode
spacer = " " * level
for desc, attr in [("Node Name", axdebug.DOCUMENTNAMETYPE_APPNODE),
("Title", axdebug.DOCUMENTNAMETYPE_TITLE),
("Filename", axdebug.DOCUMENTNAMETYPE_FILE_TAIL),
("URL", axdebug.DOCUMENTNAMETYPE_URL),
]:
try:
info = node.GetName(attr)
except pythoncom.com_error:
info = "<N/A>"
print("%s%s: %s" % (spacer, desc, info))
try:
doc = node.GetDocument()
except pythoncom.com_error:
doc = None
if doc:
doctext = doc.QueryInterface(axdebug.IID_IDebugDocumentText)
numLines, numChars = doctext.GetSize()
# text, attr = doctext.GetText(0, 20, 1)
text, attr = doctext.GetText(0, numChars, 1)
print("%sText is %s, %d bytes long" % (spacer, repr(text[:40]+"..."), len(text)))
else:
print("%s%s" % (spacer, "<No document available>"))
for child in Enumerator(node.EnumChildren()):
DumpDebugApplicationNode(child, level+1)
def dumpall():
dm=pythoncom.CoCreateInstance(axdebug.CLSID_MachineDebugManager,None,pythoncom.CLSCTX_ALL, axdebug.IID_IMachineDebugManager)
e=Enumerator(dm.EnumApplications())
for app in e:
print("Application: %s" % app.GetName())
node = app.GetRootNode() # of type PyIDebugApplicationNode->PyIDebugDocumentProvider->PyIDebugDocumentInfo
DumpDebugApplicationNode(node)
if __name__=='__main__':
try:
dumpall()
except:
traceback.print_exc()

View file

@ -0,0 +1,156 @@
from . import axdebug, gateways
from .util import _wrap, _wrap_remove, RaiseNotImpl
import io, traceback
from pprint import pprint
from win32com.server.exception import COMException
import winerror
import string
import sys
# Given an object, return a nice string
def MakeNiceString(ob):
stream = io.StringIO()
pprint(ob, stream)
return string.strip(stream.getvalue())
class ProvideExpressionContexts(gateways.ProvideExpressionContexts):
pass
class ExpressionContext(gateways.DebugExpressionContext):
def __init__(self, frame):
self.frame = frame
def ParseLanguageText(self, code, radix, delim, flags):
return _wrap(Expression(self.frame, code, radix, delim, flags), axdebug.IID_IDebugExpression)
def GetLanguageInfo(self):
# print "GetLanguageInfo"
return "Python", "{DF630910-1C1D-11d0-AE36-8C0F5E000000}"
class Expression(gateways.DebugExpression):
def __init__(self, frame, code, radix, delim, flags):
self.callback = None
self.frame = frame
self.code = code
self.radix = radix
self.delim = delim
self.flags = flags
self.isComplete = 0
self.result=None
self.hresult = winerror.E_UNEXPECTED
def Start(self, callback):
try:
try:
try:
self.result = eval(self.code, self.frame.f_globals, self.frame.f_locals)
except SyntaxError:
exec(self.code, self.frame.f_globals, self.frame.f_locals)
self.result = ""
self.hresult = 0
except:
l = traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])
# l is a list of strings with trailing "\n"
self.result = string.join(map(lambda s:s[:-1], l), "\n")
self.hresult = winerror.E_FAIL
finally:
self.isComplete = 1
callback.onComplete()
def Abort(self):
print("** ABORT **")
def QueryIsComplete(self):
return self.isComplete
def GetResultAsString(self):
# print "GetStrAsResult returning", self.result
return self.hresult, MakeNiceString(self.result)
def GetResultAsDebugProperty(self):
result = _wrap(DebugProperty(self.code, self.result, None, self.hresult), axdebug.IID_IDebugProperty)
return self.hresult, result
def MakeEnumDebugProperty(object, dwFieldSpec, nRadix, iid, stackFrame = None):
name_vals = []
if hasattr(object, "items") and hasattr(object, "keys"): # If it is a dict.
name_vals = iter(object.items())
dictionary = object
elif hasattr(object, "__dict__"): #object with dictionary, module
name_vals = iter(object.__dict__.items())
dictionary = object.__dict__
infos = []
for name, val in name_vals:
infos.append(GetPropertyInfo(name, val, dwFieldSpec, nRadix, 0, dictionary, stackFrame))
return _wrap(EnumDebugPropertyInfo(infos), axdebug.IID_IEnumDebugPropertyInfo)
def GetPropertyInfo(obname, obvalue, dwFieldSpec, nRadix, hresult=0, dictionary = None, stackFrame = None):
# returns a tuple
name = typ = value = fullname = attrib = dbgprop = None
if dwFieldSpec & axdebug.DBGPROP_INFO_VALUE:
value = MakeNiceString(obvalue)
if dwFieldSpec & axdebug.DBGPROP_INFO_NAME:
name = obname
if dwFieldSpec & axdebug.DBGPROP_INFO_TYPE:
if hresult:
typ = "Error"
else:
try:
typ = type(obvalue).__name__
except AttributeError:
typ = str(type(obvalue))
if dwFieldSpec & axdebug.DBGPROP_INFO_FULLNAME:
fullname = obname
if dwFieldSpec & axdebug.DBGPROP_INFO_ATTRIBUTES:
if hasattr(obvalue, "has_key") or hasattr(obvalue, "__dict__"): # If it is a dict or object
attrib = axdebug.DBGPROP_ATTRIB_VALUE_IS_EXPANDABLE
else:
attrib = 0
if dwFieldSpec & axdebug.DBGPROP_INFO_DEBUGPROP:
dbgprop = _wrap(DebugProperty(name, obvalue, None, hresult, dictionary, stackFrame), axdebug.IID_IDebugProperty)
return name, typ, value, fullname, attrib, dbgprop
from win32com.server.util import ListEnumeratorGateway
class EnumDebugPropertyInfo(ListEnumeratorGateway):
"""A class to expose a Python sequence as an EnumDebugCodeContexts
Create an instance of this class passing a sequence (list, tuple, or
any sequence protocol supporting object) and it will automatically
support the EnumDebugCodeContexts interface for the object.
"""
_public_methods_ = ListEnumeratorGateway._public_methods_ + ["GetCount"]
_com_interfaces_ = [ axdebug.IID_IEnumDebugPropertyInfo]
def GetCount(self):
return len(self._list_)
def _wrap(self, ob):
return ob
class DebugProperty:
_com_interfaces_ = [axdebug.IID_IDebugProperty]
_public_methods_ = ['GetPropertyInfo', 'GetExtendedInfo', 'SetValueAsString',
'EnumMembers', 'GetParent'
]
def __init__(self, name, value, parent = None, hresult = 0, dictionary = None, stackFrame = None):
self.name = name
self.value = value
self.parent = parent
self.hresult = hresult
self.dictionary = dictionary
self.stackFrame = stackFrame
def GetPropertyInfo(self, dwFieldSpec, nRadix):
return GetPropertyInfo(self.name, self.value, dwFieldSpec, nRadix, self.hresult, dictionary, stackFrame)
def GetExtendedInfo(self): ### Note - not in the framework.
RaiseNotImpl("DebugProperty::GetExtendedInfo")
def SetValueAsString(self, value, radix):
if self.stackFrame and self.dictionary:
self.dictionary[self.name]= eval(value,self.stackFrame.f_globals, self.stackFrame.f_locals)
else:
RaiseNotImpl("DebugProperty::SetValueAsString")
def EnumMembers(self, dwFieldSpec, nRadix, iid):
# Returns IEnumDebugPropertyInfo
return MakeEnumDebugProperty(self.value, dwFieldSpec, nRadix, iid, self.stackFrame)
def GetParent(self):
# return IDebugProperty
RaiseNotImpl("DebugProperty::GetParent")

View file

@ -0,0 +1,452 @@
# Classes which describe interfaces.
from win32com.server.exception import Exception
from win32com.server.util import ListEnumeratorGateway
from win32com.axdebug import axdebug
from win32com.axdebug.util import RaiseNotImpl, _wrap
import pythoncom
import win32com.server.connect
import winerror
class EnumDebugCodeContexts(ListEnumeratorGateway):
"""A class to expose a Python sequence as an EnumDebugCodeContexts
Create an instance of this class passing a sequence (list, tuple, or
any sequence protocol supporting object) and it will automatically
support the EnumDebugCodeContexts interface for the object.
"""
_com_interfaces_ = [ axdebug.IID_IEnumDebugCodeContexts ]
class EnumDebugStackFrames(ListEnumeratorGateway):
"""A class to expose a Python sequence as an EnumDebugStackFrames
Create an instance of this class passing a sequence (list, tuple, or
any sequence protocol supporting object) and it will automatically
support the EnumDebugStackFrames interface for the object.
"""
_com_interfaces_ = [ axdebug.IID_IEnumDebugStackFrames ]
class EnumDebugApplicationNodes(ListEnumeratorGateway):
"""A class to expose a Python sequence as an EnumDebugStackFrames
Create an instance of this class passing a sequence (list, tuple, or
any sequence protocol supporting object) and it will automatically
support the EnumDebugApplicationNodes interface for the object.
"""
_com_interfaces_ = [ axdebug.IID_IEnumDebugApplicationNodes ]
class EnumRemoteDebugApplications(ListEnumeratorGateway):
_com_interfaces_ = [ axdebug.IID_IEnumRemoteDebugApplications ]
class EnumRemoteDebugApplicationThreads(ListEnumeratorGateway):
_com_interfaces_ = [ axdebug.IID_IEnumRemoteDebugApplicationThreads ]
class DebugDocumentInfo:
_public_methods_ = ["GetName", "GetDocumentClassId"]
_com_interfaces_ = [axdebug.IID_IDebugDocumentInfo]
def __init__(self):
pass
def GetName(self, dnt):
""" Get the one of the name of the document
dnt -- int DOCUMENTNAMETYPE
"""
RaiseNotImpl("GetName")
def GetDocumentClassId(self):
"""
Result must be an IID object (or string representing one).
"""
RaiseNotImpl("GetDocumentClassId")
class DebugDocumentProvider(DebugDocumentInfo):
_public_methods_ = DebugDocumentInfo._public_methods_ + ["GetDocument"]
_com_interfaces_ = DebugDocumentInfo._com_interfaces_ + [axdebug.IID_IDebugDocumentProvider]
def GetDocument(self):
RaiseNotImpl("GetDocument")
class DebugApplicationNode(DebugDocumentProvider):
"""Provides the functionality of IDebugDocumentProvider, plus a context within a project tree.
"""
_public_methods_ = """EnumChildren GetParent SetDocumentProvider
Close Attach Detach""".split() + \
DebugDocumentProvider._public_methods_
_com_interfaces_ = [axdebug.IID_IDebugDocumentProvider] + \
DebugDocumentProvider._com_interfaces_
def __init__(self):
DebugDocumentProvider.__init__(self)
def EnumChildren(self):
# Result is type PyIEnumDebugApplicationNodes
RaiseNotImpl("EnumChildren")
def GetParent(self):
# result is type PyIDebugApplicationNode
RaiseNotImpl("GetParent")
def SetDocumentProvider(self, pddp): # PyIDebugDocumentProvider pddp
# void result.
RaiseNotImpl("SetDocumentProvider")
def Close(self):
# void result.
RaiseNotImpl("Close")
def Attach(self, parent): # PyIDebugApplicationNode
# void result.
RaiseNotImpl("Attach")
def Detach(self):
# void result.
RaiseNotImpl("Detach")
class DebugApplicationNodeEvents:
"""Event interface for DebugApplicationNode object.
"""
_public_methods_ = "onAddChild onRemoveChild onDetach".split()
_com_interfaces_ = [axdebug.IID_IDebugApplicationNodeEvents]
def __init__(self):
pass
def onAddChild(self, child): # PyIDebugApplicationNode
# void result.
RaiseNotImpl("onAddChild")
def onRemoveChild(self, child): # PyIDebugApplicationNode
# void result.
RaiseNotImpl("onRemoveChild")
def onDetach(self):
# void result.
RaiseNotImpl("onDetach")
def onAttach(self, parent): # PyIDebugApplicationNode
# void result.
RaiseNotImpl("onAttach")
class DebugDocument(DebugDocumentInfo):
"""The base interface to all debug documents.
"""
_public_methods_ = DebugDocumentInfo._public_methods_
_com_interfaces_ = [axdebug.IID_IDebugDocument] + DebugDocumentInfo._com_interfaces_
class DebugDocumentText(DebugDocument):
"""The interface to a text only debug document.
"""
_com_interfaces_ = [axdebug.IID_IDebugDocumentText] + \
DebugDocument._com_interfaces_
_public_methods_ = ["GetDocumentAttributes", "GetSize",
"GetPositionOfLine", "GetLineOfPosition", "GetText",
"GetPositionOfContext", "GetContextOfPosition"] + \
DebugDocument._public_methods_
def __init__(self):
pass
# IDebugDocumentText
def GetDocumentAttributes(self):
# Result is int (TEXT_DOC_ATTR)
RaiseNotImpl("GetDocumentAttributes")
def GetSize(self):
# Result is (numLines, numChars)
RaiseNotImpl("GetSize")
def GetPositionOfLine(self, cLineNumber):
# Result is int char position
RaiseNotImpl("GetPositionOfLine")
def GetLineOfPosition(self, charPos):
# Result is int, int (lineNo, offset)
RaiseNotImpl("GetLineOfPosition")
def GetText(self, charPos, maxChars, wantAttr):
"""Params
charPos -- integer
maxChars -- integer
wantAttr -- Should the function compute attributes.
Return value must be (string, attribtues). attributes may be
None if(not wantAttr)
"""
RaiseNotImpl("GetText")
def GetPositionOfContext(self, debugDocumentContext):
"""Params
debugDocumentContext -- a PyIDebugDocumentContext object.
Return value must be (charPos, numChars)
"""
RaiseNotImpl("GetPositionOfContext")
def GetContextOfPosition(self, charPos, maxChars):
"""Params are integers.
Return value must be PyIDebugDocumentContext object
"""
print(self)
RaiseNotImpl("GetContextOfPosition")
class DebugDocumentTextExternalAuthor:
"""Allow external editors to edit file-based debugger documents, and to notify the document when the source file has been changed.
"""
_public_methods_ = ["GetPathName", "GetFileName", "NotifyChanged"]
_com_interfaces_ = [axdebug.IID_IDebugDocumentTextExternalAuthor]
def __init__(self):
pass
def GetPathName(self):
"""Return the full path (including file name) to the document's source file.
Result must be (filename, fIsOriginal), where
- if fIsOriginalPath is TRUE if the path refers to the original file for the document.
- if fIsOriginalPath is FALSE if the path refers to a newly created temporary file.
raise Exception(winerror.E_FAIL) if no source file can be created/determined.
"""
RaiseNotImpl("GetPathName")
def GetFileName(self):
"""Return just the name of the document, with no path information. (Used for "Save As...")
Result is a string
"""
RaiseNotImpl("GetFileName")
def NotifyChanged(self):
""" Notify the host that the document's source file has been saved and
that its contents should be refreshed.
"""
RaiseNotImpl("NotifyChanged")
class DebugDocumentTextEvents:
_public_methods_ = """onDestroy onInsertText onRemoveText
onReplaceText onUpdateTextAttributes
onUpdateDocumentAttributes""".split()
_com_interfaces_ = [ axdebug.IID_IDebugDocumentTextEvents ]
def __init__(self):
pass
def onDestroy(self):
# Result is void.
RaiseNotImpl("onDestroy")
def onInsertText(self, cCharacterPosition, cNumToInsert):
# Result is void.
RaiseNotImpl("onInsertText")
def onRemoveText(self, cCharacterPosition, cNumToRemove):
# Result is void.
RaiseNotImpl("onRemoveText")
def onReplaceText(self, cCharacterPosition, cNumToReplace):
# Result is void.
RaiseNotImpl("onReplaceText")
def onUpdateTextAttributes(self, cCharacterPosition, cNumToUpdate):
# Result is void.
RaiseNotImpl("onUpdateTextAttributes")
def onUpdateDocumentAttributes(self,textdocattr): # TEXT_DOC_ATTR
# Result is void.
RaiseNotImpl("onUpdateDocumentAttributes")
class DebugDocumentContext:
_public_methods_ = [ 'GetDocument', 'EnumCodeContexts']
_com_interfaces_ = [ axdebug.IID_IDebugDocumentContext ]
def __init__(self):
pass
def GetDocument(self):
"""Return value must be a PyIDebugDocument object
"""
RaiseNotImpl("GetDocument")
def EnumCodeContexts(self):
"""Return value must be a PyIEnumDebugCodeContexts object
"""
RaiseNotImpl("EnumCodeContexts")
class DebugCodeContext:
_public_methods_ = [ 'GetDocumentContext', 'SetBreakPoint']
_com_interfaces_ = [ axdebug.IID_IDebugCodeContext ]
def __init__(self):
pass
def GetDocumentContext(self):
"""Return value must be a PyIDebugDocumentContext object
"""
RaiseNotImpl("GetDocumentContext")
def SetBreakPoint(self, bps):
"""bps -- an integer with flags.
"""
RaiseNotImpl("SetBreakPoint")
class DebugStackFrame:
"""Abstraction representing a logical stack frame on the stack of a thread."""
_public_methods_ = [ 'GetCodeContext', 'GetDescriptionString', 'GetLanguageString', 'GetThread', 'GetDebugProperty']
_com_interfaces_ = [ axdebug.IID_IDebugStackFrame ]
def __init__(self):
pass
def GetCodeContext(self):
"""Returns the current code context associated with the stack frame.
Return value must be a IDebugCodeContext object
"""
RaiseNotImpl("GetCodeContext")
def GetDescriptionString(self, fLong):
"""Returns a textual description of the stack frame.
fLong -- A flag indicating if the long name is requested.
"""
RaiseNotImpl("GetDescriptionString")
def GetLanguageString(self):
"""Returns a short or long textual description of the language.
fLong -- A flag indicating if the long name is requested.
"""
RaiseNotImpl("GetLanguageString")
def GetThread(self):
""" Returns the thread associated with this stack frame.
Result must be a IDebugApplicationThread
"""
RaiseNotImpl("GetThread")
def GetDebugProperty(self):
RaiseNotImpl("GetDebugProperty")
class DebugDocumentHost:
"""The interface from the IDebugDocumentHelper back to
the smart host or language engine. This interface
exposes host specific functionality such as syntax coloring.
"""
_public_methods_ = [ 'GetDeferredText', 'GetScriptTextAttributes', 'OnCreateDocumentContext', 'GetPathName', 'GetFileName', 'NotifyChanged']
_com_interfaces_ = [ axdebug.IID_IDebugDocumentHost ]
def __init__(self):
pass
def GetDeferredText(self, dwTextStartCookie, maxChars, bWantAttr):
RaiseNotImpl("GetDeferredText")
def GetScriptTextAttributes(self, codeText, delimterText, flags):
# Result must be an attribute sequence of same "length" as the code.
RaiseNotImpl("GetScriptTextAttributes")
def OnCreateDocumentContext(self):
# Result must be a PyIUnknown
RaiseNotImpl("OnCreateDocumentContext")
def GetPathName(self):
# Result must be (string, int) where the int is a BOOL
# - TRUE if the path refers to the original file for the document.
# - FALSE if the path refers to a newly created temporary file.
# - raise Exception(scode=E_FAIL) if no source file can be created/determined.
RaiseNotImpl("GetPathName")
def GetFileName(self):
# Result is a string with just the name of the document, no path information.
RaiseNotImpl("GetFileName")
def NotifyChanged(self):
RaiseNotImpl("NotifyChanged")
# Additional gateway related functions.
class DebugDocumentTextConnectServer:
_public_methods_ = win32com.server.connect.IConnectionPointContainer_methods + win32com.server.connect.IConnectionPoint_methods
_com_interfaces_ = [pythoncom.IID_IConnectionPoint, pythoncom.IID_IConnectionPointContainer]
# IConnectionPoint interfaces
def __init__(self):
self.cookieNo = -1
self.connections = {}
def EnumConnections(self):
RaiseNotImpl("EnumConnections")
def GetConnectionInterface(self):
RaiseNotImpl("GetConnectionInterface")
def GetConnectionPointContainer(self):
return _wrap(self)
def Advise(self, pUnk):
# Creates a connection to the client. Simply allocate a new cookie,
# find the clients interface, and store it in a dictionary.
interface = pUnk.QueryInterface(axdebug.IID_IDebugDocumentTextEvents,1)
self.cookieNo = self.cookieNo + 1
self.connections[self.cookieNo] = interface
return self.cookieNo
def Unadvise(self, cookie):
# Destroy a connection - simply delete interface from the map.
try:
del self.connections[cookie]
except KeyError:
return Exception(scode=winerror.E_UNEXPECTED)
# IConnectionPointContainer interfaces
def EnumConnectionPoints(self):
RaiseNotImpl("EnumConnectionPoints")
def FindConnectionPoint(self, iid):
# Find a connection we support. Only support the single event interface.
if iid==axdebug.IID_IDebugDocumentTextEvents:
return _wrap(self)
raise Exception(scode=winerror.E_NOINTERFACE) # ??
class RemoteDebugApplicationEvents:
_public_methods_ = ["OnConnectDebugger","OnDisconnectDebugger","OnSetName","OnDebugOutput","OnClose","OnEnterBreakPoint","OnLeaveBreakPoint","OnCreateThread","OnDestroyThread","OnBreakFlagChange"]
_com_interfaces_ = [axdebug.IID_IRemoteDebugApplicationEvents]
def OnConnectDebugger(self, appDebugger):
"""appDebugger -- a PyIApplicationDebugger
"""
RaiseNotImpl("OnConnectDebugger")
def OnDisconnectDebugger(self):
RaiseNotImpl("OnDisconnectDebugger")
def OnSetName(self, name):
RaiseNotImpl("OnSetName")
def OnDebugOutput(self, string):
RaiseNotImpl("OnDebugOutput")
def OnClose(self):
RaiseNotImpl("OnClose")
def OnEnterBreakPoint(self, rdat):
"""rdat -- PyIRemoteDebugApplicationThread
"""
RaiseNotImpl("OnEnterBreakPoint")
def OnLeaveBreakPoint(self, rdat):
"""rdat -- PyIRemoteDebugApplicationThread
"""
RaiseNotImpl("OnLeaveBreakPoint")
def OnCreateThread(self, rdat):
"""rdat -- PyIRemoteDebugApplicationThread
"""
RaiseNotImpl("OnCreateThread")
def OnDestroyThread(self, rdat):
"""rdat -- PyIRemoteDebugApplicationThread
"""
RaiseNotImpl("OnDestroyThread")
def OnBreakFlagChange(self, abf, rdat):
"""abf -- int - one of the axdebug.APPBREAKFLAGS constants
rdat -- PyIRemoteDebugApplicationThread
RaiseNotImpl("OnBreakFlagChange")
"""
class DebugExpressionContext:
_public_methods_ = ["ParseLanguageText", "GetLanguageInfo"]
_com_interfaces_ = [axdebug.IID_IDebugExpressionContext]
def __init__(self):
pass
def ParseLanguageText(self, code, radix, delim, flags):
"""
result is IDebugExpression
"""
RaiseNotImpl("ParseLanguageText")
def GetLanguageInfo(self):
"""
result is (string langName, iid langId)
"""
RaiseNotImpl("GetLanguageInfo")
class DebugExpression:
_public_methods_ = ["Start", "Abort", "QueryIsComplete", "GetResultAsString", "GetResultAsDebugProperty"]
_com_interfaces_ = [axdebug.IID_IDebugExpression]
def Start(self, callback):
"""
callback -- an IDebugExpressionCallback
result - void
"""
RaiseNotImpl("Start")
def Abort(self):
"""
no params
result -- void
"""
RaiseNotImpl("Abort")
def QueryIsComplete(self):
"""
no params
result -- void
"""
RaiseNotImpl("QueryIsComplete")
def GetResultAsString(self):
RaiseNotImpl("GetResultAsString")
def GetResultAsDebugProperty(self):
RaiseNotImpl("GetResultAsDebugProperty")
class ProvideExpressionContexts:
_public_methods_ = ["EnumExpressionContexts"]
_com_interfaces_ = [axdebug.IID_IProvideExpressionContexts]
def EnumExpressionContexts(self):
RaiseNotImpl("EnumExpressionContexts")

View file

@ -0,0 +1,146 @@
"""Support for stack-frames.
Provides Implements a nearly complete wrapper for a stack frame.
"""
import sys
from .util import _wrap, RaiseNotImpl
import expressions, gateways, axdebug, winerror
import pythoncom
from win32com.server.exception import COMException
from .util import trace
#def trace(*args):
# pass
class EnumDebugStackFrames(gateways.EnumDebugStackFrames):
"""A class that given a debugger object, can return an enumerator
of DebugStackFrame objects.
"""
def __init__(self, debugger):
infos = []
frame = debugger.currentframe
# print "Stack check"
while frame:
# print " Checking frame", frame.f_code.co_filename, frame.f_lineno-1, frame.f_trace,
# Get a DebugCodeContext for the stack frame. If we fail, then it
# is not debuggable, and therefore not worth displaying.
cc = debugger.codeContainerProvider.FromFileName(frame.f_code.co_filename)
if cc is not None:
try:
address = frame.f_locals['__axstack_address__']
except KeyError:
# print "Couldnt find stack address for",frame.f_code.co_filename, frame.f_lineno-1
# Use this one, even tho it is wrong :-(
address = axdebug.GetStackAddress()
frameInfo = DebugStackFrame(frame, frame.f_lineno-1, cc), address, address+1, 0, None
infos.append(frameInfo)
# print "- Kept!"
# else:
# print "- rejected"
frame = frame.f_back
gateways.EnumDebugStackFrames.__init__(self, infos, 0)
# def __del__(self):
# print "EnumDebugStackFrames dieing"
def Next(self, count):
return gateways.EnumDebugStackFrames.Next(self, count)
# def _query_interface_(self, iid):
# from win32com.util import IIDToInterfaceName
# print "EnumDebugStackFrames QI with %s (%s)" % (IIDToInterfaceName(iid), str(iid))
# return 0
def _wrap(self, obj):
# This enum returns a tuple, with 2 com objects in it.
obFrame, min, lim, fFinal, obFinal = obj
obFrame = _wrap(obFrame, axdebug.IID_IDebugStackFrame)
if obFinal:
obFinal = _wrap(obFinal, pythoncom.IID_IUnknown)
return obFrame, min, lim, fFinal, obFinal
class DebugStackFrame(gateways.DebugStackFrame):
def __init__(self, frame, lineno, codeContainer):
self.frame = frame
self.lineno = lineno
self.codeContainer = codeContainer
self.expressionContext = None
# def __del__(self):
# print "DSF dieing"
def _query_interface_(self, iid):
if iid==axdebug.IID_IDebugExpressionContext:
if self.expressionContext is None:
self.expressionContext = _wrap(expressions.ExpressionContext(self.frame), axdebug.IID_IDebugExpressionContext)
return self.expressionContext
# from win32com.util import IIDToInterfaceName
# print "DebugStackFrame QI with %s (%s)" % (IIDToInterfaceName(iid), str(iid))
return 0
#
# The following need implementation
def GetThread(self):
""" Returns the thread associated with this stack frame.
Result must be a IDebugApplicationThread
"""
RaiseNotImpl("GetThread")
def GetCodeContext(self):
offset = self.codeContainer.GetPositionOfLine(self.lineno)
return self.codeContainer.GetCodeContextAtPosition(offset)
#
# The following are usefully implemented
def GetDescriptionString(self, fLong):
filename = self.frame.f_code.co_filename
s = ""
if 0: #fLong:
s = s + filename
if self.frame.f_code.co_name:
s = s + self.frame.f_code.co_name
else:
s = s + "<lambda>"
return s
def GetLanguageString(self, fLong):
if fLong:
return "Python ActiveX Scripting Engine"
else:
return "Python"
def GetDebugProperty(self):
return _wrap(StackFrameDebugProperty(self.frame), axdebug.IID_IDebugProperty)
class DebugStackFrameSniffer:
_public_methods_ = ["EnumStackFrames"]
_com_interfaces_ = [axdebug.IID_IDebugStackFrameSniffer]
def __init__(self, debugger):
self.debugger = debugger
trace("DebugStackFrameSniffer instantiated")
# def __del__(self):
# print "DSFS dieing"
def EnumStackFrames(self):
trace("DebugStackFrameSniffer.EnumStackFrames called")
return _wrap(EnumDebugStackFrames(self.debugger), axdebug.IID_IEnumDebugStackFrames)
# A DebugProperty for a stack frame.
class StackFrameDebugProperty:
_com_interfaces_ = [axdebug.IID_IDebugProperty]
_public_methods_ = ['GetPropertyInfo', 'GetExtendedInfo', 'SetValueAsString',
'EnumMembers', 'GetParent'
]
def __init__(self, frame):
self.frame = frame
def GetPropertyInfo(self, dwFieldSpec, nRadix):
RaiseNotImpl("StackFrameDebugProperty::GetPropertyInfo")
def GetExtendedInfo(self): ### Note - not in the framework.
RaiseNotImpl("StackFrameDebugProperty::GetExtendedInfo")
def SetValueAsString(self, value, radix):
#
RaiseNotImpl("DebugProperty::SetValueAsString")
def EnumMembers(self, dwFieldSpec, nRadix, iid):
print("EnumMembers", dwFieldSpec, nRadix, iid)
from . import expressions
return expressions.MakeEnumDebugProperty(self.frame.f_locals, dwFieldSpec, nRadix, iid, self.frame)
def GetParent(self):
# return IDebugProperty
RaiseNotImpl("DebugProperty::GetParent")

View file

@ -0,0 +1,114 @@
# Utility function for wrapping objects. Centralising allows me to turn
# debugging on and off for the entire package in a single spot.
import sys
import win32com.server.util
from win32com.server.exception import Exception
import winerror
import win32api
import os
try:
os.environ["DEBUG_AXDEBUG"]
debugging = 1
except KeyError:
debugging = 0
def trace(*args):
if not debugging: return
print(str(win32api.GetCurrentThreadId()) + ":", end=' ')
for arg in args:
print(arg, end=' ')
print()
# The AXDebugging implementation assumes that the returned COM pointers are in
# some cases identical. Eg, from a C++ perspective:
# p->GetSomeInterface( &p1 );
# p->GetSomeInterface( &p2 );
# p1==p2
# By default, this is _not_ true for Python.
# (Now this is only true for Document objects, and Python
# now does ensure this.
all_wrapped = {}
def _wrap_nodebug(object, iid):
return win32com.server.util.wrap(object, iid)
def _wrap_debug(object, iid):
import win32com.server.policy
dispatcher = win32com.server.policy.DispatcherWin32trace
return win32com.server.util.wrap(object, iid, useDispatcher = dispatcher)
if debugging:
_wrap = _wrap_debug
else:
_wrap = _wrap_nodebug
def _wrap_remove(object, iid = None):
# Old - no longer used or necessary!
return
def _dump_wrapped():
from win32com.server.util import unwrap
print("Wrapped items:")
for key, items in all_wrapped.items():
print(key, end=' ')
try:
ob = unwrap(key)
print(ob, sys.getrefcount(ob))
except:
print("<error>")
def RaiseNotImpl(who = None):
if who is not None:
print("********* Function %s Raising E_NOTIMPL ************" % (who))
# Print a sort-of "traceback", dumping all the frames leading to here.
try:
1/0
except:
frame = sys.exc_info()[2].tb_frame
while frame:
print("File: %s, Line: %d" % (frame.f_code.co_filename, frame.f_lineno))
frame = frame.f_back
# and raise the exception for COM
raise Exception(scode=winerror.E_NOTIMPL)
import win32com.server.policy
class Dispatcher(win32com.server.policy.DispatcherWin32trace):
def __init__(self, policyClass, object):
win32com.server.policy.DispatcherTrace.__init__(self, policyClass, object)
import win32traceutil # Sets up everything.
# print "Object with win32trace dispatcher created (object=%s)" % `object`
def _QueryInterface_(self, iid):
rc = win32com.server.policy.DispatcherBase._QueryInterface_(self, iid)
# if not rc:
# self._trace_("in _QueryInterface_ with unsupported IID %s (%s)\n" % (IIDToInterfaceName(iid),iid))
return rc
def _Invoke_(self, dispid, lcid, wFlags, args):
print("In Invoke with", dispid, lcid, wFlags, args, "with object",self.policy._obj_)
try:
rc = win32com.server.policy.DispatcherBase._Invoke_(self, dispid, lcid, wFlags, args)
# print "Invoke of", dispid, "returning", rc
return rc
except Exception:
t, v, tb = sys.exc_info()
tb = None # A cycle
scode = v.scode
try:
desc = " (" + str(v.description) + ")"
except AttributeError:
desc = ""
print("*** Invoke of %s raised COM exception 0x%x%s" % (dispid, scode, desc))
except:
print("*** Invoke of %s failed:" % dispid)
typ, val, tb = sys.exc_info()
import traceback
traceback.print_exception(typ, val, tb)
raise

View file

@ -0,0 +1,19 @@
<HTML>
<SCRIPT Language="Python" RUNAT=Server>
# Just for the sake of the demo, our Python script engine
# will create a Python.Interpreter COM object, and call that.
# This is completely useless, as the Python Script Engine is
# completely normal Python, and ASP does not impose retrictions, so
# there is nothing the COM object can do that we can not do natively.
o = Server.CreateObject("Python.Interpreter")
Response.Write("Python says 1+1=" + str(o.Eval("1+1")))
</SCRIPT>
</HTML>

View file

@ -0,0 +1,52 @@
<%@ Language=Python %>
<HTML>
<HEAD>
<BODY BACKGROUND="/samples/images/backgrnd.gif">
<TITLE>Python test</TITLE>
</HEAD>
<BODY BGCOLOR="FFFFFF">
<SCRIPT Language="Python" RUNAT=Server>
# NOTE that the <% tags below execute _before_ these tags!
Response.Write("Hello from Python<P>")
Response.Write("Browser is "+bc.browser)
import win32api # Should be no problem using win32api in ASP pages.
Response.Write("<p>Win32 username is "+win32api.GetUserName())
</SCRIPT>
<BODY BGCOLOR="FFFFFF">
<%
import sys
print sys.path
from win32com.axscript.asputil import *
print "Hello"
print "There"
print "How are you"
%>
<%bc = Server.CreateObject("MSWC.BrowserType")%>
<BODY BGCOLOR="FFFFFF">
<table border=1>
<tr><td>Browser</td><td> <%=bc.browser %>
<tr><td>Version</td><td> <%=bc.version %> </td></TR>
<tr><td>Frames</td><td>
<%Response.Write( iif(bc.frames, "TRUE", "FALSE")) %></td></TR>
<tr><td>Tables</td><td>
<%Response.Write( iif (bc.tables, "TRUE", "FALSE")) %></td></TR>
<tr><td>BackgroundSounds</td><td>
<%Response.Write( iif(bc.BackgroundSounds, "TRUE", "FALSE"))%></td></TR>
<tr><td>VBScript</td><td>
<%Response.Write( iif(bc.vbscript, "TRUE", "FALSE"))%></td></TR>
<tr><td>JavaScript</td><td>
<%Response.Write( iif(bc.javascript, "TRUE", "FALSE"))%></td></TR>
</table>
</body>
</html>

View file

@ -0,0 +1,4 @@
<%@ language=python%>
<html>
<%Response.Redirect("test1.html")%>
</html>

View file

@ -0,0 +1,10 @@
<html>
<head>
<body>
GOT There
<script language=javascript>
location.href ="http://192.168.0.1/Python/interrupt/test.asp"
</script>
</body>
</head>
</html>

View file

@ -0,0 +1,6 @@
<%@ language =Python%>
<html>
<head>
<%Response.Redirect("test.html")%>
</head>
</html>

View file

@ -0,0 +1,11 @@
<html>
<head>
<body>
GOT HERE
<script language=javascript>
location.href ="http://192.168.0.1/Python/interrupt/test1.asp"
</script>
</body>
</head>
</html>

View file

@ -0,0 +1,11 @@
<HTML>
<SCRIPT Language="Python" RUNAT=Server>
for i in range(3,8):
Response.Write("<FONT SIZE=%d>Hello World!!<BR>" % i)
</SCRIPT>
</HTML>

View file

@ -0,0 +1,25 @@
<HTML>
<HEAD>
<base target="text">
<TITLE> Internet Workshop </TITLE>
</HEAD>
<BODY leftmargin=8 bgcolor="#FFFFFF" VLINK="#666666" LINK="#FF0000">
<FONT FACE="ARIAL,HELVETICA" SIZE="2">
<P>
<BR>
<P><FONT FACE="ARIAL,HELVETICA" SIZE="5"><B>Python AX Script Engine</B></FONT>
<BR>Demo using the Marquee Control
<BR>Mark Hammond.
<P>This is really quite a boring demo, as the Marquee control does everything. However, there is Python code behind the buttons that change the speed. This code is all of 2 lines per button!!!
<P>For more information on Python as an ActiveX scripting language, see
<P><B>Python</B>
<BR><A HREF="http://www.python.org">http://www.python.org</A>
</FONT>
</BODY>
</HTML>

View file

@ -0,0 +1,116 @@
<HTML>
<HEAD><TITLE>Python Script sample: Calculator</TITLE></HEAD>
<BODY><FONT FACE=ARIAL SIZE=3> <!-- global default -->
<SCRIPT LANGUAGE="Python">
# globals
Accum = 0.0 # Previous number (operand) awaiting operation
FlagNewNum = 1 # Flag to indicate a new number (operand) is being entered
NullOp = lambda x,y: y
PendingOp = NullOp# Pending operation waiting for completion of second operand
numberButNames = ['Zero','One','Two','Three','Four','Five','Six','Seven','Eight','Nine']
def NumPressed(Num):
print "NumPressed", Num
global FlagNewNum
if FlagNewNum:
ax.document.Keypad.ReadOut.Value = Num
FlagNewNum = None
else:
if ax.document.Keypad.ReadOut.Value == "0":
ax.document.Keypad.ReadOut.Value = str(Num)
else:
ax.document.Keypad.ReadOut.Value= ax.document.Keypad.ReadOut.Value + str(Num)
# Dynamically create handlers for all the decimal buttons.
# (ie, this will dynamically create "One_OnClick()"... etc handlers
for i in range(len(numberButNames)):
exec "def %s_OnClick():\tNumPressed(%d)\n" % (numberButNames[i],i)
def Decimal_OnClick():
global curReadOut, FlagNewNum
curReadOut = ax.document.Keypad.ReadOut.Value
if FlagNewNum:
curReadOut = "0."
FlagNewNum = None
else:
if not ("." in curReadOut):
curReadOut = curReadOut + "."
ax.document.Keypad.ReadOut.Value = curReadOut
import sys, string
def Operation(Op, fn):
global FlagNewNum, PendingOp, Accum
ReadOut = ax.document.Keypad.ReadOut.Value
print "Operation", Op, ReadOut, PendingOp, Accum
if FlagNewNum:
# User is hitting op keys repeatedly, so don't do anything
PendingOp = NullOp
else:
FlagNewNum = 1
Accum = PendingOp( Accum, string.atof(ReadOut) )
ax.document.Keypad.ReadOut.Value = str(Accum)
PendingOp = fn
def ClearEntry_OnClick():
# Remove current number and reset state
global FlagNewNum
ax.document.Keypad.ReadOut.Value = "0"
FlagNewNum = 1
def Clear_OnClick():
global Accum, PendingOp
Accum = 0
PendingOp = NullOp
ClearEntry_OnClick()
def Neg_OnClick():
ax.document.Keypad.ReadOut.Value = str(-string.atof(ax.document.Keypad.ReadOut.Value))
</SCRIPT>
<form action="" Name="Keypad">
<TABLE>
<B>
<TABLE BORDER=2 WIDTH=50 HEIGHT=60 CELLPADDING=1 CELLSPACING=5>
<CAPTION ALIGN=top> <b>Calculator</b><p> </CAPTION>
<TR>
<TD COLSPAN=3 ALIGN=MIDDLE><INPUT NAME="ReadOut" TYPE="Text" SIZE=24 VALUE="0" WIDTH=100%></TD>
<TD></TD>
<TD><INPUT NAME="Clear" TYPE="Button" VALUE=" C " ></TD>
<TD><INPUT NAME="ClearEntry" TYPE="Button" VALUE=" CE " ></TD>
</TR>
<TR>
<TD><INPUT NAME="Seven" TYPE="Button" VALUE=" 7 " ></TD>
<TD><INPUT NAME="Eight" TYPE="Button" VALUE=" 8 " ></TD>
<TD><INPUT NAME="Nine" TYPE="Button" VALUE=" 9 " ></TD>
<TD></TD>
<TD><INPUT NAME="Neg" TYPE="Button" VALUE=" +/- " ></TD>
<TD><INPUT NAME="Percent" TYPE="Button" VALUE=" % " OnClick="Operation('%', lambda x,y: x*y/100.0)"></TD>
</TR>
<TR>
<TD><INPUT NAME="Four" TYPE="Button" VALUE=" 4 " ></TD>
<TD><INPUT NAME="Five" TYPE="Button" VALUE=" 5 " ></TD>
<TD><INPUT NAME="Six" TYPE="Button" VALUE=" 6 " ></TD>
<TD></TD>
<TD ALIGN=MIDDLE><INPUT NAME="Plus" TYPE="Button" VALUE=" + " OnClick="Operation('+', lambda x,y: x+y)"></TD>
<TD ALIGN=MIDDLE><INPUT NAME="Minus" TYPE="Button" VALUE=" - " OnClick="Operation('-', lambda x,y: x-y)"></TD>
</TR>
<TR>
<TD><INPUT NAME="One" TYPE="Button" VALUE=" 1 " ></TD>
<TD><INPUT NAME="Two" TYPE="Button" VALUE=" 2 " ></TD>
<TD><INPUT NAME="Three" TYPE="Button" VALUE=" 3 " ></TD>
<TD></TD>
<TD ALIGN=MIDDLE><INPUT NAME="Multiply" TYPE="Button" VALUE=" * " OnClick="Operation('*', lambda x,y: x*y)" ></TD>
<TD ALIGN=MIDDLE><INPUT NAME="Divide" TYPE="Button" VALUE=" / " OnClick="Operation('/', lambda x,y: x/y)" ></TD>
</TR>
<TR>
<TD><INPUT NAME="Zero" TYPE="Button" VALUE=" 0 " ></TD>
<TD><INPUT NAME="Decimal" TYPE="Button" VALUE=" . " ></TD>
<TD COLSPAN=3></TD>
<TD><INPUT NAME="Equals" TYPE="Button" VALUE=" = " OnClick="Operation('=', lambda x,y: x)"></TD>
</TR></TABLE></TABLE></B>
</FORM>
</FONT></BODY></HTML>

View file

@ -0,0 +1,16 @@
<HTML>
<BODY>
<SCRIPT>
b="Hello There, how are you"
</SCRIPT>
<SCRIPT LANGUAGE="Python">
print "Hello"
a="Hi there"
document.write("Hello<P>")
alert("Hi there")
</SCRIPT>
</BODY>
</HTML>

View file

@ -0,0 +1,26 @@
<HTML>
<HEAD>
<TITLE>Python AXScript Demos</TITLE>
</HEAD>
<SCRIPT LANGUAGE="Python">
def Window_OnLoad():
pass
# import win32traceutil
# print "Frames are", ax.window.frames._print_details_()
# print "Frame 0 href = ", ax.frames.Item(0).location.href
def Name_OnLoad():
print "Frame loading"
</SCRIPT>
<FRAMESET FRAMEBORDER=1 COLS = "250, *">
<FRAME SRC="demo_menu.htm">
<FRAME SRC="demo_check.htm" NAME="Body">
</FRAMESET>
</HTML>

View file

@ -0,0 +1,42 @@
<HTML>
<H1>Engine Registration</H1>
<BODY>
<p>The Python ActiveX Scripting Engine is not currently registered.<p>
<p>Due to a <a href="http://starship.python.net/crew/mhammond/win32/PrivacyProblem.html">privacy
concern</a> discovered in the engine, the use of Python inside IE has been disabled.</p>
Before any of the supplied demos will work, the engine must be successfully registered.
<P>To install a version of the engine, that does work with IE, you can execute the Python program
<CODE>win32com\axscript\client\pyscript_rexec.py</CODE> must be run. You can either do this manually, or follow the instructions below.</p>
<H2>Register the engine now!</H2>
<p>If you have read about the <a href="http://starship.python.net/crew/mhammond/win32/PrivacyProblem.html">privacy
concern</a> and still wish to register the engine, just follow the process outlined below:</p>
<OL>
<LI>Click on the link below
<LI><B>A dialog will be presented asking if the file should be opened or saved to disk. Select "Open it".</B>
<LI>A Console program will briefly open, while the server is registered.
</OL>
<P><A HREF="..\..\..\client\pyscript_rexec.py">Register the engine now</A>
<H2>Checking the registration</H2>
After the registration is complete, simply hit the Reload button. If the
registration was successful, the page will change to the Python/AvtiveX Demo Page.
<SCRIPT LANGUAGE="Python">
try:
window.open("demo_intro.htm", "Body")
except:
history.back()
</SCRIPT>
</BODY></HTML>

View file

@ -0,0 +1,38 @@
<HTML>
<BODY>
<H1>
<MARQUEE NAME="Marquee1" DIRECTION=LEFT BEHAVIOR=SCROLL SCROLLAMOUNT=10 SCROLLDELAY=200
>Python ActiveX Scripting Demonstation
</MARQUEE>
</H1>
<p>Congratulations on installing the Python ActiveX Scripting Engine</p>
<p>Be warned that there is a <a href="http://starship.python.net/crew/mhammond/win32/PrivacyProblem.html">privacy
concern</a> with this engine. Please read this information, including how to disable the feature.</p>
<H3>Object model</H3>
<P>Except as described below, the object module exposed should be similar to that exposed
by Visual Basic, etc. Due to the nature of ActiveX Scripting, the details for each
host are different, but Python should work "correctly".
<P>The object model exposed via Python for MSIE is not as seamless as VB. The biggest limitation is
the concept of a "local" namespace. For example, in VB, you can
code <code>text="Hi there"</code>, but in Python, you must code
<code>MyForm.ThisButton.Text="Hi There"</code>. See the <A HREF="foo2.htm">foo2</A> sample
for futher details.
<H3>Known bugs and problems</H3>
<UL>
<LI><P>This release seems to have broken Aaron's mouse-trace sample. No idea why, and Im supposed to be looking into it.
<LI><P>Builtin objects such as MARQUEE are giving me grief. Objects accessed via forms are generally
no problem.
<LI><P>If you are trying to use Python with the Windows Scripting Host, note that
.pys files are not correct registered - you will need to explicitely
specify either cscript.exe or wscript.exe on the command line.
</UL>
</BODY></HTML>

View file

@ -0,0 +1,16 @@
<HTML>
<BODY>
<H1>Scripting Demos</H1>
<P>An <A HREF="demo_check.htm" TARGET=Body>Introduction</A> to the
scripting engine.
<P>The <A HREF="calc.htm" TARGET=Body>Calculator Demo</A> is a very
cool sample written by Aaron Watters.
<P><A HREF="mouseTrack.htm" TARGET=Body>Mouse track</A> is another of
Aaron's samples, and shows how fast the Python engine is!
<P>The <A HREF="foo2.htm" TARGET=Body>foo2 sample</A> is mainly used
for debugging and testing, but does show some forms in action.

View file

@ -0,0 +1,25 @@
<HTML>
<BODY>
A page generated by Python
<SCRIPT LANGUAGE="XXXVBScript">
document.open()
document.writeLn "<P>Hello from VBScript"
document.close()
</SCRIPT>
<SCRIPT LANGUAGE="Python">
ax.document.write("<P>Hello from Python")
ax.document.close()
ax.document.open()
ax.document.write("<P>Hello again from Python")
ax.document.close()
def Window_OnLoad():
pass
# ax.document.write("<P>Hello from Load from Python")
# ax.document.close()
</SCRIPT>
</BODY>
</HTML>

View file

@ -0,0 +1,105 @@
<HTML>
<BODY>
<SCRIPT>
b="Hello"
</SCRIPT>
<SCRIPT LANGUAGE="Python">
import win32traceutil
import sys
print "Hello"
a="Hi there"
print "Location is", document.location
document.write("Hello", " from version ", 2, " of the Python AXScript Engine","<P>")
document.writeln("This is Python", sys.version)
</SCRIPT>
<P>The caption on the first button is set by the Window Load code. Clicking
that button changes the text in the first edit box.
<P>The second button changes its own text when clicked.
<P>The fourth button calls a global function, defined in the global 'script' scope,
rather than the 'MyForm' scope.
<FORM NAME="MyForm" METHOD="GET">
<SCRIPT LANGUAGE="Python">
print "Hello from in the form"
</SCRIPT>
<INPUT NAME="Button1" TYPE="Button" OnClick="MyForm.Text1.value='Hi'" LANGUAGE="Python">
<INPUT TYPE="TEXT" SIZE=25 NAME="Text1">
<INPUT NAME="Button2" TYPE="Button" VALUE="Click for 'Hi'" OnClick="a='Howdy'; MyForm.Button2.value='Hi'" LANGUAGE="Python">
<INPUT NAME="Button3" TYPE="Button" VALUE="Click for URL" OnClick="MyForm.Text2.value=document.location" LANGUAGE="Python">
<INPUT TYPE="TEXT" SIZE=25 NAME="Text2">
<INPUT NAME="Button4" TYPE="Button" VALUE="Call global fn" OnClick="foo1()" LANGUAGE="Python">
<INPUT NAME="Button5" TYPE="Button" VALUE="Script for... Test">
<script for="Button5" event="onClick" language="Python">
print "HelloThere";
window.alert("Hello")
def ATest():
print "Hello from ATEst"
ATest()
</script>
<INPUT NAME="Button6" TYPE="Button" VALUE="Set Other" OnClick="Form2.Text1.Value='Hi from other'" LANGUAGE="Python">
</FORM><BR>
<P>
And here is a second form
<P>
<FORM NAME="Form2" METHOD="GET">
<INPUT NAME="Button1" TYPE="Button" OnClick="Form2.Text1.Value='Hi'" LANGUAGE="Python">
<INPUT NAME="Button2" TYPE="Button" VALUE="Set Other" OnClick="MyForm.Text1.Value='Hi from other'" LANGUAGE="Python">
<INPUT TYPE="TEXT" SIZE=25 NAME="Text1">
<INPUT NAME="ButRExec" TYPE="Button" VALUE="RExec fail" OnClick="import win32api;win32api.MessageBox(0,'Oops')" LANGUAGE="Python">
<INPUT NAME="ButRExec2" TYPE="Button" VALUE="RExec fail 2" OnClick="import sys,win32traceutil;print sys.modules;from win32com.client import dynamic;import win32com.client.dynamic, pythoncom, win32com.client;o=win32com.client.Dispatch('Word.Application')" LANGUAGE="Python">
<INPUT NAME="ButVB" TYPE="Button" VALUE="VBScript Button" OnClick='alert("Hi from VBScript")'>
<INPUT NAME="ButCallChain" TYPE="Button" VALUE="Multi-Language call" OnClick='CallPython()'>
</FORM><BR>
<SCRIPT LANGUAGE="VBScript">
function CallPython()
alert("Hello from VB - Im about to call Python!")
PythonGlobalFunction()
end function
</SCRIPT>
<SCRIPT LANGUAGE="JScript">
function JScriptFunction()
{
alert("Hello from JScript");
}
</SCRIPT>
<SCRIPT LANGUAGE="Python">
x=13
def foo1():
y = 14
for name, item in globals().items():
print name, `item`
alert ("Hello from AXCode")
print "Y is ",y
def PythonGlobalFunction():
window.alert("Hello from Python - Im about to call JScript!")
window.JScriptFunction()
def Window_OnLoad():
print "X is", x
print "a is", a
# print "------ GLOBALS ----------"
# for n,v in globals().items():
# print n,'=',v
print "MyForm is", MyForm
print "MyForm is repr", `MyForm`
print "MyForm.Button1 is", `MyForm.Button1`
MyForm.Button1.Value = "Python Rules!"
Form2.Button1.value = "Form2!"
MyForm.Text1.value = document.location
</SCRIPT>
</BODY>
</HTML>

View file

@ -0,0 +1,25 @@
<HTML>
<BODY>
<FORM NAME="TestForm" METHOD="POST" >
<INPUT TYPE="TEXT" SIZE=25 NAME="Name">Name<br>
<INPUT TYPE="TEXT" SIZE=25 NAME="Address">Address<br>
<INPUT TYPE=SUBMIT
</FORM>
<SCRIPT LANGUAGE="Python" for="TestForm" Event="onSubmit">
return Validate()
</SCRIPT>
<SCRIPT LANGUAGE="Python">
def Validate():
if not TestForm.Name.Value or not TestForm.Address.Value:
ax.alert("You must enter a name and address.")
return 1
return 0
</SCRIPT>
</BODY>
</HTML>

View file

@ -0,0 +1,60 @@
<HTML>
<HEAD>
<base target="text">
<TITLE> Internet Workshop </TITLE>
</HEAD>
<BODY leftmargin=8 bgcolor="#FFFFFF" VLINK="#666666" LINK="#FF0000">
<FONT FACE="ARIAL,HELVETICA" SIZE="2">
<P>
<BR>
<P><FONT FACE="ARIAL,HELVETICA" SIZE="5"><B>Marquee Demo</B></FONT>
<P>
<OBJECT
ID="Marquee1"
CLASSID="CLSID:1A4DA620-6217-11CF-BE62-0080C72EDD2D"
CODEBASE="/workshop/activex/gallery/ms/marquee/other/marquee.ocx#Version=4,70,0,1112"
TYPE="application/x-oleobject"
WIDTH=100%
HEIGHT=80
>
<PARAM NAME="szURL" VALUE="marqueeText1.htm">
<PARAM NAME="ScrollPixelsX" VALUE="0">
<PARAM NAME="ScrollPixelsY" VALUE="-5">
<PARAM NAME="ScrollDelay" VALUE="100">
<PARAM NAME="Whitespace" VALUE="0">
</OBJECT>
<br> <br>
<INPUT TYPE="Button" NAME="btnFaster" VALUE="Faster">
<INPUT TYPE="Button" NAME="btnNormal" VALUE="Normal">
<INPUT TYPE="Button" NAME="btnSlower" VALUE="Slower">
<SCRIPT Language="Python">
def btnFaster_Onclick():
ax.Marquee1.ScrollDelay = 0
def btnNormal_Onclick():
ax.Marquee1.ScrollDelay = 50
def btnSlower_Onclick():
ax.Marquee1.ScrollDelay = 300
</SCRIPT>
<P>&nbsp;
<HR>
<B>Notes:</B>
<P>
</FONT>
</BODY>
</HTML>

View file

@ -0,0 +1,83 @@
<HTML>
<HEAD><TITLE>Python Scripting sample: Mouse tracking</TITLE></HEAD>
<BODY BGCOLOR="#FFFFFF" TOPMARGIN=8>
<FONT SIZE=5>
<TABLE Border=0><TR VALIGN=MIDDLE><TD>
<A ID="Image"> <IMG
SRC="file:..\..\..\..\..\win32com\html\image\pycom_blowing.gif"
ALT="Clickable Map Image" HEIGHT=113 WIDTH=624 BORDER=0></A>
</TD></TR>
<TR><TD>&nbsp;</TD></TR>
<TR VALIGN=MIDDLE><TD VALIGN=MIDDLE ALIGN=CENTER><FONT SIZE=5><INPUT
TYPE="text" NAME="TxtLinkDescription" SIZE=50></FONT></TD></TR></TABLE>
</FONT>
<P>
A mouse tracking demo. Move the mouse over the image above...
<SCRIPT Language="Python">
<!--
# Remember the last location clicked
#print "here we go", 1
mx = my = 0
# class for rectangle testing
class rect:
def __init__(self, lowx, lowy, upx, upy, desc, url):
self.lowx, self.lowy, self.upx, self.upy, self.desc, self.url = \
lowx, lowy, upx, upy, desc, url
def inside(self, x, y):
# print (x,y), "inside", self.desc,
result = self.lowx <= x <= self.upx and self.lowy <= y <= self.upy
# print result
return result
def mouse_move(self):
# print "move", self.desc
ax.TxtLinkDescription.Value = coords + " - " + self.desc
def onclick(self):
# print "click", self.desc
ax.TxtLinkDescription.Value = coords +" click! " + `self.url`
if self.url: ax.location = self.url
blows = "Blows away "
rects =[rect(12,48,59,101,blows+"Visual Basic", ""),
rect(107,0,172,58,blows+"Internet Explorer", ""),
rect(193,0,261,56,blows+"Microsoft Access", ""),
rect(332,43,392,93,blows+"Microsoft Word", ""),
rect(457,52,521,99,blows+"Microsoft Excel", ""),
rect(537,12,613,85,"Python blows them all away!", "http://www.python.org"),
]
default = rect(0,0,0,0,"Click on an icon","")
def Image_MouseMove(s, b, x, y):
global mx, my, coords
coords =`(x,y)`
# print coords,
mx, my = x, y
for r in rects:
if r.inside(x,y):
# print r.desc
r.mouse_move()
break
else:
# print default.desc
default.mouse_move()
def Image_OnClick():
for r in rects:
if r.inside(mx,my):
r.onclick()
break
-->
</SCRIPT>
<P>
</FONT>
</BODY>
</HTML>

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -0,0 +1,34 @@
#app=WScript.Application
#app._print_details_() # Use this to see what Python knows about a COM object.
g_index = 1
# A procedure, using a global.
def Show(desc, value = None):
global g_index # Need global for g_index, as I locally assign.
# No global needed to "xl" object, as only referenced.
# Also note "xl" is assigned later in the script - ie, Python is very late bound.
xl.Cells(g_index, 1).Value = desc
if value: xl.Cells(g_index, 2).Value = value
g_index = g_index + 1
xl = WScript.CreateObject("Excel.Application")
import sys
xl.Visible = 1
#xl.Workbooks().Add() # Excel versions before 98
xl.Workbooks.Add()
# Show the WScript properties.
Show("Application Friendly Name", WScript.Name)
Show("Application Version", WScript.Version)
Show("Application Context: Fully Qualified Name", WScript.FullName)
Show("Application Context: Path Only", WScript.Path)
Show("State of Interactive Mode", WScript.Interactive)
Show("All script arguments:")
args = WScript.Arguments
for i in range(0,args.Count()):
Show("Arg %d" % i, args(i))

View file

@ -0,0 +1,45 @@
""" Windows Script Host Sample Script
' Ported to Python
'
' ------------------------------------------------------------------------
' Copyright (C) 1996 Microsoft Corporation
'
' You have a royalty-free right to use, modify, reproduce and distribute
' the Sample Application Files (and/or any modified version) in any way
' you find useful, provided that you agree that Microsoft has no warranty,
' obligations or liability for any Sample Application Files.
' ------------------------------------------------------------------------
'
' This sample demonstrates how to write/delete from the registry.
"""
WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Popup("This script shows how to use registry related methods.", 2)
WshShell.Popup("Create key HKCU\\Foo with value 'Top level key'")
WshShell.RegWrite("HKCU\\Foo\\", "Top level key")
WshShell.Popup("Create key HKCU\\Foo\\Bar with value 'Second level key'")
WshShell.RegWrite( "HKCU\\Foo\\Bar\\", "Second level key")
WshShell.Popup ("Set value HKCU\\Foo\\Value to REG_SZ 1")
WshShell.RegWrite( "HKCU\\Foo\\Value", 1)
WshShell.Popup ("Set value HKCU\\Foo\\Bar to REG_DWORD 2")
WshShell.RegWrite ("HKCU\\Foo\\Bar", 2, "REG_DWORD")
WshShell.Popup ("Set value HKCU\\Foo\\Bar to REG_EXPAND_SZ '3'")
WshShell.RegWrite ("HKCU\\Foo\\Bar\\Baz", "%SystemRoot%\\Foo")
WshShell.Popup ("Delete value HKCU\\Foo\\Bar\\Baz")
WshShell.RegDelete ("HKCU\\Foo\\Bar\\Baz")
WshShell.Popup ("Delete key HKCU\\Foo\\Bar")
WshShell.RegDelete ("HKCU\\Foo\\Bar\\")
WshShell.Popup ("Delete key HKCU\\Foo")
WshShell.RegDelete ("HKCU\\Foo\\")
WScript.Echo ("Done")

View file

@ -0,0 +1,15 @@
# Testall - test core AX support.
# Test "Restricted Execution" (ie, IObjectSafety).
# This will fail if in a "restricted execution" environment, but
# will silenty do nothing of not restricted. This same line in an MSIE
# script would cause an exception.
print("Importing win32api...")
import win32api
if 1==1:
print("Hi")
WScript.Echo("Hello from WScript")
#fail

View file

@ -0,0 +1,4 @@
# See if we have a special directory for the binaries (for developers)
import win32com
win32com.__PackageSupportBuildPath__(__path__)

View file

@ -0,0 +1,12 @@
"""A utility module for ASP (Active Server Pages on MS Internet Info Server.
Contains:
iif -- A utility function to avoid using "if" statements in ASP <% tags
"""
def iif(cond, t, f):
if cond:
return t
else:
return f

View file

@ -0,0 +1 @@
# This is a Python package

View file

@ -0,0 +1,209 @@
import traceback, sys, string
import win32com.server.util
from win32com.util import IIDToInterfaceName
from win32com.client.util import Enumerator
from win32com.server.exception import COMException
import pythoncom
from .framework import trace
from win32com.axdebug import axdebug, gateways, contexts, stackframe, documents, adb
from win32com.axdebug.codecontainer import SourceCodeContainer
from win32com.axdebug.util import _wrap, _wrap_remove
import win32com.client.connect
import win32api, winerror
import os
try:
os.environ["DEBUG_AXDEBUG"]
debuggingTrace = 1 # Should we print "trace" output?
except KeyError:
debuggingTrace = 0
def trace(*args):
"""A function used instead of "print" for debugging output.
"""
if not debuggingTrace:
return
print(win32api.GetCurrentThreadId(), end=' ')
for arg in args:
print(arg, end=' ')
print()
# Note that the DebugManager is not a COM gateway class for the
# debugger - but it does create and manage them.
class DebugManager:
_debugger_interfaces_ = [axdebug.IID_IActiveScriptDebug]
def __init__(self, scriptEngine):
self.scriptEngine = scriptEngine
self.adb = adb.Debugger()
self.rootNode = None
self.debugApplication = None
self.ccProvider = documents.CodeContainerProvider()
try:
self.scriptSiteDebug = scriptEngine.GetScriptSite(axdebug.IID_IActiveScriptSiteDebug)
except pythoncom.com_error:
# No debugger interface (ie, dumb host). Do the extra work.
trace("Scripting site has no debugger interface")
self.scriptSiteDebug = None
# Get the debug application object.
self.debugApplication = None
if self.scriptSiteDebug is not None:
# Spec says that we should test for this, and if it fails revert to
# PDM application.
try:
self.debugApplication = self.scriptSiteDebug.GetApplication()
self.rootNode = self.scriptSiteDebug.GetRootApplicationNode()
except pythoncom.com_error:
self.debugApplication = None
if self.debugApplication is None:
# Try to get/create the default one
# NOTE - Dont catch exceptions here - let the parent do it,
# so it knows debug support is available.
pdm=pythoncom.CoCreateInstance(axdebug.CLSID_ProcessDebugManager,None,pythoncom.CLSCTX_ALL, axdebug.IID_IProcessDebugManager)
self.debugApplication = pdm.GetDefaultApplication()
self.rootNode = self.debugApplication.GetRootNode()
assert self.debugApplication is not None, "Need to have a DebugApplication object by now!"
self.activeScriptDebug = None
if self.debugApplication is not None:
self.adb.AttachApp(self.debugApplication, self.ccProvider)
self.codeContainers = {}
self.activeScriptDebug = _wrap(ActiveScriptDebug(self, self.codeContainers), axdebug.IID_IActiveScriptDebug)
def Close(self):
# Called by the language engine when it receives a close request
if self.activeScriptDebug is not None:
_wrap_remove(self.activeScriptDebug)
self.activeScriptDebug = None
self.scriptEngine = None
self.rootNode = None
self.debugApplication = None
self.scriptSiteDebug = None
if self.ccProvider is not None:
self.ccProvider.Close()
self.ccProvider = None
self.codeContainers = {}
if self.adb:
self.adb.CloseApp()
self.adb = None
# print "Close complete"
def IsAnyHost(self):
"Do we have _any_ debugging interfaces installed?"
return self.debugApplication is not None
def IsSimpleHost(self):
return self.scriptSiteDebug is None
def HandleRuntimeError( self ):
"""Called by the engine when a runtime error occurs. If we have a debugger,
we let it know.
The result is a boolean which indicates if the error handler should call
IActiveScriptSite::OnScriptError()
"""
# if self.IsAnyHost:
# site = _wrap(self, axdebug.IID_IActiveScriptSite)
# breakResume, errorResume, fCallOnError = self.debugApplication(activeScriptErrorDebug, site)
# Do something with these!
# else:
trace("HandleRuntimeError")
fCallOnError = 1
return fCallOnError
def _query_interface_for_debugger_(self, iid):
if iid in self._debugger_interfaces_:
return self.activeScriptDebug
trace("DebugManager QI - unknown IID", iid)
return 0
def OnEnterScript(self):
trace("OnEnterScript")
try:
1/0
except:
# Bit of a hack - reach into engine.
baseFrame = sys.exc_info()[2].tb_frame.f_back
self.adb.SetupAXDebugging(baseFrame)
def OnLeaveScript(self):
trace("OnLeaveScript")
self.adb.ResetAXDebugging()
def AddScriptBlock(self, codeBlock):
# If we dont have debugging support, dont bother.
cc = DebugCodeBlockContainer(codeBlock, self.scriptSiteDebug)
if self.IsSimpleHost():
document = documents.DebugDocumentText(cc)
document = _wrap(document, axdebug.IID_IDebugDocument)
provider = documents.DebugDocumentProvider(document)
provider = _wrap(provider, axdebug.IID_IDebugDocumentProvider)
cc.debugDocument = document
newNode = self.debugApplication.CreateApplicationNode()
newNode.SetDocumentProvider(provider)
newNode.Attach(self.rootNode)
else:
newNode = None # Managed by smart host.
self.codeContainers[cc.sourceContext] = cc
self.ccProvider.AddCodeContainer(cc, newNode)
class DebugCodeBlockContainer(SourceCodeContainer):
def __init__(self, codeBlock, site):
self.codeBlock = codeBlock
SourceCodeContainer.__init__(self, codeBlock.codeText, codeBlock.GetFileName(), codeBlock.sourceContextCookie, codeBlock.startLineNumber, site)
def GetName(self, dnt):
if dnt==axdebug.DOCUMENTNAMETYPE_APPNODE:
return self.codeBlock.GetDisplayName()
elif dnt==axdebug.DOCUMENTNAMETYPE_TITLE:
return self.codeBlock.GetDisplayName()
# elif dnt==axdebug.DOCUMENTNAMETYPE_FILE_TAIL:
# elif dnt==axdebug.DOCUMENTNAMETYPE_URL:
else:
raise COMException(scode=winerror.S_FALSE)
class EnumDebugCodeContexts(gateways.EnumDebugCodeContexts):
def _wrap(self, ob):
return ob
class ActiveScriptDebug:
"""The class which implements the IActiveScriptDebug interface for the Active Script engine.
Only ever used by smart hosts.
"""
_public_methods_ = ["GetScriptTextAttributes", "GetScriptletTextAttributes", "EnumCodeContextsOfPosition"]
_com_interfaces_ = [axdebug.IID_IActiveScriptDebug]
def __init__(self, debugMgr, codeContainers):
self.debugMgr = debugMgr
self.scriptSiteDebug = debugMgr.scriptSiteDebug
self.codeContainers = codeContainers
def _Close(self):
self.debugMgr = None
self.scriptSiteDebug = None
self.codeContainers = {}
def _query_interface_(self, iid):
trace("DebuggerQI with", iid)
return _wrap(self.debugMgr.scriptEngine, iid)
def GetScriptTextAttributes(self, code, delim, flags):
container = SourceCodeContainer(code, "<Temp Code Block>")
return container.GetSyntaxColorAttributes()
def GetScriptletTextAttributes(self, code, delim, flags):
trace ("GetScriptletTextAttributes", code, delim, flags)
container = SourceCodeContainer(code, "<Temp Code Block>")
return container.GetSyntaxColorAttributes()
def EnumCodeContextsOfPosition(self, context, charOffset, numChars):
trace("EnumCodeContextsOfPosition", context, charOffset, numChars)
try:
context = self.codeContainers[context].GetCodeContextAtPosition(charOffset)
except KeyError:
raise COMException(scode=winerror.E_UNEXPECTED)
enum = EnumDebugCodeContexts([context])
return _wrap(enum, axdebug.IID_IEnumDebugCodeContexts)

View file

@ -0,0 +1,243 @@
"""Exception and error handling.
This contains the core exceptions that the implementations should raise
as well as the IActiveScriptError interface code.
"""
import sys, traceback
from win32com.axscript import axscript
import winerror
import win32com.server.exception
import win32com.server.util
import pythoncom
import re
debugging = 0
def FormatForAX(text):
"""Format a string suitable for an AX Host
"""
# Replace all " with ', so it works OK in HTML (ie, ASP)
return ExpandTabs(AddCR(text))
def ExpandTabs(text):
return re.sub('\t',' ', text)
def AddCR(text):
return re.sub('\n','\r\n',text)
class IActiveScriptError:
"""An implementation of IActiveScriptError
The ActiveX Scripting host calls this client whenever we report
an exception to it. This interface provides the exception details
for the host to report to the user.
"""
_com_interfaces_ = [axscript.IID_IActiveScriptError]
_public_methods_ = ["GetSourceLineText","GetSourcePosition","GetExceptionInfo"]
def _query_interface_(self, iid):
print("IActiveScriptError QI - unknown IID", iid)
return 0
def _SetExceptionInfo(self, exc):
self.exception = exc
def GetSourceLineText(self):
return self.exception.linetext
def GetSourcePosition(self):
ctx = self.exception.sourceContext
# Zero based in the debugger (but our columns are too!)
return ctx, self.exception.lineno + self.exception.startLineNo-1, self.exception.colno
def GetExceptionInfo(self):
return self.exception
class AXScriptException(win32com.server.exception.COMException):
"""A class used as a COM exception.
Note this has attributes which conform to the standard attributes
for COM exceptions, plus a few others specific to our IActiveScriptError
object.
"""
def __init__(self, site, codeBlock, exc_type, exc_value, exc_traceback):
# set properties base class shares via base ctor...
win32com.server.exception.COMException.__init__( self, \
description = "Unknown Exception", \
scode = winerror.DISP_E_EXCEPTION, \
source = "Python ActiveX Scripting Engine",
)
# And my other values...
if codeBlock is None:
self.sourceContext = 0
self.startLineNo = 0
else:
self.sourceContext = codeBlock.sourceContextCookie
self.startLineNo = codeBlock.startLineNumber
self.linetext = ""
self.__BuildFromException(site, exc_type, exc_value, exc_traceback)
def __BuildFromException(self, site, type , value, tb):
if debugging:
import linecache
linecache.clearcache()
try:
if issubclass(type, SyntaxError):
self._BuildFromSyntaxError(site, value, tb)
else:
self._BuildFromOther(site, type, value, tb)
except: # Error extracting traceback info!!!
traceback.print_exc()
# re-raise.
raise
def _BuildFromSyntaxError(self, site, exc, tb):
value = exc.args
# All syntax errors should have a message as element 0
try:
msg = value[0]
except:
msg = "Unknown Error (%s)" % (value,)
try:
(filename, lineno, offset, line) = value[1]
# Some of these may be None, which upsets us!
if offset is None:
offset = 0
if line is None:
line = ""
except:
msg = "Unknown"
lineno = 0
offset = 0
line = "Unknown"
self.description=FormatForAX(msg)
self.lineno = lineno
self.colno = offset - 1
self.linetext = ExpandTabs(line.rstrip())
def _BuildFromOther(self, site, exc_type, value, tb):
self.colno = -1
self.lineno = 0
if debugging: # Full traceback if debugging.
list=traceback.format_exception(exc_type, value, tb)
self.description = ExpandTabs(''.join(list))
return
# Run down the traceback list, looking for the first "<Script..>"
# Hide traceback above this. In addition, keep going down
# looking for a "_*_" attribute, and below hide these also.
hide_names = ["r_import","r_reload","r_open"] # hide from these functions down in the traceback.
depth = None
tb_top = tb
while tb_top:
filename, lineno, name, line = self.ExtractTracebackInfo(tb_top, site)
if filename[:7]=="<Script":
break
tb_top = tb_top.tb_next
format_items = []
if tb_top: # found one.
depth = 0
tb_look = tb_top
# Look down for our bottom
while tb_look:
filename, lineno, name, line = self.ExtractTracebackInfo(tb_look, site)
if name in hide_names:
break
# We can report a line-number, but not a filename. Therefore,
# we return the last line-number we find in one of our script
# blocks.
if filename.startswith("<Script"):
self.lineno = lineno
self.linetext = line
format_items.append((filename, lineno, name, line))
depth = depth + 1
tb_look = tb_look.tb_next
else:
depth = None
tb_top = tb
bits = ['Traceback (most recent call last):\n']
bits.extend(traceback.format_list(format_items))
if exc_type==pythoncom.com_error:
desc = "%s (0x%x)" % (value.strerror, value.hresult)
if value.hresult==winerror.DISP_E_EXCEPTION and value.excepinfo and value.excepinfo[2]:
desc = value.excepinfo[2]
bits.append("COM Error: "+desc)
else:
bits.extend(traceback.format_exception_only(exc_type, value))
# XXX - this utf8 encoding seems bogus. From well before py3k,
# we had the comment:
# > all items in the list are utf8 courtesy of Python magically
# > converting unicode to utf8 before compilation.
# but that is likely just confusion from early unicode days;
# Python isn't doing it, pywin32 probably was, so 'mbcs' would
# be the default encoding. We should never hit this these days
# anyway, but on py3k, we *never* will, and str objects there
# don't have a decode method...
if sys.version_info < (3,):
for i in range(len(bits)):
if type(bits[i]) is str:
#assert type(bits[i]) is str, type(bits[i])
bits[i] = bits[i].decode('utf8')
self.description = ExpandTabs(''.join(bits))
# Clear tracebacks etc.
tb = tb_top = tb_look = None
def ExtractTracebackInfo(self, tb, site):
import linecache
f = tb.tb_frame
lineno = tb.tb_lineno
co = f.f_code
filename = co.co_filename
name = co.co_name
line = linecache.getline(filename, lineno)
if not line:
try:
codeBlock = site.scriptCodeBlocks[filename]
except KeyError:
codeBlock = None
if codeBlock:
# Note: 'line' will now be unicode.
line = codeBlock.GetLineNo(lineno)
if line:
line = line.strip()
else:
line = None
return filename, lineno, name, line
def __repr__(self):
return "AXScriptException Object with description:" + self.description
def ProcessAXScriptException(scriptingSite, debugManager, exceptionInstance):
"""General function to handle any exception in AX code
This function creates an instance of our IActiveScriptError interface, and
gives it to the host, along with out exception class. The host will
likely call back on the IActiveScriptError interface to get the source text
and other information not normally in COM exceptions.
"""
# traceback.print_exc()
instance = IActiveScriptError()
instance._SetExceptionInfo(exceptionInstance)
gateway = win32com.server.util.wrap(instance, axscript.IID_IActiveScriptError)
if debugManager:
fCallOnError = debugManager.HandleRuntimeError()
if not fCallOnError:
return None
try:
result = scriptingSite.OnScriptError(gateway)
except pythoncom.com_error as details:
print("**OnScriptError failed:", details)
print("Exception description:'%s'" % (repr(exceptionInstance.description)))
print("Exception text:'%s'" % (repr(exceptionInstance.linetext)))
result = winerror.S_FALSE
if result==winerror.S_OK:
# If the above returns NOERROR, it is assumed the error has been
# correctly registered and the value SCRIPT_E_REPORTED is returned.
ret = win32com.server.exception.COMException(scode=axscript.SCRIPT_E_REPORTED)
return ret
else:
# The error is taken to be unreported and is propagated up the call stack
# via the IDispatch::Invoke's EXCEPINFO parameter (hr returned is DISP_E_EXCEPTION.
return exceptionInstance

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,70 @@
# pydumper.py
#
# This is being worked on - it does not yet work at all, in ay way
# shape or form :-)
#
# A new script engine, derived from the standard scripting engine,
# which dumps information.
# This generally can be used to grab all sorts of useful details about
# an engine - expose bugs in it or Python, dump the object model, etc.
# As it is derived from the standard engine, it fully supports Python
# as a scripting language - meaning the dumps produced can be quite dynamic,
# and based on the script code you execute.
from . import pyscript
from win32com.axscript import axscript
from .pyscript import RaiseAssert, trace, Exception, SCRIPTTEXT_FORCEEXECUTION
PyDump_CLSID = '{ac527e60-c693-11d0-9c25-00aa00125a98}'
class AXScriptAttribute(pyscript.AXScriptAttribute):
pass
class NamedScriptAttribute(pyscript.NamedScriptAttribute):
pass
class PyScript(pyscript.PyScript):
pass
def Register():
import sys
if '-d' in sys.argv:
dispatcher = "DispatcherWin32trace"
debug_desc = " ("+dispatcher+")"
debug_option = "Yes"
else:
dispatcher = None
debug_desc = ""
debug_option = ""
categories = [axscript.CATID_ActiveScript,axscript.CATID_ActiveScriptParse]
clsid = PyDump_CLSID
lcid = 0x0409 # // english
policy = None # "win32com.axscript.client.axspolicy.AXScriptPolicy"
print("Registering COM server%s..." % debug_desc)
from win32com.server.register import RegisterServer
languageName = "PyDump"
verProgId = "Python.Dumper.1"
RegisterServer(clsid = clsid, pythonInstString = "win32com.axscript.client.pyscript.PyDumper",
className = "Python Debugging/Dumping ActiveX Scripting Engine",
progID = languageName, verProgID = verProgId,
catids = categories,
policy=policy, dispatcher = dispatcher)
CreateRegKey(languageName + "\\OLEScript")
# Basic Registration for wsh.
win32com.server.register._set_string(".pysDump", "pysDumpFile")
win32com.server.register._set_string("pysDumpFile\\ScriptEngine", languageName)
print("Dumping Server registered.")
if __name__=='__main__':
Register()

View file

@ -0,0 +1,372 @@
"""Python ActiveX Scripting Implementation
This module implements the Python ActiveX Scripting client.
To register the implementation, simply "run" this Python program - ie
either double-click on it, or run "python.exe pyscript.py" from the
command line.
"""
import winerror
import win32com
import win32api
import pythoncom
import sys
import traceback
import re
import win32com.client.dynamic
from win32com.axscript.client import framework, scriptdispatch
from win32com.axscript import axscript
import win32com.server.register
from win32com.axscript.client.framework import \
RaiseAssert, trace, Exception, SCRIPTTEXT_FORCEEXECUTION, \
SCRIPTTEXT_ISEXPRESSION, SCRIPTTEXT_ISPERSISTENT
PyScript_CLSID = "{DF630910-1C1D-11d0-AE36-8C0F5E000000}"
debugging_attr = 0
def debug_attr_print(*args):
if debugging_attr:
trace(*args)
def ExpandTabs(text):
return re.sub('\t',' ', text)
def AddCR(text):
return re.sub('\n','\r\n',text)
class AXScriptCodeBlock(framework.AXScriptCodeBlock):
def GetDisplayName(self):
return "PyScript - " + framework.AXScriptCodeBlock.GetDisplayName(self)
# There is only ever _one_ ax object - it exists in the global namespace
# for all script items.
# It performs a search from all global/visible objects
# down.
# This means that if 2 sub-objects of the same name are used
# then only one is ever reachable using the ax shortcut.
class AXScriptAttribute:
"An attribute in a scripts namespace."
def __init__(self, engine):
self.__dict__['_scriptEngine_'] = engine
def __getattr__(self, attr):
if attr[1]=="_" and attr[:-1]=="_":
raise AttributeError(attr)
rc = self._FindAttribute_(attr)
if rc is None:
raise AttributeError(attr)
return rc
def _Close_(self):
self.__dict__['_scriptEngine_'] = None
def _DoFindAttribute_(self, obj, attr):
try:
return obj.subItems[attr.lower()].attributeObject
except KeyError:
pass
# Check out the sub-items
for item in obj.subItems.values():
try:
return self._DoFindAttribute_(item, attr)
except AttributeError:
pass
raise AttributeError(attr)
def _FindAttribute_(self, attr):
for item in self._scriptEngine_.subItems.values():
try:
return self._DoFindAttribute_(item, attr)
except AttributeError:
pass
# All else fails, see if it is a global
# (mainly b/w compat)
return getattr(self._scriptEngine_.globalNameSpaceModule, attr)
# raise AttributeError(attr)
class NamedScriptAttribute:
"An explicitely named object in an objects namespace"
# Each named object holds a reference to one of these.
# Whenever a sub-item appears in a namespace, it is really one of these
# objects. Has a circular reference back to the item itself, which is
# closed via _Close_()
def __init__(self, scriptItem):
self.__dict__['_scriptItem_'] = scriptItem
def __repr__(self):
return "<NamedItemAttribute" + repr(self._scriptItem_) + ">"
def __getattr__(self, attr):
# If a known subitem, return it.
try:
return self._scriptItem_.subItems[attr.lower()].attributeObject
except KeyError:
# Otherwise see if the dispatch can give it to us
if self._scriptItem_.dispatchContainer:
return getattr(self._scriptItem_.dispatchContainer,attr)
raise AttributeError(attr)
def __setattr__(self, attr, value):
# XXX - todo - if a known item, then should call its default
# dispatch method.
attr=attr.lower()
if self._scriptItem_.dispatchContainer:
try:
return setattr(self._scriptItem_.dispatchContainer,attr, value)
except AttributeError:
pass
raise AttributeError(attr)
def _Close_(self):
self.__dict__['_scriptItem_'] = None
class ScriptItem(framework.ScriptItem):
def __init__(self, parentItem, name, dispatch, flags):
framework.ScriptItem.__init__(self, parentItem, name, dispatch, flags)
self.scriptlets = {}
self.attributeObject = None
def Reset(self):
framework.ScriptItem.Reset(self)
if self.attributeObject:
self.attributeObject._Close_()
self.attributeObject = None
def Close(self):
framework.ScriptItem.Close(self) # calls reset.
self.dispatchContainer = None
self.scriptlets = {}
def Register(self):
framework.ScriptItem.Register(self)
self.attributeObject = NamedScriptAttribute(self)
if self.dispatch:
# Need to avoid the new Python "lazy" dispatch behaviour.
try:
engine = self.GetEngine()
olerepr = clsid = None
typeinfo = self.dispatch.GetTypeInfo()
clsid = typeinfo.GetTypeAttr()[0]
try:
olerepr = engine.mapKnownCOMTypes[clsid]
except KeyError:
pass
except pythoncom.com_error:
typeinfo = None
if olerepr is None:
olerepr = win32com.client.dynamic.MakeOleRepr(self.dispatch, typeinfo, None)
if clsid is not None:
engine.mapKnownCOMTypes[clsid] = olerepr
self.dispatchContainer = win32com.client.dynamic.CDispatch(self.dispatch, olerepr, self.name)
# self.dispatchContainer = win32com.client.dynamic.Dispatch(self.dispatch, userName = self.name)
# self.dispatchContainer = win32com.client.dynamic.DumbDispatch(self.dispatch, userName = self.name)
# def Connect(self):
# framework.ScriptItem.Connect(self)
# def Disconnect(self):
# framework.ScriptItem.Disconnect(self)
class PyScript(framework.COMScript):
# Setup the auto-registration stuff...
_reg_verprogid_ = "Python.AXScript.2"
_reg_progid_ = "Python"
# _reg_policy_spec_ = default
_reg_catids_ = [axscript.CATID_ActiveScript,axscript.CATID_ActiveScriptParse]
_reg_desc_ = "Python ActiveX Scripting Engine"
_reg_clsid_ = PyScript_CLSID
_reg_class_spec_ = "win32com.axscript.client.pyscript.PyScript"
_reg_remove_keys_ = [(".pys",), ("pysFile",)]
_reg_threading_ = "both"
def __init__(self):
framework.COMScript.__init__(self)
self.globalNameSpaceModule = None
self.codeBlocks = []
self.scriptDispatch = None
def InitNew(self):
framework.COMScript.InitNew(self)
import imp
self.scriptDispatch = None
self.globalNameSpaceModule = imp.new_module("__ax_main__")
self.globalNameSpaceModule.__dict__['ax'] = AXScriptAttribute(self)
self.codeBlocks = []
self.persistedCodeBlocks = []
self.mapKnownCOMTypes = {} # Map of known CLSID to typereprs
self.codeBlockCounter = 0
def Stop(self):
# Flag every pending script as already done
for b in self.codeBlocks:
b.beenExecuted = 1
return framework.COMScript.Stop(self)
def Reset(self):
# Reset all code-blocks that are persistent, and discard the rest
oldCodeBlocks = self.codeBlocks[:]
self.codeBlocks = []
for b in oldCodeBlocks:
if b.flags & SCRIPTTEXT_ISPERSISTENT:
b.beenExecuted = 0
self.codeBlocks.append(b)
return framework.COMScript.Reset(self)
def _GetNextCodeBlockNumber(self):
self.codeBlockCounter = self.codeBlockCounter + 1
return self.codeBlockCounter
def RegisterNamedItem(self, item):
wasReg = item.isRegistered
framework.COMScript.RegisterNamedItem(self, item)
if not wasReg:
# Insert into our namespace.
# Add every item by name
if item.IsVisible():
self.globalNameSpaceModule.__dict__[item.name] = item.attributeObject
if item.IsGlobal():
# Global items means sub-items are also added...
for subitem in item.subItems.values():
self.globalNameSpaceModule.__dict__[subitem.name] = subitem.attributeObject
# Also add all methods
for name, entry in item.dispatchContainer._olerepr_.mapFuncs.items():
if not entry.hidden:
self.globalNameSpaceModule.__dict__[name] = getattr(item.dispatchContainer,name)
def DoExecutePendingScripts(self):
try:
globs = self.globalNameSpaceModule.__dict__
for codeBlock in self.codeBlocks:
if not codeBlock.beenExecuted:
if self.CompileInScriptedSection(codeBlock, "exec"):
self.ExecInScriptedSection(codeBlock, globs)
finally:
pass
def DoRun(self):
pass
def Close(self):
self.ResetNamespace()
self.globalNameSpaceModule = None
self.codeBlocks = []
self.scriptDispatch = None
framework.COMScript.Close(self)
def GetScriptDispatch(self, name):
# trace("GetScriptDispatch with", name)
# if name is not None: return None
if self.scriptDispatch is None:
self.scriptDispatch = scriptdispatch.MakeScriptDispatch(self, self.globalNameSpaceModule)
return self.scriptDispatch
def MakeEventMethodName(self, subItemName, eventName):
return subItemName[0].upper()+subItemName[1:] + "_" + eventName[0].upper()+eventName[1:]
def DoAddScriptlet(self, defaultName, code, itemName, subItemName, eventName, delimiter,sourceContextCookie, startLineNumber):
# Just store the code away - compile when called. (JIT :-)
item = self.GetNamedItem(itemName)
if itemName==subItemName: # Explicit handlers - eg <SCRIPT LANGUAGE="Python" for="TestForm" Event="onSubmit">
subItem = item
else:
subItem = item.GetCreateSubItem(item, subItemName, None, None)
funcName = self.MakeEventMethodName(subItemName, eventName)
codeBlock = AXScriptCodeBlock("Script Event %s" %funcName, code, sourceContextCookie, startLineNumber, 0)
self._AddScriptCodeBlock(codeBlock)
subItem.scriptlets[funcName] = codeBlock
def DoProcessScriptItemEvent(self, item, event, lcid, wFlags, args):
# trace("ScriptItemEvent", self, item, event, event.name, lcid, wFlags, args)
funcName = self.MakeEventMethodName(item.name, event.name)
codeBlock = function = None
try:
function = item.scriptlets[funcName]
if type(function)==type(self): # ie, is a CodeBlock instance
codeBlock = function
function = None
except KeyError:
pass
if codeBlock is not None:
realCode = "def %s():\n" % funcName
for line in framework.RemoveCR(codeBlock.codeText).split("\n"):
realCode = realCode + '\t' + line + '\n'
realCode = realCode + '\n'
if not self.CompileInScriptedSection(codeBlock, "exec", realCode):
return
dict = {}
self.ExecInScriptedSection(codeBlock, self.globalNameSpaceModule.__dict__, dict)
function = dict[funcName]
# cache back in scriptlets as a function.
item.scriptlets[funcName] = function
if function is None:
# still no function - see if in the global namespace.
try:
function = self.globalNameSpaceModule.__dict__[funcName]
except KeyError:
# Not there _exactly_ - do case ins search.
funcNameLook = funcName.lower()
for attr in self.globalNameSpaceModule.__dict__.keys():
if funcNameLook==attr.lower():
function = self.globalNameSpaceModule.__dict__[attr]
# cache back in scriptlets, to avoid this overhead next time
item.scriptlets[funcName] = function
if function is None:
raise Exception(scode=winerror.DISP_E_MEMBERNOTFOUND)
return self.ApplyInScriptedSection(codeBlock, function, args)
def DoParseScriptText(self, code, sourceContextCookie, startLineNumber, bWantResult, flags):
code = framework.RemoveCR(code) + "\n"
if flags & SCRIPTTEXT_ISEXPRESSION:
name = "Script Expression"
exec_type = "eval"
else:
name = "Script Block"
exec_type = "exec"
num = self._GetNextCodeBlockNumber()
if num==1: num=""
name = "%s %s" % (name, num)
codeBlock = AXScriptCodeBlock(name, code, sourceContextCookie, startLineNumber, flags)
self._AddScriptCodeBlock(codeBlock)
globs = self.globalNameSpaceModule.__dict__
if bWantResult: # always immediate.
if self.CompileInScriptedSection(codeBlock, exec_type):
if flags & SCRIPTTEXT_ISEXPRESSION:
return self.EvalInScriptedSection(codeBlock, globs)
else:
return self.ExecInScriptedSection(codeBlock, globs)
# else compile failed, but user chose to keep running...
else:
if flags & SCRIPTTEXT_FORCEEXECUTION:
if self.CompileInScriptedSection(codeBlock, exec_type):
self.ExecInScriptedSection(codeBlock, globs)
else:
self.codeBlocks.append(codeBlock)
def GetNamedItemClass(self):
return ScriptItem
def ResetNamespace(self):
if self.globalNameSpaceModule is not None:
try:
self.globalNameSpaceModule.ax._Reset_()
except AttributeError:
pass # ???
globalNameSpaceModule = None
def DllRegisterServer():
klass=PyScript
win32com.server.register._set_subkeys(klass._reg_progid_ + "\\OLEScript", {}) # Just a CreateKey
# Basic Registration for wsh.
win32com.server.register._set_string(".pys", "pysFile")
win32com.server.register._set_string("pysFile\\ScriptEngine", klass._reg_progid_)
guid_wsh_shellex = "{60254CA5-953B-11CF-8C96-00AA00B8708C}"
win32com.server.register._set_string("pysFile\\ShellEx\\DropHandler", guid_wsh_shellex)
win32com.server.register._set_string("pysFile\\ShellEx\\PropertySheetHandlers\\WSHProps", guid_wsh_shellex)
def Register(klass=PyScript):
import sys
ret = win32com.server.register.UseCommandLine(klass,
finalize_register=DllRegisterServer)
return ret
if __name__=='__main__':
Register()

View file

@ -0,0 +1,43 @@
# A version of the ActiveScripting engine that enables rexec support
# This version supports hosting by IE - however, due to Python's
# rexec module being neither completely trusted nor private, it is
# *not* enabled by default.
# As of Python 2.2, rexec is simply not available - thus, if you use this,
# a HTML page can do almost *anything* at all on your machine.
# You almost certainly do NOT want to use thus!
import pythoncom
from win32com.axscript import axscript
import winerror
from . import pyscript
INTERFACE_USES_DISPEX = 0x00000004 # Object knows to use IDispatchEx
INTERFACE_USES_SECURITY_MANAGER = 0x00000008 # Object knows to use IInternetHostSecurityManager
class PyScriptRExec(pyscript.PyScript):
# Setup the auto-registration stuff...
_reg_verprogid_ = "Python.AXScript-rexec.2"
_reg_progid_ = "Python" # Same ProgID as the standard engine.
# _reg_policy_spec_ = default
_reg_catids_ = [axscript.CATID_ActiveScript,axscript.CATID_ActiveScriptParse]
_reg_desc_ = "Python ActiveX Scripting Engine (with rexec support)"
_reg_clsid_ = "{69c2454b-efa2-455b-988c-c3651c4a2f69}"
_reg_class_spec_ = "win32com.axscript.client.pyscript_rexec.PyScriptRExec"
_reg_remove_keys_ = [(".pys",), ("pysFile",)]
_reg_threading_ = "Apartment"
def _GetSupportedInterfaceSafetyOptions(self):
# print "**** calling", pyscript.PyScript._GetSupportedInterfaceSafetyOptions, "**->", pyscript.PyScript._GetSupportedInterfaceSafetyOptions(self)
return INTERFACE_USES_DISPEX | \
INTERFACE_USES_SECURITY_MANAGER | \
axscript.INTERFACESAFE_FOR_UNTRUSTED_DATA | \
axscript.INTERFACESAFE_FOR_UNTRUSTED_CALLER
if __name__=='__main__':
print("WARNING: By registering this engine, you are giving remote HTML code")
print("the ability to execute *any* code on your system.")
print()
print("You almost certainly do NOT want to do this.")
print("You have been warned, and are doing this at your own (significant) risk")
pyscript.Register(PyScriptRExec)

View file

@ -0,0 +1,105 @@
"""dynamic dispatch objects for AX Script.
This is an IDispatch object that a scripting host may use to
query and invoke methods on the main script. Not may hosts use
this yet, so it is not well tested!
"""
import winerror
import types
from win32com.server.exception import COMException
import win32com.server.policy
import win32com.server.util
from win32com.client import Dispatch
import pythoncom
from win32com.axscript import axscript
debugging = 0
PyIDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]
def _is_callable(obj):
return type(obj) in [types.FunctionType, types.MethodType]
# ignore hasattr(obj, "__call__") as this means all COM objects!
class ScriptDispatch:
_public_methods_ = []
def __init__(self, engine, scriptNamespace):
self.engine = engine
self.scriptNamespace = scriptNamespace
def _dynamic_(self, name, lcid, wFlags, args):
# Ensure any newly added items are available.
self.engine.RegisterNewNamedItems()
self.engine.ProcessNewNamedItemsConnections()
if wFlags & pythoncom.INVOKE_FUNC:
# attempt to call a function
try:
func = getattr(self.scriptNamespace, name)
if not _is_callable(func):
raise AttributeError(name) # Not a function.
realArgs = []
for arg in args:
if type(arg)==PyIDispatchType:
realArgs.append(Dispatch(arg))
else:
realArgs.append(arg)
try:
# xxx - todo - work out what code block to pass???
return self.engine.ApplyInScriptedSection(None, func, tuple(realArgs))
except COMException as xxx_todo_changeme:
(hr, msg, exc, arg) = xxx_todo_changeme.args
raise
except AttributeError:
if not wFlags & pythoncom.DISPATCH_PROPERTYGET:
raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)
if wFlags & pythoncom.DISPATCH_PROPERTYGET:
# attempt to get a property
try:
ret = getattr(self.scriptNamespace, name)
if _is_callable(ret):
raise AttributeError(name) # Not a property.
except AttributeError:
raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)
except COMException as instance:
raise
except:
ret = self.engine.HandleException()
return ret
raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)
class StrictDynamicPolicy(win32com.server.policy.DynamicPolicy):
def _wrap_(self, object):
win32com.server.policy.DynamicPolicy._wrap_(self, object)
if hasattr(self._obj_, 'scriptNamespace'):
for name in dir(self._obj_.scriptNamespace):
self._dyn_dispid_to_name_[self._getdispid_(name,0)] = name
def _getmembername_(self, dispid):
try:
return str(self._dyn_dispid_to_name_[dispid])
except KeyError:
raise COMException(scode=winerror.DISP_E_UNKNOWNNAME, desc="Name not found")
def _getdispid_(self, name, fdex):
try:
func = getattr(self._obj_.scriptNamespace, str(name))
except AttributeError:
raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)
# if not _is_callable(func):
return win32com.server.policy.DynamicPolicy._getdispid_(self, name, fdex)
def _wrap_debug(obj):
return win32com.server.util.wrap(obj, usePolicy=StrictDynamicPolicy, useDispatcher=win32com.server.policy.DispatcherWin32trace)
def _wrap_nodebug(obj):
return win32com.server.util.wrap(obj, usePolicy=StrictDynamicPolicy)
if debugging:
_wrap = _wrap_debug
else:
_wrap = _wrap_nodebug
def MakeScriptDispatch(engine, namespace):
return _wrap(ScriptDispatch(engine, namespace))

View file

@ -0,0 +1,126 @@
import win32com.axscript.axscript
import winerror
from win32com.axscript import axscript
from win32com.server import exception, util
import pythoncom
class AXEngine:
def __init__(self, site, engine):
self.eScript = self.eParse = self.eSafety = None
if type(engine) == type(''):
engine = pythoncom.CoCreateInstance(engine,
None,
pythoncom.CLSCTX_SERVER,
pythoncom.IID_IUnknown)
self.eScript = engine.QueryInterface(axscript.IID_IActiveScript)
self.eParse = engine.QueryInterface(axscript.IID_IActiveScriptParse)
self.eSafety = engine.QueryInterface(axscript.IID_IObjectSafety)
self.eScript.SetScriptSite(site)
self.eParse.InitNew()
def __del__(self):
self.Close()
def GetScriptDispatch(self, name = None):
return self.eScript.GetScriptDispatch(name)
def AddNamedItem(self, item, flags):
return self.eScript.AddNamedItem(item, flags)
# Some helpers.
def AddCode(self, code, flags=0):
self.eParse.ParseScriptText(code, None, None, None, 0, 0, flags)
def EvalCode(self, code):
return self.eParse.ParseScriptText(code, None, None, None, 0, 0, axscript.SCRIPTTEXT_ISEXPRESSION)
def Start(self):
# Should maybe check state?
# Do I need to transition through?
self.eScript.SetScriptState(axscript.SCRIPTSTATE_STARTED)
# self.eScript.SetScriptState(axscript.SCRIPTSTATE_CONNECTED)
def Close(self):
if self.eScript:
self.eScript.Close()
self.eScript = self.eParse = self.eSafety = None
def SetScriptState(self, state):
self.eScript.SetScriptState(state)
IActiveScriptSite_methods = [
'GetLCID',
'GetItemInfo',
'GetDocVersionString',
'OnScriptTerminate',
'OnStateChange',
'OnScriptError',
'OnEnterScript',
'OnLeaveScript',
]
class AXSite:
"""An Active Scripting site. A Site can have exactly one engine.
"""
_public_methods_ = IActiveScriptSite_methods
_com_interfaces_ = [ axscript.IID_IActiveScriptSite ]
def __init__(self, objModel={}, engine = None, lcid=0):
self.lcid = lcid
self.objModel = { }
for name, object in objModel.items():
# Gregs code did string.lower this - I think that is callers job if he wants!
self.objModel[name] = object
self.engine = None
if engine:
self._AddEngine(engine)
def AddEngine(self, engine):
"""Adds a new engine to the site.
engine can be a string, or a fully wrapped engine object.
"""
if type(engine)==type(''):
newEngine = AXEngine(util.wrap(self), engine)
else:
newEngine = engine
self.engine = newEngine
flags = axscript.SCRIPTITEM_ISVISIBLE | axscript.SCRIPTITEM_NOCODE | axscript.SCRIPTITEM_GLOBALMEMBERS | axscript.SCRIPTITEM_ISPERSISTENT
for name in self.objModel.keys():
newEngine.AddNamedItem(name, flags)
newEngine.SetScriptState(axscript.SCRIPTSTATE_INITIALIZED)
return newEngine
# B/W compat
_AddEngine = AddEngine
def _Close(self):
self.engine.Close()
self.objModel = {}
def GetLCID(self):
return self.lcid
def GetItemInfo(self, name, returnMask):
if name not in self.objModel:
raise exception.Exception(scode=winerror.TYPE_E_ELEMENTNOTFOUND, desc='item not found')
### for now, we don't have any type information
if returnMask & axscript.SCRIPTINFO_IUNKNOWN:
return (self.objModel[name], None)
return (None, None)
def GetDocVersionString(self):
return 'Python AXHost version 1.0'
def OnScriptTerminate(self, result, excepInfo):
pass
def OnStateChange(self, state):
pass
def OnScriptError(self, errorInterface):
return winerror.S_FALSE
def OnEnterScript(self):
pass
def OnLeaveScript(self):
pass

View file

@ -0,0 +1,15 @@
"""Exception instance for AXScript servers.
This module implements an exception instance that is raised by the core
server scripting support.
When a script error occurs, it wraps the COM object that describes the
exception in a Python instance, which can then be raised and caught.
"""
class Exception:
def __init__(self, activeScriptError):
self.activeScriptError = activeScriptError
def __getattr__(self, attr):
return getattr(self.activeScriptError, attr)

Some files were not shown because too many files have changed in this diff Show more