Todo: 集成多平台 解决因SaiNiu线程抢占资源问题 本地提交测试环境打包 和 正式打包脚本与正式环境打包bat 提交Python32环境包 改进多日志文件生成情况修改打包日志细节

This commit is contained in:
2025-09-18 15:52:03 +08:00
parent 8b9fc925fa
commit 7cfc0c22b7
7608 changed files with 2424791 additions and 25 deletions

View File

@@ -0,0 +1,164 @@
"""
A pure-python re-implementation of methods used by win32verstamp.
This is to avoid a bootstraping problem where win32verstamp is used during build,
but requires an installation of pywin32 to be present.
We used to work around this by ignoring failure to verstamp, but that's easy to miss.
Implementations adapted, simplified and typed from:
- https://github.com/enthought/pywin32-ctypes/blob/main/win32ctypes/core/ctypes/_util.py
- https://github.com/enthought/pywin32-ctypes/blob/main/win32ctypes/core/cffi/_resource.py
- https://github.com/enthought/pywin32-ctypes/blob/main/win32ctypes/pywin32/win32api.py
---
(C) Copyright 2014 Enthought, Inc., Austin, TX
All right reserved.
This file is open source software distributed according to the terms in
https://github.com/enthought/pywin32-ctypes/blob/main/LICENSE.txt
"""
from __future__ import annotations
from collections.abc import Iterable
from ctypes import FormatError, WinDLL, get_last_error
from ctypes.wintypes import (
BOOL,
DWORD,
HANDLE,
LPCWSTR,
LPVOID,
WORD,
)
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ctypes import _NamedFuncPointer
from _typeshed import ReadableBuffer
from typing_extensions import Literal, SupportsBytes, SupportsIndex
kernel32 = WinDLL("kernel32", use_last_error=True)
###
# https://github.com/enthought/pywin32-ctypes/blob/main/win32ctypes/core/ctypes/_util.py
###
def make_error(function: _NamedFuncPointer) -> OSError:
code = get_last_error()
exception = OSError()
exception.winerror = code
exception.function = function.__name__
exception.strerror = FormatError(code).strip()
return exception
def check_null(result: int | None, function: _NamedFuncPointer, *_) -> int:
if result is None:
raise make_error(function)
return result
def check_false(result: int | None, function: _NamedFuncPointer, *_) -> Literal[True]:
if not bool(result):
raise make_error(function)
else:
return True
###
# https://github.com/enthought/pywin32-ctypes/blob/main/win32ctypes/core/cffi/_resource.py
###
_BeginUpdateResource = kernel32.BeginUpdateResourceW
_BeginUpdateResource.argtypes = [LPCWSTR, BOOL]
_BeginUpdateResource.restype = HANDLE
_BeginUpdateResource.errcheck = check_null # type: ignore[assignment] # ctypes is badly typed
_EndUpdateResource = kernel32.EndUpdateResourceW
_EndUpdateResource.argtypes = [HANDLE, BOOL]
_EndUpdateResource.restype = BOOL
_EndUpdateResource.errcheck = check_false # type: ignore[assignment] # ctypes is badly typed
_UpdateResource = kernel32.UpdateResourceW
_UpdateResource.argtypes = [HANDLE, LPCWSTR, LPCWSTR, WORD, LPVOID, DWORD]
_UpdateResource.restype = BOOL
_UpdateResource.errcheck = check_false # type: ignore[assignment] # ctypes is badly typed
###
# https://github.com/enthought/pywin32-ctypes/blob/main/win32ctypes/pywin32/win32api.py
###
LANG_NEUTRAL = 0x00
def BeginUpdateResource(filename: str, delete: bool):
"""Get a handle that can be used by the :func:`UpdateResource`.
Parameters
----------
fileName : str
The filename of the module to load.
delete : bool
When true all existing resources are deleted
Returns
-------
result : hModule
Handle of the resource.
"""
return _BeginUpdateResource(filename, delete)
def EndUpdateResource(handle: int, discard: bool) -> None:
"""End the update resource of the handle.
Parameters
----------
handle : hModule
The handle of the resource as it is returned
by :func:`BeginUpdateResource`
discard : bool
When True all writes are discarded.
"""
_EndUpdateResource(handle, discard)
def UpdateResource(
handle: int,
type: str | int,
name: str | int,
data: Iterable[SupportsIndex] | SupportsIndex | SupportsBytes | ReadableBuffer,
language: int = LANG_NEUTRAL,
) -> None:
"""Update a resource.
Parameters
----------
handle : hModule
The handle of the resource file as returned by
:func:`BeginUpdateResource`.
type : str | int
The type of resource to update.
name : str | int
The name or Id of the resource to update.
data : bytes-like
A bytes like object is expected.
language : int
Language to use, default is LANG_NEUTRAL.
"""
lp_data = bytes(data)
_UpdateResource(
handle, LPCWSTR(type), LPCWSTR(name), language, lp_data, len(lp_data)
)

View File

@@ -0,0 +1,8 @@
import warnings
from pywin.mfc.afxres import *
warnings.warn(
"Importing the global `afxres` module is deprecated. Import from `pywin.mfc.afxres` instead.",
category=DeprecationWarning,
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,956 @@
import win32api
# Generated by h2py from d:/msdev/include/mmsystem.h
MAXPNAMELEN = 32
MAXERRORLENGTH = 256
MAX_JOYSTICKOEMVXDNAME = 260
MM_MICROSOFT = 1
MM_MIDI_MAPPER = 1
MM_WAVE_MAPPER = 2
MM_SNDBLST_MIDIOUT = 3
MM_SNDBLST_MIDIIN = 4
MM_SNDBLST_SYNTH = 5
MM_SNDBLST_WAVEOUT = 6
MM_SNDBLST_WAVEIN = 7
MM_ADLIB = 9
MM_MPU401_MIDIOUT = 10
MM_MPU401_MIDIIN = 11
MM_PC_JOYSTICK = 12
TIME_MS = 0x0001
TIME_SAMPLES = 0x0002
TIME_BYTES = 0x0004
TIME_SMPTE = 0x0008
TIME_MIDI = 0x0010
TIME_TICKS = 0x0020
MM_JOY1MOVE = 0x3A0
MM_JOY2MOVE = 0x3A1
MM_JOY1ZMOVE = 0x3A2
MM_JOY2ZMOVE = 0x3A3
MM_JOY1BUTTONDOWN = 0x3B5
MM_JOY2BUTTONDOWN = 0x3B6
MM_JOY1BUTTONUP = 0x3B7
MM_JOY2BUTTONUP = 0x3B8
MM_MCINOTIFY = 0x3B9
MM_WOM_OPEN = 0x3BB
MM_WOM_CLOSE = 0x3BC
MM_WOM_DONE = 0x3BD
MM_WIM_OPEN = 0x3BE
MM_WIM_CLOSE = 0x3BF
MM_WIM_DATA = 0x3C0
MM_MIM_OPEN = 0x3C1
MM_MIM_CLOSE = 0x3C2
MM_MIM_DATA = 0x3C3
MM_MIM_LONGDATA = 0x3C4
MM_MIM_ERROR = 0x3C5
MM_MIM_LONGERROR = 0x3C6
MM_MOM_OPEN = 0x3C7
MM_MOM_CLOSE = 0x3C8
MM_MOM_DONE = 0x3C9
MM_STREAM_OPEN = 0x3D4
MM_STREAM_CLOSE = 0x3D5
MM_STREAM_DONE = 0x3D6
MM_STREAM_ERROR = 0x3D7
MM_MOM_POSITIONCB = 0x3CA
MM_MIM_MOREDATA = 0x3CC
MM_MIXM_LINE_CHANGE = 0x3D0
MM_MIXM_CONTROL_CHANGE = 0x3D1
MMSYSERR_BASE = 0
WAVERR_BASE = 32
MIDIERR_BASE = 64
TIMERR_BASE = 96
JOYERR_BASE = 160
MCIERR_BASE = 256
MIXERR_BASE = 1024
MCI_STRING_OFFSET = 512
MCI_VD_OFFSET = 1024
MCI_CD_OFFSET = 1088
MCI_WAVE_OFFSET = 1152
MCI_SEQ_OFFSET = 1216
MMSYSERR_NOERROR = 0
MMSYSERR_ERROR = MMSYSERR_BASE + 1
MMSYSERR_BADDEVICEID = MMSYSERR_BASE + 2
MMSYSERR_NOTENABLED = MMSYSERR_BASE + 3
MMSYSERR_ALLOCATED = MMSYSERR_BASE + 4
MMSYSERR_INVALHANDLE = MMSYSERR_BASE + 5
MMSYSERR_NODRIVER = MMSYSERR_BASE + 6
MMSYSERR_NOMEM = MMSYSERR_BASE + 7
MMSYSERR_NOTSUPPORTED = MMSYSERR_BASE + 8
MMSYSERR_BADERRNUM = MMSYSERR_BASE + 9
MMSYSERR_INVALFLAG = MMSYSERR_BASE + 10
MMSYSERR_INVALPARAM = MMSYSERR_BASE + 11
MMSYSERR_HANDLEBUSY = MMSYSERR_BASE + 12
MMSYSERR_INVALIDALIAS = MMSYSERR_BASE + 13
MMSYSERR_BADDB = MMSYSERR_BASE + 14
MMSYSERR_KEYNOTFOUND = MMSYSERR_BASE + 15
MMSYSERR_READERROR = MMSYSERR_BASE + 16
MMSYSERR_WRITEERROR = MMSYSERR_BASE + 17
MMSYSERR_DELETEERROR = MMSYSERR_BASE + 18
MMSYSERR_VALNOTFOUND = MMSYSERR_BASE + 19
MMSYSERR_NODRIVERCB = MMSYSERR_BASE + 20
MMSYSERR_LASTERROR = MMSYSERR_BASE + 20
DRV_LOAD = 0x0001
DRV_ENABLE = 0x0002
DRV_OPEN = 0x0003
DRV_CLOSE = 0x0004
DRV_DISABLE = 0x0005
DRV_FREE = 0x0006
DRV_CONFIGURE = 0x0007
DRV_QUERYCONFIGURE = 0x0008
DRV_INSTALL = 0x0009
DRV_REMOVE = 0x000A
DRV_EXITSESSION = 0x000B
DRV_POWER = 0x000F
DRV_RESERVED = 0x0800
DRV_USER = 0x4000
DRVCNF_CANCEL = 0x0000
DRVCNF_OK = 0x0001
DRVCNF_RESTART = 0x0002
DRV_CANCEL = DRVCNF_CANCEL
DRV_OK = DRVCNF_OK
DRV_RESTART = DRVCNF_RESTART
DRV_MCI_FIRST = DRV_RESERVED
DRV_MCI_LAST = DRV_RESERVED + 0xFFF
CALLBACK_TYPEMASK = 0x00070000
CALLBACK_NULL = 0x00000000
CALLBACK_WINDOW = 0x00010000
CALLBACK_TASK = 0x00020000
CALLBACK_FUNCTION = 0x00030000
CALLBACK_THREAD = CALLBACK_TASK
CALLBACK_EVENT = 0x00050000
SND_SYNC = 0x0000
SND_ASYNC = 0x0001
SND_NODEFAULT = 0x0002
SND_MEMORY = 0x0004
SND_LOOP = 0x0008
SND_NOSTOP = 0x0010
SND_NOWAIT = 0x00002000
SND_ALIAS = 0x00010000
SND_ALIAS_ID = 0x00110000
SND_FILENAME = 0x00020000
SND_RESOURCE = 0x00040004
SND_PURGE = 0x0040
SND_APPLICATION = 0x0080
SND_ALIAS_START = 0
WAVERR_BADFORMAT = WAVERR_BASE + 0
WAVERR_STILLPLAYING = WAVERR_BASE + 1
WAVERR_UNPREPARED = WAVERR_BASE + 2
WAVERR_SYNC = WAVERR_BASE + 3
WAVERR_LASTERROR = WAVERR_BASE + 3
WOM_OPEN = MM_WOM_OPEN
WOM_CLOSE = MM_WOM_CLOSE
WOM_DONE = MM_WOM_DONE
WIM_OPEN = MM_WIM_OPEN
WIM_CLOSE = MM_WIM_CLOSE
WIM_DATA = MM_WIM_DATA
WAVE_MAPPER = -1 # 0xFFFFFFFF
WAVE_FORMAT_QUERY = 0x0001
WAVE_ALLOWSYNC = 0x0002
WAVE_MAPPED = 0x0004
WAVE_FORMAT_DIRECT = 0x0008
WAVE_FORMAT_DIRECT_QUERY = WAVE_FORMAT_QUERY | WAVE_FORMAT_DIRECT
WHDR_DONE = 0x00000001
WHDR_PREPARED = 0x00000002
WHDR_BEGINLOOP = 0x00000004
WHDR_ENDLOOP = 0x00000008
WHDR_INQUEUE = 0x00000010
WAVECAPS_PITCH = 0x0001
WAVECAPS_PLAYBACKRATE = 0x0002
WAVECAPS_VOLUME = 0x0004
WAVECAPS_LRVOLUME = 0x0008
WAVECAPS_SYNC = 0x0010
WAVECAPS_SAMPLEACCURATE = 0x0020
WAVECAPS_DIRECTSOUND = 0x0040
WAVE_INVALIDFORMAT = 0x00000000
WAVE_FORMAT_1M08 = 0x00000001
WAVE_FORMAT_1S08 = 0x00000002
WAVE_FORMAT_1M16 = 0x00000004
WAVE_FORMAT_1S16 = 0x00000008
WAVE_FORMAT_2M08 = 0x00000010
WAVE_FORMAT_2S08 = 0x00000020
WAVE_FORMAT_2M16 = 0x00000040
WAVE_FORMAT_2S16 = 0x00000080
WAVE_FORMAT_4M08 = 0x00000100
WAVE_FORMAT_4S08 = 0x00000200
WAVE_FORMAT_4M16 = 0x00000400
WAVE_FORMAT_4S16 = 0x00000800
WAVE_FORMAT_PCM = 1
WAVE_FORMAT_IEEE_FLOAT = 3
MIDIERR_UNPREPARED = MIDIERR_BASE + 0
MIDIERR_STILLPLAYING = MIDIERR_BASE + 1
MIDIERR_NOMAP = MIDIERR_BASE + 2
MIDIERR_NOTREADY = MIDIERR_BASE + 3
MIDIERR_NODEVICE = MIDIERR_BASE + 4
MIDIERR_INVALIDSETUP = MIDIERR_BASE + 5
MIDIERR_BADOPENMODE = MIDIERR_BASE + 6
MIDIERR_DONT_CONTINUE = MIDIERR_BASE + 7
MIDIERR_LASTERROR = MIDIERR_BASE + 7
MIDIPATCHSIZE = 128
MIM_OPEN = MM_MIM_OPEN
MIM_CLOSE = MM_MIM_CLOSE
MIM_DATA = MM_MIM_DATA
MIM_LONGDATA = MM_MIM_LONGDATA
MIM_ERROR = MM_MIM_ERROR
MIM_LONGERROR = MM_MIM_LONGERROR
MOM_OPEN = MM_MOM_OPEN
MOM_CLOSE = MM_MOM_CLOSE
MOM_DONE = MM_MOM_DONE
MIM_MOREDATA = MM_MIM_MOREDATA
MOM_POSITIONCB = MM_MOM_POSITIONCB
MIDI_IO_STATUS = 0x00000020
MIDI_CACHE_ALL = 1
MIDI_CACHE_BESTFIT = 2
MIDI_CACHE_QUERY = 3
MIDI_UNCACHE = 4
MOD_MIDIPORT = 1
MOD_SYNTH = 2
MOD_SQSYNTH = 3
MOD_FMSYNTH = 4
MOD_MAPPER = 5
MIDICAPS_VOLUME = 0x0001
MIDICAPS_LRVOLUME = 0x0002
MIDICAPS_CACHE = 0x0004
MIDICAPS_STREAM = 0x0008
MHDR_DONE = 0x00000001
MHDR_PREPARED = 0x00000002
MHDR_INQUEUE = 0x00000004
MHDR_ISSTRM = 0x00000008
MEVT_F_SHORT = 0x00000000
MEVT_F_LONG = -2147483648 # 0x80000000
MEVT_F_CALLBACK = 0x40000000
def MEVT_EVENTTYPE(x):
return (x >> 24) & 0xFF
def MEVT_EVENTPARM(x):
return x & 0x00FFFFFF
MIDISTRM_ERROR = -2
MIDIPROP_SET = -2147483648 # 0x80000000
MIDIPROP_GET = 0x40000000
MIDIPROP_TIMEDIV = 0x00000001
MIDIPROP_TEMPO = 0x00000002
AUXCAPS_CDAUDIO = 1
AUXCAPS_AUXIN = 2
AUXCAPS_VOLUME = 0x0001
AUXCAPS_LRVOLUME = 0x0002
MIXER_SHORT_NAME_CHARS = 16
MIXER_LONG_NAME_CHARS = 64
MIXERR_INVALLINE = MIXERR_BASE + 0
MIXERR_INVALCONTROL = MIXERR_BASE + 1
MIXERR_INVALVALUE = MIXERR_BASE + 2
MIXERR_LASTERROR = MIXERR_BASE + 2
MIXER_OBJECTF_HANDLE = -2147483648 # 0x80000000
MIXER_OBJECTF_MIXER = 0x00000000
MIXER_OBJECTF_HMIXER = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIXER
MIXER_OBJECTF_WAVEOUT = 0x10000000
MIXER_OBJECTF_HWAVEOUT = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_WAVEOUT
MIXER_OBJECTF_WAVEIN = 0x20000000
MIXER_OBJECTF_HWAVEIN = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_WAVEIN
MIXER_OBJECTF_MIDIOUT = 0x30000000
MIXER_OBJECTF_HMIDIOUT = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIDIOUT
MIXER_OBJECTF_MIDIIN = 0x40000000
MIXER_OBJECTF_HMIDIIN = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIDIIN
MIXER_OBJECTF_AUX = 0x50000000
MIXERLINE_LINEF_ACTIVE = 0x00000001
MIXERLINE_LINEF_DISCONNECTED = 0x00008000
MIXERLINE_LINEF_SOURCE = -2147483648 # 0x80000000
MIXERLINE_COMPONENTTYPE_DST_FIRST = 0x00000000
MIXERLINE_COMPONENTTYPE_DST_UNDEFINED = MIXERLINE_COMPONENTTYPE_DST_FIRST + 0
MIXERLINE_COMPONENTTYPE_DST_DIGITAL = MIXERLINE_COMPONENTTYPE_DST_FIRST + 1
MIXERLINE_COMPONENTTYPE_DST_LINE = MIXERLINE_COMPONENTTYPE_DST_FIRST + 2
MIXERLINE_COMPONENTTYPE_DST_MONITOR = MIXERLINE_COMPONENTTYPE_DST_FIRST + 3
MIXERLINE_COMPONENTTYPE_DST_SPEAKERS = MIXERLINE_COMPONENTTYPE_DST_FIRST + 4
MIXERLINE_COMPONENTTYPE_DST_HEADPHONES = MIXERLINE_COMPONENTTYPE_DST_FIRST + 5
MIXERLINE_COMPONENTTYPE_DST_TELEPHONE = MIXERLINE_COMPONENTTYPE_DST_FIRST + 6
MIXERLINE_COMPONENTTYPE_DST_WAVEIN = MIXERLINE_COMPONENTTYPE_DST_FIRST + 7
MIXERLINE_COMPONENTTYPE_DST_VOICEIN = MIXERLINE_COMPONENTTYPE_DST_FIRST + 8
MIXERLINE_COMPONENTTYPE_DST_LAST = MIXERLINE_COMPONENTTYPE_DST_FIRST + 8
MIXERLINE_COMPONENTTYPE_SRC_FIRST = 0x00001000
MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 0
MIXERLINE_COMPONENTTYPE_SRC_DIGITAL = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 1
MIXERLINE_COMPONENTTYPE_SRC_LINE = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 2
MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 3
MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 4
MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 5
MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 6
MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 7
MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 8
MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 9
MIXERLINE_COMPONENTTYPE_SRC_ANALOG = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 10
MIXERLINE_COMPONENTTYPE_SRC_LAST = MIXERLINE_COMPONENTTYPE_SRC_FIRST + 10
MIXERLINE_TARGETTYPE_UNDEFINED = 0
MIXERLINE_TARGETTYPE_WAVEOUT = 1
MIXERLINE_TARGETTYPE_WAVEIN = 2
MIXERLINE_TARGETTYPE_MIDIOUT = 3
MIXERLINE_TARGETTYPE_MIDIIN = 4
MIXERLINE_TARGETTYPE_AUX = 5
MIXER_GETLINEINFOF_DESTINATION = 0x00000000
MIXER_GETLINEINFOF_SOURCE = 0x00000001
MIXER_GETLINEINFOF_LINEID = 0x00000002
MIXER_GETLINEINFOF_COMPONENTTYPE = 0x00000003
MIXER_GETLINEINFOF_TARGETTYPE = 0x00000004
MIXER_GETLINEINFOF_QUERYMASK = 0x0000000F
MIXERCONTROL_CONTROLF_UNIFORM = 0x00000001
MIXERCONTROL_CONTROLF_MULTIPLE = 0x00000002
MIXERCONTROL_CONTROLF_DISABLED = -2147483648 # 0x80000000
MIXERCONTROL_CT_CLASS_MASK = -268435456 # 0xF0000000
MIXERCONTROL_CT_CLASS_CUSTOM = 0x00000000
MIXERCONTROL_CT_CLASS_METER = 0x10000000
MIXERCONTROL_CT_CLASS_SWITCH = 0x20000000
MIXERCONTROL_CT_CLASS_NUMBER = 0x30000000
MIXERCONTROL_CT_CLASS_SLIDER = 0x40000000
MIXERCONTROL_CT_CLASS_FADER = 0x50000000
MIXERCONTROL_CT_CLASS_TIME = 0x60000000
MIXERCONTROL_CT_CLASS_LIST = 0x70000000
MIXERCONTROL_CT_SUBCLASS_MASK = 0x0F000000
MIXERCONTROL_CT_SC_SWITCH_BOOLEAN = 0x00000000
MIXERCONTROL_CT_SC_SWITCH_BUTTON = 0x01000000
MIXERCONTROL_CT_SC_METER_POLLED = 0x00000000
MIXERCONTROL_CT_SC_TIME_MICROSECS = 0x00000000
MIXERCONTROL_CT_SC_TIME_MILLISECS = 0x01000000
MIXERCONTROL_CT_SC_LIST_SINGLE = 0x00000000
MIXERCONTROL_CT_SC_LIST_MULTIPLE = 0x01000000
MIXERCONTROL_CT_UNITS_MASK = 0x00FF0000
MIXERCONTROL_CT_UNITS_CUSTOM = 0x00000000
MIXERCONTROL_CT_UNITS_BOOLEAN = 0x00010000
MIXERCONTROL_CT_UNITS_SIGNED = 0x00020000
MIXERCONTROL_CT_UNITS_UNSIGNED = 0x00030000
MIXERCONTROL_CT_UNITS_DECIBELS = 0x00040000
MIXERCONTROL_CT_UNITS_PERCENT = 0x00050000
MIXERCONTROL_CONTROLTYPE_CUSTOM = (
MIXERCONTROL_CT_CLASS_CUSTOM | MIXERCONTROL_CT_UNITS_CUSTOM
)
MIXERCONTROL_CONTROLTYPE_BOOLEANMETER = (
MIXERCONTROL_CT_CLASS_METER
| MIXERCONTROL_CT_SC_METER_POLLED
| MIXERCONTROL_CT_UNITS_BOOLEAN
)
MIXERCONTROL_CONTROLTYPE_SIGNEDMETER = (
MIXERCONTROL_CT_CLASS_METER
| MIXERCONTROL_CT_SC_METER_POLLED
| MIXERCONTROL_CT_UNITS_SIGNED
)
MIXERCONTROL_CONTROLTYPE_PEAKMETER = MIXERCONTROL_CONTROLTYPE_SIGNEDMETER + 1
MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER = (
MIXERCONTROL_CT_CLASS_METER
| MIXERCONTROL_CT_SC_METER_POLLED
| MIXERCONTROL_CT_UNITS_UNSIGNED
)
MIXERCONTROL_CONTROLTYPE_BOOLEAN = (
MIXERCONTROL_CT_CLASS_SWITCH
| MIXERCONTROL_CT_SC_SWITCH_BOOLEAN
| MIXERCONTROL_CT_UNITS_BOOLEAN
)
MIXERCONTROL_CONTROLTYPE_ONOFF = MIXERCONTROL_CONTROLTYPE_BOOLEAN + 1
MIXERCONTROL_CONTROLTYPE_MUTE = MIXERCONTROL_CONTROLTYPE_BOOLEAN + 2
MIXERCONTROL_CONTROLTYPE_MONO = MIXERCONTROL_CONTROLTYPE_BOOLEAN + 3
MIXERCONTROL_CONTROLTYPE_LOUDNESS = MIXERCONTROL_CONTROLTYPE_BOOLEAN + 4
MIXERCONTROL_CONTROLTYPE_STEREOENH = MIXERCONTROL_CONTROLTYPE_BOOLEAN + 5
MIXERCONTROL_CONTROLTYPE_BUTTON = (
MIXERCONTROL_CT_CLASS_SWITCH
| MIXERCONTROL_CT_SC_SWITCH_BUTTON
| MIXERCONTROL_CT_UNITS_BOOLEAN
)
MIXERCONTROL_CONTROLTYPE_DECIBELS = (
MIXERCONTROL_CT_CLASS_NUMBER | MIXERCONTROL_CT_UNITS_DECIBELS
)
MIXERCONTROL_CONTROLTYPE_SIGNED = (
MIXERCONTROL_CT_CLASS_NUMBER | MIXERCONTROL_CT_UNITS_SIGNED
)
MIXERCONTROL_CONTROLTYPE_UNSIGNED = (
MIXERCONTROL_CT_CLASS_NUMBER | MIXERCONTROL_CT_UNITS_UNSIGNED
)
MIXERCONTROL_CONTROLTYPE_PERCENT = (
MIXERCONTROL_CT_CLASS_NUMBER | MIXERCONTROL_CT_UNITS_PERCENT
)
MIXERCONTROL_CONTROLTYPE_SLIDER = (
MIXERCONTROL_CT_CLASS_SLIDER | MIXERCONTROL_CT_UNITS_SIGNED
)
MIXERCONTROL_CONTROLTYPE_PAN = MIXERCONTROL_CONTROLTYPE_SLIDER + 1
MIXERCONTROL_CONTROLTYPE_QSOUNDPAN = MIXERCONTROL_CONTROLTYPE_SLIDER + 2
MIXERCONTROL_CONTROLTYPE_FADER = (
MIXERCONTROL_CT_CLASS_FADER | MIXERCONTROL_CT_UNITS_UNSIGNED
)
MIXERCONTROL_CONTROLTYPE_VOLUME = MIXERCONTROL_CONTROLTYPE_FADER + 1
MIXERCONTROL_CONTROLTYPE_BASS = MIXERCONTROL_CONTROLTYPE_FADER + 2
MIXERCONTROL_CONTROLTYPE_TREBLE = MIXERCONTROL_CONTROLTYPE_FADER + 3
MIXERCONTROL_CONTROLTYPE_EQUALIZER = MIXERCONTROL_CONTROLTYPE_FADER + 4
MIXERCONTROL_CONTROLTYPE_SINGLESELECT = (
MIXERCONTROL_CT_CLASS_LIST
| MIXERCONTROL_CT_SC_LIST_SINGLE
| MIXERCONTROL_CT_UNITS_BOOLEAN
)
MIXERCONTROL_CONTROLTYPE_MUX = MIXERCONTROL_CONTROLTYPE_SINGLESELECT + 1
MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT = (
MIXERCONTROL_CT_CLASS_LIST
| MIXERCONTROL_CT_SC_LIST_MULTIPLE
| MIXERCONTROL_CT_UNITS_BOOLEAN
)
MIXERCONTROL_CONTROLTYPE_MIXER = MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT + 1
MIXERCONTROL_CONTROLTYPE_MICROTIME = (
MIXERCONTROL_CT_CLASS_TIME
| MIXERCONTROL_CT_SC_TIME_MICROSECS
| MIXERCONTROL_CT_UNITS_UNSIGNED
)
MIXERCONTROL_CONTROLTYPE_MILLITIME = (
MIXERCONTROL_CT_CLASS_TIME
| MIXERCONTROL_CT_SC_TIME_MILLISECS
| MIXERCONTROL_CT_UNITS_UNSIGNED
)
MIXER_GETLINECONTROLSF_ALL = 0x00000000
MIXER_GETLINECONTROLSF_ONEBYID = 0x00000001
MIXER_GETLINECONTROLSF_ONEBYTYPE = 0x00000002
MIXER_GETLINECONTROLSF_QUERYMASK = 0x0000000F
MIXER_GETCONTROLDETAILSF_VALUE = 0x00000000
MIXER_GETCONTROLDETAILSF_LISTTEXT = 0x00000001
MIXER_GETCONTROLDETAILSF_QUERYMASK = 0x0000000F
MIXER_SETCONTROLDETAILSF_VALUE = 0x00000000
MIXER_SETCONTROLDETAILSF_CUSTOM = 0x00000001
MIXER_SETCONTROLDETAILSF_QUERYMASK = 0x0000000F
TIMERR_NOERROR = 0
TIMERR_NOCANDO = TIMERR_BASE + 1
TIMERR_STRUCT = TIMERR_BASE + 33
TIME_ONESHOT = 0x0000
TIME_PERIODIC = 0x0001
TIME_CALLBACK_FUNCTION = 0x0000
TIME_CALLBACK_EVENT_SET = 0x0010
TIME_CALLBACK_EVENT_PULSE = 0x0020
JOYERR_NOERROR = 0
JOYERR_PARMS = JOYERR_BASE + 5
JOYERR_NOCANDO = JOYERR_BASE + 6
JOYERR_UNPLUGGED = JOYERR_BASE + 7
JOY_BUTTON1 = 0x0001
JOY_BUTTON2 = 0x0002
JOY_BUTTON3 = 0x0004
JOY_BUTTON4 = 0x0008
JOY_BUTTON1CHG = 0x0100
JOY_BUTTON2CHG = 0x0200
JOY_BUTTON3CHG = 0x0400
JOY_BUTTON4CHG = 0x0800
JOY_BUTTON5 = 0x00000010
JOY_BUTTON6 = 0x00000020
JOY_BUTTON7 = 0x00000040
JOY_BUTTON8 = 0x00000080
JOY_BUTTON9 = 0x00000100
JOY_BUTTON10 = 0x00000200
JOY_BUTTON11 = 0x00000400
JOY_BUTTON12 = 0x00000800
JOY_BUTTON13 = 0x00001000
JOY_BUTTON14 = 0x00002000
JOY_BUTTON15 = 0x00004000
JOY_BUTTON16 = 0x00008000
JOY_BUTTON17 = 0x00010000
JOY_BUTTON18 = 0x00020000
JOY_BUTTON19 = 0x00040000
JOY_BUTTON20 = 0x00080000
JOY_BUTTON21 = 0x00100000
JOY_BUTTON22 = 0x00200000
JOY_BUTTON23 = 0x00400000
JOY_BUTTON24 = 0x00800000
JOY_BUTTON25 = 0x01000000
JOY_BUTTON26 = 0x02000000
JOY_BUTTON27 = 0x04000000
JOY_BUTTON28 = 0x08000000
JOY_BUTTON29 = 0x10000000
JOY_BUTTON30 = 0x20000000
JOY_BUTTON31 = 0x40000000
JOY_BUTTON32 = -2147483648 # 0x80000000
JOY_POVFORWARD = 0
JOY_POVRIGHT = 9000
JOY_POVBACKWARD = 18000
JOY_POVLEFT = 27000
JOY_RETURNX = 0x00000001
JOY_RETURNY = 0x00000002
JOY_RETURNZ = 0x00000004
JOY_RETURNR = 0x00000008
JOY_RETURNU = 0x00000010
JOY_RETURNV = 0x00000020
JOY_RETURNPOV = 0x00000040
JOY_RETURNBUTTONS = 0x00000080
JOY_RETURNRAWDATA = 0x00000100
JOY_RETURNPOVCTS = 0x00000200
JOY_RETURNCENTERED = 0x00000400
JOY_USEDEADZONE = 0x00000800
JOY_RETURNALL = (
JOY_RETURNX
| JOY_RETURNY
| JOY_RETURNZ
| JOY_RETURNR
| JOY_RETURNU
| JOY_RETURNV
| JOY_RETURNPOV
| JOY_RETURNBUTTONS
)
JOY_CAL_READALWAYS = 0x00010000
JOY_CAL_READXYONLY = 0x00020000
JOY_CAL_READ3 = 0x00040000
JOY_CAL_READ4 = 0x00080000
JOY_CAL_READXONLY = 0x00100000
JOY_CAL_READYONLY = 0x00200000
JOY_CAL_READ5 = 0x00400000
JOY_CAL_READ6 = 0x00800000
JOY_CAL_READZONLY = 0x01000000
JOY_CAL_READRONLY = 0x02000000
JOY_CAL_READUONLY = 0x04000000
JOY_CAL_READVONLY = 0x08000000
JOYSTICKID1 = 0
JOYSTICKID2 = 1
JOYCAPS_HASZ = 0x0001
JOYCAPS_HASR = 0x0002
JOYCAPS_HASU = 0x0004
JOYCAPS_HASV = 0x0008
JOYCAPS_HASPOV = 0x0010
JOYCAPS_POV4DIR = 0x0020
JOYCAPS_POVCTS = 0x0040
MMIOERR_BASE = 256
MMIOERR_FILENOTFOUND = MMIOERR_BASE + 1
MMIOERR_OUTOFMEMORY = MMIOERR_BASE + 2
MMIOERR_CANNOTOPEN = MMIOERR_BASE + 3
MMIOERR_CANNOTCLOSE = MMIOERR_BASE + 4
MMIOERR_CANNOTREAD = MMIOERR_BASE + 5
MMIOERR_CANNOTWRITE = MMIOERR_BASE + 6
MMIOERR_CANNOTSEEK = MMIOERR_BASE + 7
MMIOERR_CANNOTEXPAND = MMIOERR_BASE + 8
MMIOERR_CHUNKNOTFOUND = MMIOERR_BASE + 9
MMIOERR_UNBUFFERED = MMIOERR_BASE + 10
MMIOERR_PATHNOTFOUND = MMIOERR_BASE + 11
MMIOERR_ACCESSDENIED = MMIOERR_BASE + 12
MMIOERR_SHARINGVIOLATION = MMIOERR_BASE + 13
MMIOERR_NETWORKERROR = MMIOERR_BASE + 14
MMIOERR_TOOMANYOPENFILES = MMIOERR_BASE + 15
MMIOERR_INVALIDFILE = MMIOERR_BASE + 16
CFSEPCHAR = ord("+")
MMIO_RWMODE = 0x00000003
MMIO_SHAREMODE = 0x00000070
MMIO_CREATE = 0x00001000
MMIO_PARSE = 0x00000100
MMIO_DELETE = 0x00000200
MMIO_EXIST = 0x00004000
MMIO_ALLOCBUF = 0x00010000
MMIO_GETTEMP = 0x00020000
MMIO_DIRTY = 0x10000000
MMIO_READ = 0x00000000
MMIO_WRITE = 0x00000001
MMIO_READWRITE = 0x00000002
MMIO_COMPAT = 0x00000000
MMIO_EXCLUSIVE = 0x00000010
MMIO_DENYWRITE = 0x00000020
MMIO_DENYREAD = 0x00000030
MMIO_DENYNONE = 0x00000040
MMIO_FHOPEN = 0x0010
MMIO_EMPTYBUF = 0x0010
MMIO_TOUPPER = 0x0010
MMIO_INSTALLPROC = 0x00010000
MMIO_GLOBALPROC = 0x10000000
MMIO_REMOVEPROC = 0x00020000
MMIO_UNICODEPROC = 0x01000000
MMIO_FINDPROC = 0x00040000
MMIO_FINDCHUNK = 0x0010
MMIO_FINDRIFF = 0x0020
MMIO_FINDLIST = 0x0040
MMIO_CREATERIFF = 0x0020
MMIO_CREATELIST = 0x0040
MMIOM_READ = MMIO_READ
MMIOM_WRITE = MMIO_WRITE
MMIOM_SEEK = 2
MMIOM_OPEN = 3
MMIOM_CLOSE = 4
MMIOM_WRITEFLUSH = 5
MMIOM_RENAME = 6
MMIOM_USER = 0x8000
SEEK_SET = 0
SEEK_CUR = 1
SEEK_END = 2
MMIO_DEFAULTBUFFER = 8192
MCIERR_INVALID_DEVICE_ID = MCIERR_BASE + 1
MCIERR_UNRECOGNIZED_KEYWORD = MCIERR_BASE + 3
MCIERR_UNRECOGNIZED_COMMAND = MCIERR_BASE + 5
MCIERR_HARDWARE = MCIERR_BASE + 6
MCIERR_INVALID_DEVICE_NAME = MCIERR_BASE + 7
MCIERR_OUT_OF_MEMORY = MCIERR_BASE + 8
MCIERR_DEVICE_OPEN = MCIERR_BASE + 9
MCIERR_CANNOT_LOAD_DRIVER = MCIERR_BASE + 10
MCIERR_MISSING_COMMAND_STRING = MCIERR_BASE + 11
MCIERR_PARAM_OVERFLOW = MCIERR_BASE + 12
MCIERR_MISSING_STRING_ARGUMENT = MCIERR_BASE + 13
MCIERR_BAD_INTEGER = MCIERR_BASE + 14
MCIERR_PARSER_INTERNAL = MCIERR_BASE + 15
MCIERR_DRIVER_INTERNAL = MCIERR_BASE + 16
MCIERR_MISSING_PARAMETER = MCIERR_BASE + 17
MCIERR_UNSUPPORTED_FUNCTION = MCIERR_BASE + 18
MCIERR_FILE_NOT_FOUND = MCIERR_BASE + 19
MCIERR_DEVICE_NOT_READY = MCIERR_BASE + 20
MCIERR_INTERNAL = MCIERR_BASE + 21
MCIERR_DRIVER = MCIERR_BASE + 22
MCIERR_CANNOT_USE_ALL = MCIERR_BASE + 23
MCIERR_MULTIPLE = MCIERR_BASE + 24
MCIERR_EXTENSION_NOT_FOUND = MCIERR_BASE + 25
MCIERR_OUTOFRANGE = MCIERR_BASE + 26
MCIERR_FLAGS_NOT_COMPATIBLE = MCIERR_BASE + 28
MCIERR_FILE_NOT_SAVED = MCIERR_BASE + 30
MCIERR_DEVICE_TYPE_REQUIRED = MCIERR_BASE + 31
MCIERR_DEVICE_LOCKED = MCIERR_BASE + 32
MCIERR_DUPLICATE_ALIAS = MCIERR_BASE + 33
MCIERR_BAD_CONSTANT = MCIERR_BASE + 34
MCIERR_MUST_USE_SHAREABLE = MCIERR_BASE + 35
MCIERR_MISSING_DEVICE_NAME = MCIERR_BASE + 36
MCIERR_BAD_TIME_FORMAT = MCIERR_BASE + 37
MCIERR_NO_CLOSING_QUOTE = MCIERR_BASE + 38
MCIERR_DUPLICATE_FLAGS = MCIERR_BASE + 39
MCIERR_INVALID_FILE = MCIERR_BASE + 40
MCIERR_NULL_PARAMETER_BLOCK = MCIERR_BASE + 41
MCIERR_UNNAMED_RESOURCE = MCIERR_BASE + 42
MCIERR_NEW_REQUIRES_ALIAS = MCIERR_BASE + 43
MCIERR_NOTIFY_ON_AUTO_OPEN = MCIERR_BASE + 44
MCIERR_NO_ELEMENT_ALLOWED = MCIERR_BASE + 45
MCIERR_NONAPPLICABLE_FUNCTION = MCIERR_BASE + 46
MCIERR_ILLEGAL_FOR_AUTO_OPEN = MCIERR_BASE + 47
MCIERR_FILENAME_REQUIRED = MCIERR_BASE + 48
MCIERR_EXTRA_CHARACTERS = MCIERR_BASE + 49
MCIERR_DEVICE_NOT_INSTALLED = MCIERR_BASE + 50
MCIERR_GET_CD = MCIERR_BASE + 51
MCIERR_SET_CD = MCIERR_BASE + 52
MCIERR_SET_DRIVE = MCIERR_BASE + 53
MCIERR_DEVICE_LENGTH = MCIERR_BASE + 54
MCIERR_DEVICE_ORD_LENGTH = MCIERR_BASE + 55
MCIERR_NO_INTEGER = MCIERR_BASE + 56
MCIERR_WAVE_OUTPUTSINUSE = MCIERR_BASE + 64
MCIERR_WAVE_SETOUTPUTINUSE = MCIERR_BASE + 65
MCIERR_WAVE_INPUTSINUSE = MCIERR_BASE + 66
MCIERR_WAVE_SETINPUTINUSE = MCIERR_BASE + 67
MCIERR_WAVE_OUTPUTUNSPECIFIED = MCIERR_BASE + 68
MCIERR_WAVE_INPUTUNSPECIFIED = MCIERR_BASE + 69
MCIERR_WAVE_OUTPUTSUNSUITABLE = MCIERR_BASE + 70
MCIERR_WAVE_SETOUTPUTUNSUITABLE = MCIERR_BASE + 71
MCIERR_WAVE_INPUTSUNSUITABLE = MCIERR_BASE + 72
MCIERR_WAVE_SETINPUTUNSUITABLE = MCIERR_BASE + 73
MCIERR_SEQ_DIV_INCOMPATIBLE = MCIERR_BASE + 80
MCIERR_SEQ_PORT_INUSE = MCIERR_BASE + 81
MCIERR_SEQ_PORT_NONEXISTENT = MCIERR_BASE + 82
MCIERR_SEQ_PORT_MAPNODEVICE = MCIERR_BASE + 83
MCIERR_SEQ_PORT_MISCERROR = MCIERR_BASE + 84
MCIERR_SEQ_TIMER = MCIERR_BASE + 85
MCIERR_SEQ_PORTUNSPECIFIED = MCIERR_BASE + 86
MCIERR_SEQ_NOMIDIPRESENT = MCIERR_BASE + 87
MCIERR_NO_WINDOW = MCIERR_BASE + 90
MCIERR_CREATEWINDOW = MCIERR_BASE + 91
MCIERR_FILE_READ = MCIERR_BASE + 92
MCIERR_FILE_WRITE = MCIERR_BASE + 93
MCIERR_NO_IDENTITY = MCIERR_BASE + 94
MCIERR_CUSTOM_DRIVER_BASE = MCIERR_BASE + 256
MCI_FIRST = DRV_MCI_FIRST
MCI_OPEN = 0x0803
MCI_CLOSE = 0x0804
MCI_ESCAPE = 0x0805
MCI_PLAY = 0x0806
MCI_SEEK = 0x0807
MCI_STOP = 0x0808
MCI_PAUSE = 0x0809
MCI_INFO = 0x080A
MCI_GETDEVCAPS = 0x080B
MCI_SPIN = 0x080C
MCI_SET = 0x080D
MCI_STEP = 0x080E
MCI_RECORD = 0x080F
MCI_SYSINFO = 0x0810
MCI_BREAK = 0x0811
MCI_SAVE = 0x0813
MCI_STATUS = 0x0814
MCI_CUE = 0x0830
MCI_REALIZE = 0x0840
MCI_WINDOW = 0x0841
MCI_PUT = 0x0842
MCI_WHERE = 0x0843
MCI_FREEZE = 0x0844
MCI_UNFREEZE = 0x0845
MCI_LOAD = 0x0850
MCI_CUT = 0x0851
MCI_COPY = 0x0852
MCI_PASTE = 0x0853
MCI_UPDATE = 0x0854
MCI_RESUME = 0x0855
MCI_DELETE = 0x0856
MCI_USER_MESSAGES = DRV_MCI_FIRST + 0x400
MCI_LAST = 0x0FFF
MCI_DEVTYPE_VCR = 513
MCI_DEVTYPE_VIDEODISC = 514
MCI_DEVTYPE_OVERLAY = 515
MCI_DEVTYPE_CD_AUDIO = 516
MCI_DEVTYPE_DAT = 517
MCI_DEVTYPE_SCANNER = 518
MCI_DEVTYPE_ANIMATION = 519
MCI_DEVTYPE_DIGITAL_VIDEO = 520
MCI_DEVTYPE_OTHER = 521
MCI_DEVTYPE_WAVEFORM_AUDIO = 522
MCI_DEVTYPE_SEQUENCER = 523
MCI_DEVTYPE_FIRST = MCI_DEVTYPE_VCR
MCI_DEVTYPE_LAST = MCI_DEVTYPE_SEQUENCER
MCI_DEVTYPE_FIRST_USER = 0x1000
MCI_MODE_NOT_READY = MCI_STRING_OFFSET + 12
MCI_MODE_STOP = MCI_STRING_OFFSET + 13
MCI_MODE_PLAY = MCI_STRING_OFFSET + 14
MCI_MODE_RECORD = MCI_STRING_OFFSET + 15
MCI_MODE_SEEK = MCI_STRING_OFFSET + 16
MCI_MODE_PAUSE = MCI_STRING_OFFSET + 17
MCI_MODE_OPEN = MCI_STRING_OFFSET + 18
MCI_FORMAT_MILLISECONDS = 0
MCI_FORMAT_HMS = 1
MCI_FORMAT_MSF = 2
MCI_FORMAT_FRAMES = 3
MCI_FORMAT_SMPTE_24 = 4
MCI_FORMAT_SMPTE_25 = 5
MCI_FORMAT_SMPTE_30 = 6
MCI_FORMAT_SMPTE_30DROP = 7
MCI_FORMAT_BYTES = 8
MCI_FORMAT_SAMPLES = 9
MCI_FORMAT_TMSF = 10
def MCI_MSF_MINUTE(msf):
return msf
def MCI_MSF_SECOND(msf):
return msf >> 8
def MCI_MSF_FRAME(msf):
return msf >> 16
def MCI_TMSF_TRACK(tmsf):
return tmsf
def MCI_TMSF_MINUTE(tmsf):
return tmsf >> 8
def MCI_TMSF_SECOND(tmsf):
return tmsf >> 16
def MCI_TMSF_FRAME(tmsf):
return tmsf >> 24
def MCI_HMS_HOUR(hms):
return hms
def MCI_HMS_MINUTE(hms):
return hms >> 8
def MCI_HMS_SECOND(hms):
return hms >> 16
MCI_NOTIFY_SUCCESSFUL = 0x0001
MCI_NOTIFY_SUPERSEDED = 0x0002
MCI_NOTIFY_ABORTED = 0x0004
MCI_NOTIFY_FAILURE = 0x0008
MCI_NOTIFY = 0x00000001
MCI_WAIT = 0x00000002
MCI_FROM = 0x00000004
MCI_TO = 0x00000008
MCI_TRACK = 0x00000010
MCI_OPEN_SHAREABLE = 0x00000100
MCI_OPEN_ELEMENT = 0x00000200
MCI_OPEN_ALIAS = 0x00000400
MCI_OPEN_ELEMENT_ID = 0x00000800
MCI_OPEN_TYPE_ID = 0x00001000
MCI_OPEN_TYPE = 0x00002000
MCI_SEEK_TO_START = 0x00000100
MCI_SEEK_TO_END = 0x00000200
MCI_STATUS_ITEM = 0x00000100
MCI_STATUS_START = 0x00000200
MCI_STATUS_LENGTH = 0x00000001
MCI_STATUS_POSITION = 0x00000002
MCI_STATUS_NUMBER_OF_TRACKS = 0x00000003
MCI_STATUS_MODE = 0x00000004
MCI_STATUS_MEDIA_PRESENT = 0x00000005
MCI_STATUS_TIME_FORMAT = 0x00000006
MCI_STATUS_READY = 0x00000007
MCI_STATUS_CURRENT_TRACK = 0x00000008
MCI_INFO_PRODUCT = 0x00000100
MCI_INFO_FILE = 0x00000200
MCI_INFO_MEDIA_UPC = 0x00000400
MCI_INFO_MEDIA_IDENTITY = 0x00000800
MCI_INFO_NAME = 0x00001000
MCI_INFO_COPYRIGHT = 0x00002000
MCI_GETDEVCAPS_ITEM = 0x00000100
MCI_GETDEVCAPS_CAN_RECORD = 0x00000001
MCI_GETDEVCAPS_HAS_AUDIO = 0x00000002
MCI_GETDEVCAPS_HAS_VIDEO = 0x00000003
MCI_GETDEVCAPS_DEVICE_TYPE = 0x00000004
MCI_GETDEVCAPS_USES_FILES = 0x00000005
MCI_GETDEVCAPS_COMPOUND_DEVICE = 0x00000006
MCI_GETDEVCAPS_CAN_EJECT = 0x00000007
MCI_GETDEVCAPS_CAN_PLAY = 0x00000008
MCI_GETDEVCAPS_CAN_SAVE = 0x00000009
MCI_SYSINFO_QUANTITY = 0x00000100
MCI_SYSINFO_OPEN = 0x00000200
MCI_SYSINFO_NAME = 0x00000400
MCI_SYSINFO_INSTALLNAME = 0x00000800
MCI_SET_DOOR_OPEN = 0x00000100
MCI_SET_DOOR_CLOSED = 0x00000200
MCI_SET_TIME_FORMAT = 0x00000400
MCI_SET_AUDIO = 0x00000800
MCI_SET_VIDEO = 0x00001000
MCI_SET_ON = 0x00002000
MCI_SET_OFF = 0x00004000
MCI_SET_AUDIO_ALL = 0x00000000
MCI_SET_AUDIO_LEFT = 0x00000001
MCI_SET_AUDIO_RIGHT = 0x00000002
MCI_BREAK_KEY = 0x00000100
MCI_BREAK_HWND = 0x00000200
MCI_BREAK_OFF = 0x00000400
MCI_RECORD_INSERT = 0x00000100
MCI_RECORD_OVERWRITE = 0x00000200
MCI_SAVE_FILE = 0x00000100
MCI_LOAD_FILE = 0x00000100
MCI_VD_MODE_PARK = MCI_VD_OFFSET + 1
MCI_VD_MEDIA_CLV = MCI_VD_OFFSET + 2
MCI_VD_MEDIA_CAV = MCI_VD_OFFSET + 3
MCI_VD_MEDIA_OTHER = MCI_VD_OFFSET + 4
MCI_VD_FORMAT_TRACK = 0x4001
MCI_VD_PLAY_REVERSE = 0x00010000
MCI_VD_PLAY_FAST = 0x00020000
MCI_VD_PLAY_SPEED = 0x00040000
MCI_VD_PLAY_SCAN = 0x00080000
MCI_VD_PLAY_SLOW = 0x00100000
MCI_VD_SEEK_REVERSE = 0x00010000
MCI_VD_STATUS_SPEED = 0x00004002
MCI_VD_STATUS_FORWARD = 0x00004003
MCI_VD_STATUS_MEDIA_TYPE = 0x00004004
MCI_VD_STATUS_SIDE = 0x00004005
MCI_VD_STATUS_DISC_SIZE = 0x00004006
MCI_VD_GETDEVCAPS_CLV = 0x00010000
MCI_VD_GETDEVCAPS_CAV = 0x00020000
MCI_VD_SPIN_UP = 0x00010000
MCI_VD_SPIN_DOWN = 0x00020000
MCI_VD_GETDEVCAPS_CAN_REVERSE = 0x00004002
MCI_VD_GETDEVCAPS_FAST_RATE = 0x00004003
MCI_VD_GETDEVCAPS_SLOW_RATE = 0x00004004
MCI_VD_GETDEVCAPS_NORMAL_RATE = 0x00004005
MCI_VD_STEP_FRAMES = 0x00010000
MCI_VD_STEP_REVERSE = 0x00020000
MCI_VD_ESCAPE_STRING = 0x00000100
MCI_CDA_STATUS_TYPE_TRACK = 0x00004001
MCI_CDA_TRACK_AUDIO = MCI_CD_OFFSET + 0
MCI_CDA_TRACK_OTHER = MCI_CD_OFFSET + 1
MCI_WAVE_PCM = MCI_WAVE_OFFSET + 0
MCI_WAVE_MAPPER = MCI_WAVE_OFFSET + 1
MCI_WAVE_OPEN_BUFFER = 0x00010000
MCI_WAVE_SET_FORMATTAG = 0x00010000
MCI_WAVE_SET_CHANNELS = 0x00020000
MCI_WAVE_SET_SAMPLESPERSEC = 0x00040000
MCI_WAVE_SET_AVGBYTESPERSEC = 0x00080000
MCI_WAVE_SET_BLOCKALIGN = 0x00100000
MCI_WAVE_SET_BITSPERSAMPLE = 0x00200000
MCI_WAVE_INPUT = 0x00400000
MCI_WAVE_OUTPUT = 0x00800000
MCI_WAVE_STATUS_FORMATTAG = 0x00004001
MCI_WAVE_STATUS_CHANNELS = 0x00004002
MCI_WAVE_STATUS_SAMPLESPERSEC = 0x00004003
MCI_WAVE_STATUS_AVGBYTESPERSEC = 0x00004004
MCI_WAVE_STATUS_BLOCKALIGN = 0x00004005
MCI_WAVE_STATUS_BITSPERSAMPLE = 0x00004006
MCI_WAVE_STATUS_LEVEL = 0x00004007
MCI_WAVE_SET_ANYINPUT = 0x04000000
MCI_WAVE_SET_ANYOUTPUT = 0x08000000
MCI_WAVE_GETDEVCAPS_INPUTS = 0x00004001
MCI_WAVE_GETDEVCAPS_OUTPUTS = 0x00004002
MCI_SEQ_DIV_PPQN = 0 + MCI_SEQ_OFFSET
MCI_SEQ_DIV_SMPTE_24 = 1 + MCI_SEQ_OFFSET
MCI_SEQ_DIV_SMPTE_25 = 2 + MCI_SEQ_OFFSET
MCI_SEQ_DIV_SMPTE_30DROP = 3 + MCI_SEQ_OFFSET
MCI_SEQ_DIV_SMPTE_30 = 4 + MCI_SEQ_OFFSET
MCI_SEQ_FORMAT_SONGPTR = 0x4001
MCI_SEQ_FILE = 0x4002
MCI_SEQ_MIDI = 0x4003
MCI_SEQ_SMPTE = 0x4004
MCI_SEQ_NONE = 65533
MCI_SEQ_MAPPER = 65535
MCI_SEQ_STATUS_TEMPO = 0x00004002
MCI_SEQ_STATUS_PORT = 0x00004003
MCI_SEQ_STATUS_SLAVE = 0x00004007
MCI_SEQ_STATUS_MASTER = 0x00004008
MCI_SEQ_STATUS_OFFSET = 0x00004009
MCI_SEQ_STATUS_DIVTYPE = 0x0000400A
MCI_SEQ_STATUS_NAME = 0x0000400B
MCI_SEQ_STATUS_COPYRIGHT = 0x0000400C
MCI_SEQ_SET_TEMPO = 0x00010000
MCI_SEQ_SET_PORT = 0x00020000
MCI_SEQ_SET_SLAVE = 0x00040000
MCI_SEQ_SET_MASTER = 0x00080000
MCI_SEQ_SET_OFFSET = 0x01000000
MCI_ANIM_OPEN_WS = 0x00010000
MCI_ANIM_OPEN_PARENT = 0x00020000
MCI_ANIM_OPEN_NOSTATIC = 0x00040000
MCI_ANIM_PLAY_SPEED = 0x00010000
MCI_ANIM_PLAY_REVERSE = 0x00020000
MCI_ANIM_PLAY_FAST = 0x00040000
MCI_ANIM_PLAY_SLOW = 0x00080000
MCI_ANIM_PLAY_SCAN = 0x00100000
MCI_ANIM_STEP_REVERSE = 0x00010000
MCI_ANIM_STEP_FRAMES = 0x00020000
MCI_ANIM_STATUS_SPEED = 0x00004001
MCI_ANIM_STATUS_FORWARD = 0x00004002
MCI_ANIM_STATUS_HWND = 0x00004003
MCI_ANIM_STATUS_HPAL = 0x00004004
MCI_ANIM_STATUS_STRETCH = 0x00004005
MCI_ANIM_INFO_TEXT = 0x00010000
MCI_ANIM_GETDEVCAPS_CAN_REVERSE = 0x00004001
MCI_ANIM_GETDEVCAPS_FAST_RATE = 0x00004002
MCI_ANIM_GETDEVCAPS_SLOW_RATE = 0x00004003
MCI_ANIM_GETDEVCAPS_NORMAL_RATE = 0x00004004
MCI_ANIM_GETDEVCAPS_PALETTES = 0x00004006
MCI_ANIM_GETDEVCAPS_CAN_STRETCH = 0x00004007
MCI_ANIM_GETDEVCAPS_MAX_WINDOWS = 0x00004008
MCI_ANIM_REALIZE_NORM = 0x00010000
MCI_ANIM_REALIZE_BKGD = 0x00020000
MCI_ANIM_WINDOW_HWND = 0x00010000
MCI_ANIM_WINDOW_STATE = 0x00040000
MCI_ANIM_WINDOW_TEXT = 0x00080000
MCI_ANIM_WINDOW_ENABLE_STRETCH = 0x00100000
MCI_ANIM_WINDOW_DISABLE_STRETCH = 0x00200000
MCI_ANIM_WINDOW_DEFAULT = 0x00000000
MCI_ANIM_RECT = 0x00010000
MCI_ANIM_PUT_SOURCE = 0x00020000
MCI_ANIM_PUT_DESTINATION = 0x00040000
MCI_ANIM_WHERE_SOURCE = 0x00020000
MCI_ANIM_WHERE_DESTINATION = 0x00040000
MCI_ANIM_UPDATE_HDC = 0x00020000
MCI_OVLY_OPEN_WS = 0x00010000
MCI_OVLY_OPEN_PARENT = 0x00020000
MCI_OVLY_STATUS_HWND = 0x00004001
MCI_OVLY_STATUS_STRETCH = 0x00004002
MCI_OVLY_INFO_TEXT = 0x00010000
MCI_OVLY_GETDEVCAPS_CAN_STRETCH = 0x00004001
MCI_OVLY_GETDEVCAPS_CAN_FREEZE = 0x00004002
MCI_OVLY_GETDEVCAPS_MAX_WINDOWS = 0x00004003
MCI_OVLY_WINDOW_HWND = 0x00010000
MCI_OVLY_WINDOW_STATE = 0x00040000
MCI_OVLY_WINDOW_TEXT = 0x00080000
MCI_OVLY_WINDOW_ENABLE_STRETCH = 0x00100000
MCI_OVLY_WINDOW_DISABLE_STRETCH = 0x00200000
MCI_OVLY_WINDOW_DEFAULT = 0x00000000
MCI_OVLY_RECT = 0x00010000
MCI_OVLY_PUT_SOURCE = 0x00020000
MCI_OVLY_PUT_DESTINATION = 0x00040000
MCI_OVLY_PUT_FRAME = 0x00080000
MCI_OVLY_PUT_VIDEO = 0x00100000
MCI_OVLY_WHERE_SOURCE = 0x00020000
MCI_OVLY_WHERE_DESTINATION = 0x00040000
MCI_OVLY_WHERE_FRAME = 0x00080000
MCI_OVLY_WHERE_VIDEO = 0x00100000
SELECTDIB = 41
def DIBINDEX(n):
return win32api.MAKELONG(n, 0x10FF)

View File

@@ -0,0 +1,293 @@
from __future__ import annotations
import struct
from collections.abc import Iterable
import win32wnet
# Constants generated by h2py from nb30.h
NCBNAMSZ = 16
MAX_LANA = 254
NAME_FLAGS_MASK = 0x87
GROUP_NAME = 0x80
UNIQUE_NAME = 0x00
REGISTERING = 0x00
REGISTERED = 0x04
DEREGISTERED = 0x05
DUPLICATE = 0x06
DUPLICATE_DEREG = 0x07
LISTEN_OUTSTANDING = 0x01
CALL_PENDING = 0x02
SESSION_ESTABLISHED = 0x03
HANGUP_PENDING = 0x04
HANGUP_COMPLETE = 0x05
SESSION_ABORTED = 0x06
ALL_TRANSPORTS = "M\0\0\0"
MS_NBF = "MNBF"
NCBCALL = 0x10
NCBLISTEN = 0x11
NCBHANGUP = 0x12
NCBSEND = 0x14
NCBRECV = 0x15
NCBRECVANY = 0x16
NCBCHAINSEND = 0x17
NCBDGSEND = 0x20
NCBDGRECV = 0x21
NCBDGSENDBC = 0x22
NCBDGRECVBC = 0x23
NCBADDNAME = 0x30
NCBDELNAME = 0x31
NCBRESET = 0x32
NCBASTAT = 0x33
NCBSSTAT = 0x34
NCBCANCEL = 0x35
NCBADDGRNAME = 0x36
NCBENUM = 0x37
NCBUNLINK = 0x70
NCBSENDNA = 0x71
NCBCHAINSENDNA = 0x72
NCBLANSTALERT = 0x73
NCBACTION = 0x77
NCBFINDNAME = 0x78
NCBTRACE = 0x79
ASYNCH = 0x80
NRC_GOODRET = 0x00
NRC_BUFLEN = 0x01
NRC_ILLCMD = 0x03
NRC_CMDTMO = 0x05
NRC_INCOMP = 0x06
NRC_BADDR = 0x07
NRC_SNUMOUT = 0x08
NRC_NORES = 0x09
NRC_SCLOSED = 0x0A
NRC_CMDCAN = 0x0B
NRC_DUPNAME = 0x0D
NRC_NAMTFUL = 0x0E
NRC_ACTSES = 0x0F
NRC_LOCTFUL = 0x11
NRC_REMTFUL = 0x12
NRC_ILLNN = 0x13
NRC_NOCALL = 0x14
NRC_NOWILD = 0x15
NRC_INUSE = 0x16
NRC_NAMERR = 0x17
NRC_SABORT = 0x18
NRC_NAMCONF = 0x19
NRC_IFBUSY = 0x21
NRC_TOOMANY = 0x22
NRC_BRIDGE = 0x23
NRC_CANOCCR = 0x24
NRC_CANCEL = 0x26
NRC_DUPENV = 0x30
NRC_ENVNOTDEF = 0x34
NRC_OSRESNOTAV = 0x35
NRC_MAXAPPS = 0x36
NRC_NOSAPS = 0x37
NRC_NORESOURCES = 0x38
NRC_INVADDRESS = 0x39
NRC_INVDDID = 0x3B
NRC_LOCKFAIL = 0x3C
NRC_OPENERR = 0x3F
NRC_SYSTEM = 0x40
NRC_PENDING = 0xFF
UCHAR = "B"
WORD = "H"
DWORD = "I"
USHORT = "H"
ULONG = "I"
ADAPTER_STATUS_ITEMS = [
("6s", "adapter_address"),
(UCHAR, "rev_major"),
(UCHAR, "reserved0"),
(UCHAR, "adapter_type"),
(UCHAR, "rev_minor"),
(WORD, "duration"),
(WORD, "frmr_recv"),
(WORD, "frmr_xmit"),
(WORD, "iframe_recv_err"),
(WORD, "xmit_aborts"),
(DWORD, "xmit_success"),
(DWORD, "recv_success"),
(WORD, "iframe_xmit_err"),
(WORD, "recv_buff_unavail"),
(WORD, "t1_timeouts"),
(WORD, "ti_timeouts"),
(DWORD, "reserved1"),
(WORD, "free_ncbs"),
(WORD, "max_cfg_ncbs"),
(WORD, "max_ncbs"),
(WORD, "xmit_buf_unavail"),
(WORD, "max_dgram_size"),
(WORD, "pending_sess"),
(WORD, "max_cfg_sess"),
(WORD, "max_sess"),
(WORD, "max_sess_pkt_size"),
(WORD, "name_count"),
]
NAME_BUFFER_ITEMS = [
(str(NCBNAMSZ) + "s", "name"),
(UCHAR, "name_num"),
(UCHAR, "name_flags"),
]
SESSION_HEADER_ITEMS = [
(UCHAR, "sess_name"),
(UCHAR, "num_sess"),
(UCHAR, "rcv_dg_outstanding"),
(UCHAR, "rcv_any_outstanding"),
]
SESSION_BUFFER_ITEMS = [
(UCHAR, "lsn"),
(UCHAR, "state"),
(str(NCBNAMSZ) + "s", "local_name"),
(str(NCBNAMSZ) + "s", "remote_name"),
(UCHAR, "rcvs_outstanding"),
(UCHAR, "sends_outstanding"),
]
LANA_ENUM_ITEMS = [
("B", "length"), # Number of valid entries in lana[]
(str(MAX_LANA + 1) + "s", "lana"),
]
FIND_NAME_HEADER_ITEMS = [
(WORD, "node_count"),
(UCHAR, "reserved"),
(UCHAR, "unique_group"),
]
FIND_NAME_BUFFER_ITEMS = [
(UCHAR, "length"),
(UCHAR, "access_control"),
(UCHAR, "frame_control"),
("6s", "destination_addr"),
("6s", "source_addr"),
("18s", "routing_info"),
]
ACTION_HEADER_ITEMS = [
(ULONG, "transport_id"),
(USHORT, "action_code"),
(USHORT, "reserved"),
]
del UCHAR, WORD, DWORD, USHORT, ULONG
NCB = win32wnet.NCB
def Netbios(ncb):
ob = ncb.Buffer
is_ours = hasattr(ob, "_pack")
if is_ours:
ob._pack()
try:
return win32wnet.Netbios(ncb)
finally:
if is_ours:
ob._unpack()
class NCBStruct:
def __init__(self, items: Iterable[tuple[str, str]]) -> None:
self._format = "".join([item[0] for item in items])
self._items = items
self._buffer_ = win32wnet.NCBBuffer(struct.calcsize(self._format))
for format, name in self._items:
if len(format) == 1:
if format == "c":
val: bytes | int = b"\0"
else:
val = 0
else:
l = int(format[:-1])
val = b"\0" * l
self.__dict__[name] = val
def _pack(self):
vals = [self.__dict__.get(name) for format, name in self._items]
self._buffer_[:] = struct.pack(self._format, *vals)
def _unpack(self):
items = struct.unpack(self._format, self._buffer_)
assert len(items) == len(self._items), "unexpected number of items to unpack!"
for (format, name), val in zip(self._items, items):
self.__dict__[name] = val
def __setattr__(self, attr, val):
if attr not in self.__dict__ and attr[0] != "_":
for format, attr_name in self._items:
if attr == attr_name:
break
else:
raise AttributeError(attr)
self.__dict__[attr] = val
def ADAPTER_STATUS():
return NCBStruct(ADAPTER_STATUS_ITEMS)
def NAME_BUFFER():
return NCBStruct(NAME_BUFFER_ITEMS)
def SESSION_HEADER():
return NCBStruct(SESSION_HEADER_ITEMS)
def SESSION_BUFFER():
return NCBStruct(SESSION_BUFFER_ITEMS)
def LANA_ENUM():
return NCBStruct(LANA_ENUM_ITEMS)
def FIND_NAME_HEADER():
return NCBStruct(FIND_NAME_HEADER_ITEMS)
def FIND_NAME_BUFFER():
return NCBStruct(FIND_NAME_BUFFER_ITEMS)
def ACTION_HEADER():
return NCBStruct(ACTION_HEADER_ITEMS)
if __name__ == "__main__":
# code ported from "HOWTO: Get the MAC Address for an Ethernet Adapter"
# MS KB ID: Q118623
ncb = NCB()
ncb.Command = NCBENUM
la_enum = LANA_ENUM()
ncb.Buffer = la_enum
rc = Netbios(ncb)
if rc != 0:
raise RuntimeError("Unexpected result %d" % (rc,))
for i in range(la_enum.length):
ncb.Reset()
ncb.Command = NCBRESET
ncb.Lana_num = la_enum.lana[i]
rc = Netbios(ncb)
if rc != 0:
raise RuntimeError("Unexpected result %d" % (rc,))
ncb.Reset()
ncb.Command = NCBASTAT
ncb.Lana_num = la_enum.lana[i]
ncb.Callname = b"* "
adapter = ADAPTER_STATUS()
ncb.Buffer = adapter
Netbios(ncb)
print("Adapter address:", end=" ")
for ch in adapter.adapter_address:
print(f"{ch:02x}", end=" ")
print()

View File

@@ -0,0 +1,731 @@
# Hacked from winnt.h
DELETE = 65536
READ_CONTROL = 131072
WRITE_DAC = 262144
WRITE_OWNER = 524288
SYNCHRONIZE = 1048576
STANDARD_RIGHTS_REQUIRED = 983040
STANDARD_RIGHTS_READ = READ_CONTROL
STANDARD_RIGHTS_WRITE = READ_CONTROL
STANDARD_RIGHTS_EXECUTE = READ_CONTROL
STANDARD_RIGHTS_ALL = 2031616
SPECIFIC_RIGHTS_ALL = 65535
ACCESS_SYSTEM_SECURITY = 16777216
MAXIMUM_ALLOWED = 33554432
GENERIC_READ = -2147483648
GENERIC_WRITE = 1073741824
GENERIC_EXECUTE = 536870912
GENERIC_ALL = 268435456
# file security permissions
FILE_READ_DATA = 1
FILE_LIST_DIRECTORY = 1
FILE_WRITE_DATA = 2
FILE_ADD_FILE = 2
FILE_APPEND_DATA = 4
FILE_ADD_SUBDIRECTORY = 4
FILE_CREATE_PIPE_INSTANCE = 4
FILE_READ_EA = 8
FILE_WRITE_EA = 16
FILE_EXECUTE = 32
FILE_TRAVERSE = 32
FILE_DELETE_CHILD = 64
FILE_READ_ATTRIBUTES = 128
FILE_WRITE_ATTRIBUTES = 256
FILE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 511
FILE_GENERIC_READ = (
STANDARD_RIGHTS_READ
| FILE_READ_DATA
| FILE_READ_ATTRIBUTES
| FILE_READ_EA
| SYNCHRONIZE
)
FILE_GENERIC_WRITE = (
STANDARD_RIGHTS_WRITE
| FILE_WRITE_DATA
| FILE_WRITE_ATTRIBUTES
| FILE_WRITE_EA
| FILE_APPEND_DATA
| SYNCHRONIZE
)
FILE_GENERIC_EXECUTE = (
STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE
)
SECURITY_NULL_SID_AUTHORITY = (0, 0, 0, 0, 0, 0)
SECURITY_WORLD_SID_AUTHORITY = (0, 0, 0, 0, 0, 1)
SECURITY_LOCAL_SID_AUTHORITY = (0, 0, 0, 0, 0, 2)
SECURITY_CREATOR_SID_AUTHORITY = (0, 0, 0, 0, 0, 3)
SECURITY_NON_UNIQUE_AUTHORITY = (0, 0, 0, 0, 0, 4)
SECURITY_RESOURCE_MANAGER_AUTHORITY = (0, 0, 0, 0, 0, 9)
SECURITY_NULL_RID = 0
SECURITY_WORLD_RID = 0
SECURITY_LOCAL_RID = 0x00000000
SECURITY_CREATOR_OWNER_RID = 0
SECURITY_CREATOR_GROUP_RID = 1
SECURITY_CREATOR_OWNER_SERVER_RID = 2
SECURITY_CREATOR_GROUP_SERVER_RID = 3
SECURITY_CREATOR_OWNER_RIGHTS_RID = 4
# NT well-known SIDs
SECURITY_NT_AUTHORITY = (0, 0, 0, 0, 0, 5)
SECURITY_DIALUP_RID = 1
SECURITY_NETWORK_RID = 2
SECURITY_BATCH_RID = 3
SECURITY_INTERACTIVE_RID = 4
SECURITY_SERVICE_RID = 6
SECURITY_ANONYMOUS_LOGON_RID = 7
SECURITY_PROXY_RID = 8
SECURITY_SERVER_LOGON_RID = 9
SECURITY_LOGON_IDS_RID = 5
SECURITY_LOGON_IDS_RID_COUNT = 3
SECURITY_LOCAL_SYSTEM_RID = 18
SECURITY_NT_NON_UNIQUE = 21
SECURITY_BUILTIN_DOMAIN_RID = 32
# well-known domain relative sub-authority values (RIDs)...
DOMAIN_USER_RID_ADMIN = 500
DOMAIN_USER_RID_GUEST = 501
DOMAIN_USER_RID_KRBTGT = 502
DOMAIN_USER_RID_MAX = 999
# well-known groups ...
DOMAIN_GROUP_RID_ADMINS = 512
DOMAIN_GROUP_RID_USERS = 513
DOMAIN_GROUP_RID_GUESTS = 514
DOMAIN_GROUP_RID_COMPUTERS = 515
DOMAIN_GROUP_RID_CONTROLLERS = 516
DOMAIN_GROUP_RID_CERT_ADMINS = 517
DOMAIN_GROUP_RID_SCHEMA_ADMINS = 518
DOMAIN_GROUP_RID_ENTERPRISE_ADMINS = 519
DOMAIN_GROUP_RID_POLICY_ADMINS = 520
DOMAIN_GROUP_RID_READONLY_CONTROLLERS = 521
# well-known aliases ...
DOMAIN_ALIAS_RID_ADMINS = 544
DOMAIN_ALIAS_RID_USERS = 545
DOMAIN_ALIAS_RID_GUESTS = 546
DOMAIN_ALIAS_RID_POWER_USERS = 547
DOMAIN_ALIAS_RID_ACCOUNT_OPS = 548
DOMAIN_ALIAS_RID_SYSTEM_OPS = 549
DOMAIN_ALIAS_RID_PRINT_OPS = 550
DOMAIN_ALIAS_RID_BACKUP_OPS = 551
DOMAIN_ALIAS_RID_REPLICATOR = 552
DOMAIN_ALIAS_RID_RAS_SERVERS = 553
DOMAIN_ALIAS_RID_PREW2KCOMPACCESS = 554
DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS = 555
DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS = 556
DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS = 557
DOMAIN_ALIAS_RID_MONITORING_USERS = 558
DOMAIN_ALIAS_RID_LOGGING_USERS = 559
DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS = 560
DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS = 561
DOMAIN_ALIAS_RID_DCOM_USERS = 562
DOMAIN_ALIAS_RID_IUSERS = 568
DOMAIN_ALIAS_RID_CRYPTO_OPERATORS = 569
DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP = 571
DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP = 572
DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP = 573
SECURITY_MANDATORY_LABEL_AUTHORITY = (0, 0, 0, 0, 0, 16)
SECURITY_MANDATORY_UNTRUSTED_RID = 0x00000000
SECURITY_MANDATORY_LOW_RID = 0x00001000
SECURITY_MANDATORY_MEDIUM_RID = 0x00002000
SECURITY_MANDATORY_HIGH_RID = 0x00003000
SECURITY_MANDATORY_SYSTEM_RID = 0x00004000
SECURITY_MANDATORY_PROTECTED_PROCESS_RID = 0x00005000
SECURITY_MANDATORY_MAXIMUM_USER_RID = SECURITY_MANDATORY_SYSTEM_RID
SYSTEM_LUID = (999, 0)
ANONYMOUS_LOGON_LUID = (998, 0)
LOCALSERVICE_LUID = (997, 0)
NETWORKSERVICE_LUID = (996, 0)
IUSER_LUID = (995, 0)
# Group attributes
SE_GROUP_MANDATORY = 1
SE_GROUP_ENABLED_BY_DEFAULT = 2
SE_GROUP_ENABLED = 4
SE_GROUP_OWNER = 8
SE_GROUP_USE_FOR_DENY_ONLY = 16
SE_GROUP_INTEGRITY = 32
SE_GROUP_INTEGRITY_ENABLED = 64
SE_GROUP_RESOURCE = 536870912
SE_GROUP_LOGON_ID = -1073741824
# User attributes
# (None yet defined.)
# ACE types
ACCESS_MIN_MS_ACE_TYPE = 0
ACCESS_ALLOWED_ACE_TYPE = 0
ACCESS_DENIED_ACE_TYPE = 1
SYSTEM_AUDIT_ACE_TYPE = 2
SYSTEM_ALARM_ACE_TYPE = 3
ACCESS_MAX_MS_V2_ACE_TYPE = 3
ACCESS_ALLOWED_COMPOUND_ACE_TYPE = 4
ACCESS_MAX_MS_V3_ACE_TYPE = 4
ACCESS_MIN_MS_OBJECT_ACE_TYPE = 5
ACCESS_ALLOWED_OBJECT_ACE_TYPE = 5
ACCESS_DENIED_OBJECT_ACE_TYPE = 6
SYSTEM_AUDIT_OBJECT_ACE_TYPE = 7
SYSTEM_ALARM_OBJECT_ACE_TYPE = 8
ACCESS_MAX_MS_OBJECT_ACE_TYPE = 8
ACCESS_MAX_MS_V4_ACE_TYPE = 8
ACCESS_MAX_MS_ACE_TYPE = 8
ACCESS_ALLOWED_CALLBACK_ACE_TYPE = 9
ACCESS_DENIED_CALLBACK_ACE_TYPE = 10
ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE = 11
ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE = 12
SYSTEM_AUDIT_CALLBACK_ACE_TYPE = 13
SYSTEM_ALARM_CALLBACK_ACE_TYPE = 14
SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE = 15
SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE = 16
SYSTEM_MANDATORY_LABEL_ACE_TYPE = 17
ACCESS_MAX_MS_V5_ACE_TYPE = 17
# The following are the inherit flags that go into the AceFlags field
# of an Ace header.
OBJECT_INHERIT_ACE = 1
CONTAINER_INHERIT_ACE = 2
NO_PROPAGATE_INHERIT_ACE = 4
INHERIT_ONLY_ACE = 8
VALID_INHERIT_FLAGS = 15
SUCCESSFUL_ACCESS_ACE_FLAG = 64
FAILED_ACCESS_ACE_FLAG = 128
SE_OWNER_DEFAULTED = 1
SE_GROUP_DEFAULTED = 2
SE_DACL_PRESENT = 4
SE_DACL_DEFAULTED = 8
SE_SACL_PRESENT = 16
SE_SACL_DEFAULTED = 32
SE_SELF_RELATIVE = 32768
SE_PRIVILEGE_ENABLED_BY_DEFAULT = 1
SE_PRIVILEGE_ENABLED = 2
SE_PRIVILEGE_USED_FOR_ACCESS = -2147483648
PRIVILEGE_SET_ALL_NECESSARY = 1
# NT Defined Privileges
SE_CREATE_TOKEN_NAME = "SeCreateTokenPrivilege"
SE_ASSIGNPRIMARYTOKEN_NAME = "SeAssignPrimaryTokenPrivilege"
SE_LOCK_MEMORY_NAME = "SeLockMemoryPrivilege"
SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege"
SE_UNSOLICITED_INPUT_NAME = "SeUnsolicitedInputPrivilege"
SE_MACHINE_ACCOUNT_NAME = "SeMachineAccountPrivilege"
SE_TCB_NAME = "SeTcbPrivilege"
SE_SECURITY_NAME = "SeSecurityPrivilege"
SE_TAKE_OWNERSHIP_NAME = "SeTakeOwnershipPrivilege"
SE_LOAD_DRIVER_NAME = "SeLoadDriverPrivilege"
SE_SYSTEM_PROFILE_NAME = "SeSystemProfilePrivilege"
SE_SYSTEMTIME_NAME = "SeSystemtimePrivilege"
SE_PROF_SINGLE_PROCESS_NAME = "SeProfileSingleProcessPrivilege"
SE_INC_BASE_PRIORITY_NAME = "SeIncreaseBasePriorityPrivilege"
SE_CREATE_PAGEFILE_NAME = "SeCreatePagefilePrivilege"
SE_CREATE_PERMANENT_NAME = "SeCreatePermanentPrivilege"
SE_BACKUP_NAME = "SeBackupPrivilege"
SE_RESTORE_NAME = "SeRestorePrivilege"
SE_SHUTDOWN_NAME = "SeShutdownPrivilege"
SE_DEBUG_NAME = "SeDebugPrivilege"
SE_AUDIT_NAME = "SeAuditPrivilege"
SE_SYSTEM_ENVIRONMENT_NAME = "SeSystemEnvironmentPrivilege"
SE_CHANGE_NOTIFY_NAME = "SeChangeNotifyPrivilege"
SE_REMOTE_SHUTDOWN_NAME = "SeRemoteShutdownPrivilege"
# Enum SECURITY_IMPERSONATION_LEVEL:
SecurityAnonymous = 0
SecurityIdentification = 1
SecurityImpersonation = 2
SecurityDelegation = 3
SECURITY_MAX_IMPERSONATION_LEVEL = SecurityDelegation
DEFAULT_IMPERSONATION_LEVEL = SecurityImpersonation
TOKEN_ASSIGN_PRIMARY = 1
TOKEN_DUPLICATE = 2
TOKEN_IMPERSONATE = 4
TOKEN_QUERY = 8
TOKEN_QUERY_SOURCE = 16
TOKEN_ADJUST_PRIVILEGES = 32
TOKEN_ADJUST_GROUPS = 64
TOKEN_ADJUST_DEFAULT = 128
TOKEN_ALL_ACCESS = (
STANDARD_RIGHTS_REQUIRED
| TOKEN_ASSIGN_PRIMARY
| TOKEN_DUPLICATE
| TOKEN_IMPERSONATE
| TOKEN_QUERY
| TOKEN_QUERY_SOURCE
| TOKEN_ADJUST_PRIVILEGES
| TOKEN_ADJUST_GROUPS
| TOKEN_ADJUST_DEFAULT
)
TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY
TOKEN_WRITE = (
STANDARD_RIGHTS_WRITE
| TOKEN_ADJUST_PRIVILEGES
| TOKEN_ADJUST_GROUPS
| TOKEN_ADJUST_DEFAULT
)
TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE
SidTypeUser = 1
SidTypeGroup = 2
SidTypeDomain = 3
SidTypeAlias = 4
SidTypeWellKnownGroup = 5
SidTypeDeletedAccount = 6
SidTypeInvalid = 7
SidTypeUnknown = 8
SidTypeComputer = 9
SidTypeLabel = 10
# Token types
TokenPrimary = 1
TokenImpersonation = 2
# TOKEN_INFORMATION_CLASS, used with Get/SetTokenInformation
TokenUser = 1
TokenGroups = 2
TokenPrivileges = 3
TokenOwner = 4
TokenPrimaryGroup = 5
TokenDefaultDacl = 6
TokenSource = 7
TokenType = 8
TokenImpersonationLevel = 9
TokenStatistics = 10
TokenRestrictedSids = 11
TokenSessionId = 12
TokenGroupsAndPrivileges = 13
TokenSessionReference = 14
TokenSandBoxInert = 15
TokenAuditPolicy = 16
TokenOrigin = 17
TokenElevationType = 18
TokenLinkedToken = 19
TokenElevation = 20
TokenHasRestrictions = 21
TokenAccessInformation = 22
TokenVirtualizationAllowed = 23
TokenVirtualizationEnabled = 24
TokenIntegrityLevel = 25
TokenUIAccess = 26
TokenMandatoryPolicy = 27
TokenLogonSid = 28
# DirectoryService related constants.
# Generated by h2py from NtDsAPI.h
DS_BEHAVIOR_WIN2000 = 0
DS_BEHAVIOR_WIN2003_WITH_MIXED_DOMAINS = 1
DS_BEHAVIOR_WIN2003 = 2
DS_SYNCED_EVENT_NAME = "NTDSInitialSyncsCompleted"
ACTRL_DS_OPEN = 0x00000000
ACTRL_DS_CREATE_CHILD = 0x00000001
ACTRL_DS_DELETE_CHILD = 0x00000002
ACTRL_DS_LIST = 0x00000004
ACTRL_DS_SELF = 0x00000008
ACTRL_DS_READ_PROP = 0x00000010
ACTRL_DS_WRITE_PROP = 0x00000020
ACTRL_DS_DELETE_TREE = 0x00000040
ACTRL_DS_LIST_OBJECT = 0x00000080
ACTRL_DS_CONTROL_ACCESS = 0x00000100
NTDSAPI_BIND_ALLOW_DELEGATION = 0x00000001
DS_REPSYNC_ASYNCHRONOUS_OPERATION = 0x00000001
DS_REPSYNC_WRITEABLE = 0x00000002
DS_REPSYNC_PERIODIC = 0x00000004
DS_REPSYNC_INTERSITE_MESSAGING = 0x00000008
DS_REPSYNC_ALL_SOURCES = 0x00000010
DS_REPSYNC_FULL = 0x00000020
DS_REPSYNC_URGENT = 0x00000040
DS_REPSYNC_NO_DISCARD = 0x00000080
DS_REPSYNC_FORCE = 0x00000100
DS_REPSYNC_ADD_REFERENCE = 0x00000200
DS_REPSYNC_NEVER_COMPLETED = 0x00000400
DS_REPSYNC_TWO_WAY = 0x00000800
DS_REPSYNC_NEVER_NOTIFY = 0x00001000
DS_REPSYNC_INITIAL = 0x00002000
DS_REPSYNC_USE_COMPRESSION = 0x00004000
DS_REPSYNC_ABANDONED = 0x00008000
DS_REPSYNC_INITIAL_IN_PROGRESS = 0x00010000
DS_REPSYNC_PARTIAL_ATTRIBUTE_SET = 0x00020000
DS_REPSYNC_REQUEUE = 0x00040000
DS_REPSYNC_NOTIFICATION = 0x00080000
DS_REPSYNC_ASYNCHRONOUS_REPLICA = 0x00100000
DS_REPSYNC_CRITICAL = 0x00200000
DS_REPSYNC_FULL_IN_PROGRESS = 0x00400000
DS_REPSYNC_PREEMPTED = 0x00800000
DS_REPADD_ASYNCHRONOUS_OPERATION = 0x00000001
DS_REPADD_WRITEABLE = 0x00000002
DS_REPADD_INITIAL = 0x00000004
DS_REPADD_PERIODIC = 0x00000008
DS_REPADD_INTERSITE_MESSAGING = 0x00000010
DS_REPADD_ASYNCHRONOUS_REPLICA = 0x00000020
DS_REPADD_DISABLE_NOTIFICATION = 0x00000040
DS_REPADD_DISABLE_PERIODIC = 0x00000080
DS_REPADD_USE_COMPRESSION = 0x00000100
DS_REPADD_NEVER_NOTIFY = 0x00000200
DS_REPADD_TWO_WAY = 0x00000400
DS_REPADD_CRITICAL = 0x00000800
DS_REPDEL_ASYNCHRONOUS_OPERATION = 0x00000001
DS_REPDEL_WRITEABLE = 0x00000002
DS_REPDEL_INTERSITE_MESSAGING = 0x00000004
DS_REPDEL_IGNORE_ERRORS = 0x00000008
DS_REPDEL_LOCAL_ONLY = 0x00000010
DS_REPDEL_NO_SOURCE = 0x00000020
DS_REPDEL_REF_OK = 0x00000040
DS_REPMOD_ASYNCHRONOUS_OPERATION = 0x00000001
DS_REPMOD_WRITEABLE = 0x00000002
DS_REPMOD_UPDATE_FLAGS = 0x00000001
DS_REPMOD_UPDATE_ADDRESS = 0x00000002
DS_REPMOD_UPDATE_SCHEDULE = 0x00000004
DS_REPMOD_UPDATE_RESULT = 0x00000008
DS_REPMOD_UPDATE_TRANSPORT = 0x00000010
DS_REPUPD_ASYNCHRONOUS_OPERATION = 0x00000001
DS_REPUPD_WRITEABLE = 0x00000002
DS_REPUPD_ADD_REFERENCE = 0x00000004
DS_REPUPD_DELETE_REFERENCE = 0x00000008
DS_INSTANCETYPE_IS_NC_HEAD = 0x00000001
DS_INSTANCETYPE_NC_IS_WRITEABLE = 0x00000004
DS_INSTANCETYPE_NC_COMING = 0x00000010
DS_INSTANCETYPE_NC_GOING = 0x00000020
NTDSDSA_OPT_IS_GC = 1 << 0
NTDSDSA_OPT_DISABLE_INBOUND_REPL = 1 << 1
NTDSDSA_OPT_DISABLE_OUTBOUND_REPL = 1 << 2
NTDSDSA_OPT_DISABLE_NTDSCONN_XLATE = 1 << 3
NTDSCONN_OPT_IS_GENERATED = 1 << 0
NTDSCONN_OPT_TWOWAY_SYNC = 1 << 1
NTDSCONN_OPT_OVERRIDE_NOTIFY_DEFAULT = 1 << 2
NTDSCONN_OPT_USE_NOTIFY = 1 << 3
NTDSCONN_OPT_DISABLE_INTERSITE_COMPRESSION = 1 << 4
NTDSCONN_OPT_USER_OWNED_SCHEDULE = 1 << 5
NTDSCONN_KCC_NO_REASON = 0
NTDSCONN_KCC_GC_TOPOLOGY = 1 << 0
NTDSCONN_KCC_RING_TOPOLOGY = 1 << 1
NTDSCONN_KCC_MINIMIZE_HOPS_TOPOLOGY = 1 << 2
NTDSCONN_KCC_STALE_SERVERS_TOPOLOGY = 1 << 3
NTDSCONN_KCC_OSCILLATING_CONNECTION_TOPOLOGY = 1 << 4
NTDSCONN_KCC_INTERSITE_GC_TOPOLOGY = 1 << 5
NTDSCONN_KCC_INTERSITE_TOPOLOGY = 1 << 6
NTDSCONN_KCC_SERVER_FAILOVER_TOPOLOGY = 1 << 7
NTDSCONN_KCC_SITE_FAILOVER_TOPOLOGY = 1 << 8
NTDSCONN_KCC_REDUNDANT_SERVER_TOPOLOGY = 1 << 9
FRSCONN_PRIORITY_MASK = 0x70000000
FRSCONN_MAX_PRIORITY = 0x8
NTDSCONN_OPT_IGNORE_SCHEDULE_MASK = -2147483648
NTDSSETTINGS_OPT_IS_AUTO_TOPOLOGY_DISABLED = 1 << 0
NTDSSETTINGS_OPT_IS_TOPL_CLEANUP_DISABLED = 1 << 1
NTDSSETTINGS_OPT_IS_TOPL_MIN_HOPS_DISABLED = 1 << 2
NTDSSETTINGS_OPT_IS_TOPL_DETECT_STALE_DISABLED = 1 << 3
NTDSSETTINGS_OPT_IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED = 1 << 4
NTDSSETTINGS_OPT_IS_GROUP_CACHING_ENABLED = 1 << 5
NTDSSETTINGS_OPT_FORCE_KCC_WHISTLER_BEHAVIOR = 1 << 6
NTDSSETTINGS_OPT_FORCE_KCC_W2K_ELECTION = 1 << 7
NTDSSETTINGS_OPT_IS_RAND_BH_SELECTION_DISABLED = 1 << 8
NTDSSETTINGS_OPT_IS_SCHEDULE_HASHING_ENABLED = 1 << 9
NTDSSETTINGS_OPT_IS_REDUNDANT_SERVER_TOPOLOGY_ENABLED = 1 << 10
NTDSSETTINGS_DEFAULT_SERVER_REDUNDANCY = 2
NTDSTRANSPORT_OPT_IGNORE_SCHEDULES = 1 << 0
NTDSTRANSPORT_OPT_BRIDGES_REQUIRED = 1 << 1
NTDSSITECONN_OPT_USE_NOTIFY = 1 << 0
NTDSSITECONN_OPT_TWOWAY_SYNC = 1 << 1
NTDSSITECONN_OPT_DISABLE_COMPRESSION = 1 << 2
NTDSSITELINK_OPT_USE_NOTIFY = 1 << 0
NTDSSITELINK_OPT_TWOWAY_SYNC = 1 << 1
NTDSSITELINK_OPT_DISABLE_COMPRESSION = 1 << 2
GUID_USERS_CONTAINER_A = "a9d1ca15768811d1aded00c04fd8d5cd"
GUID_COMPUTRS_CONTAINER_A = "aa312825768811d1aded00c04fd8d5cd"
GUID_SYSTEMS_CONTAINER_A = "ab1d30f3768811d1aded00c04fd8d5cd"
GUID_DOMAIN_CONTROLLERS_CONTAINER_A = "a361b2ffffd211d1aa4b00c04fd7d83a"
GUID_INFRASTRUCTURE_CONTAINER_A = "2fbac1870ade11d297c400c04fd8d5cd"
GUID_DELETED_OBJECTS_CONTAINER_A = "18e2ea80684f11d2b9aa00c04f79f805"
GUID_LOSTANDFOUND_CONTAINER_A = "ab8153b7768811d1aded00c04fd8d5cd"
GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER_A = "22b70c67d56e4efb91e9300fca3dc1aa"
GUID_PROGRAM_DATA_CONTAINER_A = "09460c08ae1e4a4ea0f64aee7daa1e5a"
GUID_MICROSOFT_PROGRAM_DATA_CONTAINER_A = "f4be92a4c777485e878e9421d53087db"
GUID_NTDS_QUOTAS_CONTAINER_A = "6227f0af1fc2410d8e3bb10615bb5b0f"
GUID_USERS_CONTAINER_BYTE = (
"\xa9\xd1\xca\x15\x76\x88\x11\xd1\xad\xed\x00\xc0\x4f\xd8\xd5\xcd"
)
GUID_COMPUTRS_CONTAINER_BYTE = (
"\xaa\x31\x28\x25\x76\x88\x11\xd1\xad\xed\x00\xc0\x4f\xd8\xd5\xcd"
)
GUID_SYSTEMS_CONTAINER_BYTE = (
"\xab\x1d\x30\xf3\x76\x88\x11\xd1\xad\xed\x00\xc0\x4f\xd8\xd5\xcd"
)
GUID_DOMAIN_CONTROLLERS_CONTAINER_BYTE = (
"\xa3\x61\xb2\xff\xff\xd2\x11\xd1\xaa\x4b\x00\xc0\x4f\xd7\xd8\x3a"
)
GUID_INFRASTRUCTURE_CONTAINER_BYTE = (
"\x2f\xba\xc1\x87\x0a\xde\x11\xd2\x97\xc4\x00\xc0\x4f\xd8\xd5\xcd"
)
GUID_DELETED_OBJECTS_CONTAINER_BYTE = (
"\x18\xe2\xea\x80\x68\x4f\x11\xd2\xb9\xaa\x00\xc0\x4f\x79\xf8\x05"
)
GUID_LOSTANDFOUND_CONTAINER_BYTE = (
"\xab\x81\x53\xb7\x76\x88\x11\xd1\xad\xed\x00\xc0\x4f\xd8\xd5\xcd"
)
GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER_BYTE = (
"\x22\xb7\x0c\x67\xd5\x6e\x4e\xfb\x91\xe9\x30\x0f\xca\x3d\xc1\xaa"
)
GUID_PROGRAM_DATA_CONTAINER_BYTE = (
"\x09\x46\x0c\x08\xae\x1e\x4a\x4e\xa0\xf6\x4a\xee\x7d\xaa\x1e\x5a"
)
GUID_MICROSOFT_PROGRAM_DATA_CONTAINER_BYTE = (
"\xf4\xbe\x92\xa4\xc7\x77\x48\x5e\x87\x8e\x94\x21\xd5\x30\x87\xdb"
)
GUID_NTDS_QUOTAS_CONTAINER_BYTE = (
"\x62\x27\xf0\xaf\x1f\xc2\x41\x0d\x8e\x3b\xb1\x06\x15\xbb\x5b\x0f"
)
DS_REPSYNCALL_NO_OPTIONS = 0x00000000
DS_REPSYNCALL_ABORT_IF_SERVER_UNAVAILABLE = 0x00000001
DS_REPSYNCALL_SYNC_ADJACENT_SERVERS_ONLY = 0x00000002
DS_REPSYNCALL_ID_SERVERS_BY_DN = 0x00000004
DS_REPSYNCALL_DO_NOT_SYNC = 0x00000008
DS_REPSYNCALL_SKIP_INITIAL_CHECK = 0x00000010
DS_REPSYNCALL_PUSH_CHANGES_OUTWARD = 0x00000020
DS_REPSYNCALL_CROSS_SITE_BOUNDARIES = 0x00000040
DS_LIST_DSA_OBJECT_FOR_SERVER = 0
DS_LIST_DNS_HOST_NAME_FOR_SERVER = 1
DS_LIST_ACCOUNT_OBJECT_FOR_SERVER = 2
DS_ROLE_SCHEMA_OWNER = 0
DS_ROLE_DOMAIN_OWNER = 1
DS_ROLE_PDC_OWNER = 2
DS_ROLE_RID_OWNER = 3
DS_ROLE_INFRASTRUCTURE_OWNER = 4
DS_SCHEMA_GUID_NOT_FOUND = 0
DS_SCHEMA_GUID_ATTR = 1
DS_SCHEMA_GUID_ATTR_SET = 2
DS_SCHEMA_GUID_CLASS = 3
DS_SCHEMA_GUID_CONTROL_RIGHT = 4
DS_KCC_FLAG_ASYNC_OP = 1 << 0
DS_KCC_FLAG_DAMPED = 1 << 1
DS_EXIST_ADVISORY_MODE = 0x1
DS_REPL_INFO_FLAG_IMPROVE_LINKED_ATTRS = 0x00000001
DS_REPL_NBR_WRITEABLE = 0x00000010
DS_REPL_NBR_SYNC_ON_STARTUP = 0x00000020
DS_REPL_NBR_DO_SCHEDULED_SYNCS = 0x00000040
DS_REPL_NBR_USE_ASYNC_INTERSITE_TRANSPORT = 0x00000080
DS_REPL_NBR_TWO_WAY_SYNC = 0x00000200
DS_REPL_NBR_RETURN_OBJECT_PARENTS = 0x00000800
DS_REPL_NBR_FULL_SYNC_IN_PROGRESS = 0x00010000
DS_REPL_NBR_FULL_SYNC_NEXT_PACKET = 0x00020000
DS_REPL_NBR_NEVER_SYNCED = 0x00200000
DS_REPL_NBR_PREEMPTED = 0x01000000
DS_REPL_NBR_IGNORE_CHANGE_NOTIFICATIONS = 0x04000000
DS_REPL_NBR_DISABLE_SCHEDULED_SYNC = 0x08000000
DS_REPL_NBR_COMPRESS_CHANGES = 0x10000000
DS_REPL_NBR_NO_CHANGE_NOTIFICATIONS = 0x20000000
DS_REPL_NBR_PARTIAL_ATTRIBUTE_SET = 0x40000000
DS_REPL_NBR_MODIFIABLE_MASK = (
DS_REPL_NBR_SYNC_ON_STARTUP
| DS_REPL_NBR_DO_SCHEDULED_SYNCS
| DS_REPL_NBR_TWO_WAY_SYNC
| DS_REPL_NBR_IGNORE_CHANGE_NOTIFICATIONS
| DS_REPL_NBR_DISABLE_SCHEDULED_SYNC
| DS_REPL_NBR_COMPRESS_CHANGES
| DS_REPL_NBR_NO_CHANGE_NOTIFICATIONS
)
# from enum DS_NAME_FORMAT
DS_UNKNOWN_NAME = 0
DS_FQDN_1779_NAME = 1
DS_NT4_ACCOUNT_NAME = 2
DS_DISPLAY_NAME = 3
DS_UNIQUE_ID_NAME = 6
DS_CANONICAL_NAME = 7
DS_USER_PRINCIPAL_NAME = 8
DS_CANONICAL_NAME_EX = 9
DS_SERVICE_PRINCIPAL_NAME = 10
DS_SID_OR_SID_HISTORY_NAME = 11
DS_DNS_DOMAIN_NAME = 12
DS_DOMAIN_SIMPLE_NAME = DS_USER_PRINCIPAL_NAME
DS_ENTERPRISE_SIMPLE_NAME = DS_USER_PRINCIPAL_NAME
# from enum DS_NAME_FLAGS
DS_NAME_NO_FLAGS = 0x0
DS_NAME_FLAG_SYNTACTICAL_ONLY = 0x1
DS_NAME_FLAG_EVAL_AT_DC = 0x2
DS_NAME_FLAG_GCVERIFY = 0x4
DS_NAME_FLAG_TRUST_REFERRAL = 0x8
# from enum DS_NAME_ERROR
DS_NAME_NO_ERROR = 0
DS_NAME_ERROR_RESOLVING = 1
DS_NAME_ERROR_NOT_FOUND = 2
DS_NAME_ERROR_NOT_UNIQUE = 3
DS_NAME_ERROR_NO_MAPPING = 4
DS_NAME_ERROR_DOMAIN_ONLY = 5
DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING = 6
DS_NAME_ERROR_TRUST_REFERRAL = 7
# from enum DS_SPN_NAME_TYPE
DS_SPN_DNS_HOST = 0
DS_SPN_DN_HOST = 1
DS_SPN_NB_HOST = 2
DS_SPN_DOMAIN = 3
DS_SPN_NB_DOMAIN = 4
DS_SPN_SERVICE = 5
# from enum DS_SPN_WRITE_OP
DS_SPN_ADD_SPN_OP = 0
DS_SPN_REPLACE_SPN_OP = 1
DS_SPN_DELETE_SPN_OP = 2
# Generated by h2py from DsGetDC.h
DS_FORCE_REDISCOVERY = 0x00000001
DS_DIRECTORY_SERVICE_REQUIRED = 0x00000010
DS_DIRECTORY_SERVICE_PREFERRED = 0x00000020
DS_GC_SERVER_REQUIRED = 0x00000040
DS_PDC_REQUIRED = 0x00000080
DS_BACKGROUND_ONLY = 0x00000100
DS_IP_REQUIRED = 0x00000200
DS_KDC_REQUIRED = 0x00000400
DS_TIMESERV_REQUIRED = 0x00000800
DS_WRITABLE_REQUIRED = 0x00001000
DS_GOOD_TIMESERV_PREFERRED = 0x00002000
DS_AVOID_SELF = 0x00004000
DS_ONLY_LDAP_NEEDED = 0x00008000
DS_IS_FLAT_NAME = 0x00010000
DS_IS_DNS_NAME = 0x00020000
DS_RETURN_DNS_NAME = 0x40000000
DS_RETURN_FLAT_NAME = -2147483648
DSGETDC_VALID_FLAGS = (
DS_FORCE_REDISCOVERY
| DS_DIRECTORY_SERVICE_REQUIRED
| DS_DIRECTORY_SERVICE_PREFERRED
| DS_GC_SERVER_REQUIRED
| DS_PDC_REQUIRED
| DS_BACKGROUND_ONLY
| DS_IP_REQUIRED
| DS_KDC_REQUIRED
| DS_TIMESERV_REQUIRED
| DS_WRITABLE_REQUIRED
| DS_GOOD_TIMESERV_PREFERRED
| DS_AVOID_SELF
| DS_ONLY_LDAP_NEEDED
| DS_IS_FLAT_NAME
| DS_IS_DNS_NAME
| DS_RETURN_FLAT_NAME
| DS_RETURN_DNS_NAME
)
DS_INET_ADDRESS = 1
DS_NETBIOS_ADDRESS = 2
DS_PDC_FLAG = 0x00000001
DS_GC_FLAG = 0x00000004
DS_LDAP_FLAG = 0x00000008
DS_DS_FLAG = 0x00000010
DS_KDC_FLAG = 0x00000020
DS_TIMESERV_FLAG = 0x00000040
DS_CLOSEST_FLAG = 0x00000080
DS_WRITABLE_FLAG = 0x00000100
DS_GOOD_TIMESERV_FLAG = 0x00000200
DS_NDNC_FLAG = 0x00000400
DS_PING_FLAGS = 0x0000FFFF
DS_DNS_CONTROLLER_FLAG = 0x20000000
DS_DNS_DOMAIN_FLAG = 0x40000000
DS_DNS_FOREST_FLAG = -2147483648
DS_DOMAIN_IN_FOREST = 0x0001
DS_DOMAIN_DIRECT_OUTBOUND = 0x0002
DS_DOMAIN_TREE_ROOT = 0x0004
DS_DOMAIN_PRIMARY = 0x0008
DS_DOMAIN_NATIVE_MODE = 0x0010
DS_DOMAIN_DIRECT_INBOUND = 0x0020
DS_DOMAIN_VALID_FLAGS = (
DS_DOMAIN_IN_FOREST
| DS_DOMAIN_DIRECT_OUTBOUND
| DS_DOMAIN_TREE_ROOT
| DS_DOMAIN_PRIMARY
| DS_DOMAIN_NATIVE_MODE
| DS_DOMAIN_DIRECT_INBOUND
)
DS_GFTI_UPDATE_TDO = 0x1
DS_GFTI_VALID_FLAGS = 0x1
DS_ONLY_DO_SITE_NAME = 0x01
DS_NOTIFY_AFTER_SITE_RECORDS = 0x02
DS_OPEN_VALID_OPTION_FLAGS = DS_ONLY_DO_SITE_NAME | DS_NOTIFY_AFTER_SITE_RECORDS
DS_OPEN_VALID_FLAGS = (
DS_FORCE_REDISCOVERY
| DS_ONLY_LDAP_NEEDED
| DS_KDC_REQUIRED
| DS_PDC_REQUIRED
| DS_GC_SERVER_REQUIRED
| DS_WRITABLE_REQUIRED
)
## from aclui.h
# SI_OBJECT_INFO.dwFlags
SI_EDIT_PERMS = 0x00000000
SI_EDIT_OWNER = 0x00000001
SI_EDIT_AUDITS = 0x00000002
SI_CONTAINER = 0x00000004
SI_READONLY = 0x00000008
SI_ADVANCED = 0x00000010
SI_RESET = 0x00000020
SI_OWNER_READONLY = 0x00000040
SI_EDIT_PROPERTIES = 0x00000080
SI_OWNER_RECURSE = 0x00000100
SI_NO_ACL_PROTECT = 0x00000200
SI_NO_TREE_APPLY = 0x00000400
SI_PAGE_TITLE = 0x00000800
SI_SERVER_IS_DC = 0x00001000
SI_RESET_DACL_TREE = 0x00004000
SI_RESET_SACL_TREE = 0x00008000
SI_OBJECT_GUID = 0x00010000
SI_EDIT_EFFECTIVE = 0x00020000
SI_RESET_DACL = 0x00040000
SI_RESET_SACL = 0x00080000
SI_RESET_OWNER = 0x00100000
SI_NO_ADDITIONAL_PERMISSION = 0x00200000
SI_MAY_WRITE = 0x10000000
SI_EDIT_ALL = SI_EDIT_PERMS | SI_EDIT_OWNER | SI_EDIT_AUDITS
SI_AUDITS_ELEVATION_REQUIRED = 0x02000000
SI_VIEW_ONLY = 0x00400000
SI_OWNER_ELEVATION_REQUIRED = 0x04000000
SI_PERMS_ELEVATION_REQUIRED = 0x01000000
# SI_ACCESS.dwFlags
SI_ACCESS_SPECIFIC = 0x00010000
SI_ACCESS_GENERAL = 0x00020000
SI_ACCESS_CONTAINER = 0x00040000
SI_ACCESS_PROPERTY = 0x00080000
# SI_PAGE_TYPE enum
SI_PAGE_PERM = 0
SI_PAGE_ADVPERM = 1
SI_PAGE_AUDIT = 2
SI_PAGE_OWNER = 3
SI_PAGE_EFFECTIVE = 4
CFSTR_ACLUI_SID_INFO_LIST = "CFSTR_ACLUI_SID_INFO_LIST"
PSPCB_SI_INITDIALOG = 1025 ## WM_USER+1

View File

@@ -0,0 +1,21 @@
# Imported by pywin32.pth to bootstrap the pywin32 environment in "portable"
# environments or any other case where the post-install script isn't run.
#
# In short, there's a directory installed by pywin32 named 'pywin32_system32'
# with some important DLLs which need to be found by Python when some pywin32
# modules are imported.
try:
import pywin32_system32
except ImportError: # Python ≥3.6: replace ImportError with ModuleNotFoundError
pass
else:
import os
# We're guaranteed only that __path__: Iterable[str]
# https://docs.python.org/3/reference/import.html#path-attributes-on-modules
for path in pywin32_system32.__path__:
if os.path.isdir(path):
os.add_dll_directory(path)
break

View File

@@ -0,0 +1,291 @@
# Utilities for the pywin32 tests
import gc
import os
import site
import sys
import unittest
import winerror
##
## unittest related stuff
##
# This is a specialized TestCase adaptor which wraps a real test.
class LeakTestCase(unittest.TestCase):
"""An 'adaptor' which takes another test. In debug builds we execute the
test once to remove one-off side-effects, then capture the total
reference count, then execute the test a few times. If the total
refcount at the end is greater than we first captured, we have a leak!
In release builds the test is executed just once, as normal.
Generally used automatically by the test runner - you can safely
ignore this.
"""
def __init__(self, real_test):
unittest.TestCase.__init__(self)
self.real_test = real_test
self.num_test_cases = 1
self.num_leak_iters = 2 # seems to be enough!
if hasattr(sys, "gettotalrefcount"):
self.num_test_cases += self.num_leak_iters
def countTestCases(self):
return self.num_test_cases
def __call__(self, result=None):
# For the COM suite's sake, always ensure we don't leak
# gateways/interfaces
from pythoncom import _GetGatewayCount, _GetInterfaceCount
gc.collect()
ni = _GetInterfaceCount()
ng = _GetGatewayCount()
self.real_test(result)
# Failed - no point checking anything else
if result.shouldStop or not result.wasSuccessful():
return
self._do_leak_tests(result)
gc.collect()
lost_i = _GetInterfaceCount() - ni
lost_g = _GetGatewayCount() - ng
if lost_i or lost_g:
msg = "%d interface objects and %d gateway objects leaked" % (
lost_i,
lost_g,
)
exc = AssertionError(msg)
result.addFailure(self.real_test, (exc.__class__, exc, None))
def runTest(self):
raise NotImplementedError("not used")
def _do_leak_tests(self, result=None):
try:
gtrc = sys.gettotalrefcount
except AttributeError:
return # can't do leak tests in this build
# Assume already called once, to prime any caches etc
gc.collect()
trc = gtrc()
for i in range(self.num_leak_iters):
self.real_test(result)
if result.shouldStop:
break
del i # created after we remembered the refcount!
# int division here means one or 2 stray references won't force
# failure, but one per loop
gc.collect()
lost = (gtrc() - trc) // self.num_leak_iters
if lost < 0:
msg = "LeakTest: %s appeared to gain %d references!!" % (
self.real_test,
-lost,
)
result.addFailure(self.real_test, (AssertionError, msg, None))
if lost > 0:
msg = "LeakTest: %s lost %d references" % (self.real_test, lost)
exc = AssertionError(msg)
result.addFailure(self.real_test, (exc.__class__, exc, None))
class TestLoader(unittest.TestLoader):
def loadTestsFromTestCase(self, testCaseClass):
"""Return a suite of all tests cases contained in testCaseClass"""
leak_tests = []
for name in self.getTestCaseNames(testCaseClass):
real_test = testCaseClass(name)
leak_test = self._getTestWrapper(real_test)
leak_tests.append(leak_test)
return self.suiteClass(leak_tests)
def fixupTestsForLeakTests(self, test):
if isinstance(test, unittest.TestSuite):
test._tests = [self.fixupTestsForLeakTests(t) for t in test._tests]
return test
else:
# just a normal test case.
return self._getTestWrapper(test)
def _getTestWrapper(self, test):
# one or 2 tests in the COM test suite set this...
no_leak_tests = getattr(test, "no_leak_tests", False)
if no_leak_tests:
print("Test says it doesn't want leak tests!")
return test
return LeakTestCase(test)
def loadTestsFromModule(self, mod):
if hasattr(mod, "suite"):
tests = mod.suite()
else:
tests = unittest.TestLoader.loadTestsFromModule(self, mod)
return self.fixupTestsForLeakTests(tests)
def loadTestsFromName(self, name, module=None):
test = unittest.TestLoader.loadTestsFromName(self, name, module)
if isinstance(test, unittest.TestSuite):
# print("Don't wrap suites yet!", test._tests)
pass # hmmm?
elif isinstance(test, unittest.TestCase):
test = self._getTestWrapper(test)
else:
print("XXX - what is", test)
return test
# Lots of classes necessary to support one simple feature: we want a 3rd
# test result state - "SKIPPED" - to indicate that the test wasn't able
# to be executed for various reasons. Inspired by bzr's tests, but it
# has other concepts, such as "Expected Failure", which we don't bother
# with.
# win32 error codes that probably mean we need to be elevated (ie, if we
# aren't elevated, we treat these error codes as 'skipped')
non_admin_error_codes = [
winerror.ERROR_ACCESS_DENIED,
winerror.ERROR_PRIVILEGE_NOT_HELD,
]
_is_admin = None
def check_is_admin():
global _is_admin
if _is_admin is None:
import pythoncom
from win32com.shell.shell import IsUserAnAdmin
try:
_is_admin = IsUserAnAdmin()
except pythoncom.com_error as exc:
if exc.hresult != winerror.E_NOTIMPL:
raise
# not impl on this platform - must be old - assume is admin
_is_admin = True
return _is_admin
# Find a test "fixture" (eg, binary test file) expected to be very close to
# the test being run.
# If the tests are being run from the "installed" version, then these fixtures
# probably don't exist - the test is "skipped".
# But it's fatal if we think we might be running from a pywin32 source tree.
def find_test_fixture(basename, extra_dir="."):
# look for the test file in various places
candidates = [
os.path.dirname(sys.argv[0]),
extra_dir,
".",
]
for candidate in candidates:
fname = os.path.join(candidate, basename)
if os.path.isfile(fname):
return fname
else:
# Can't find it - see if this is expected or not.
# This module is typically always in the installed dir, so use argv[0]
this_file = os.path.normcase(os.path.abspath(sys.argv[0]))
dirs_to_check = site.getsitepackages()[:]
if site.USER_SITE:
dirs_to_check.append(site.USER_SITE)
for d in dirs_to_check:
d = os.path.normcase(d)
if os.path.commonprefix([this_file, d]) == d:
# looks like we are in an installed Python, so skip the text.
raise TestSkipped(f"Can't find test fixture '{fname}'")
# Looks like we are running from source, so this is fatal.
raise RuntimeError(f"Can't find test fixture '{fname}'")
# If this exception is raised by a test, the test is reported as a 'skip'
class TestSkipped(Exception):
pass
# The 'TestResult' subclass that records the failures and has the special
# handling for the TestSkipped exception.
class TestResult(unittest.TextTestResult):
def __init__(self, *args, **kw):
super().__init__(*args, **kw)
self.skips = {} # count of skips for each reason.
def addError(self, test, err):
"""Called when an error has occurred. 'err' is a tuple of values as
returned by sys.exc_info().
"""
# translate a couple of 'well-known' exceptions into 'skipped'
import pywintypes
exc_val = err[1]
# translate ERROR_ACCESS_DENIED for non-admin users to be skipped.
# (access denied errors for an admin user aren't expected.)
if (
isinstance(exc_val, pywintypes.error)
and exc_val.winerror in non_admin_error_codes
and not check_is_admin()
):
exc_val = TestSkipped(exc_val)
# and COM errors due to objects not being registered (the com test
# suite will attempt to catch this and handle it itself if the user
# is admin)
elif isinstance(exc_val, pywintypes.com_error) and exc_val.hresult in [
winerror.CO_E_CLASSSTRING,
winerror.REGDB_E_CLASSNOTREG,
winerror.TYPE_E_LIBNOTREGISTERED,
]:
exc_val = TestSkipped(exc_val)
# NotImplemented generally means the platform doesn't support the
# functionality.
elif isinstance(exc_val, NotImplementedError):
exc_val = TestSkipped(NotImplementedError)
if isinstance(exc_val, TestSkipped):
reason = exc_val.args[0]
# if the reason itself is another exception, get its args.
try:
reason = tuple(reason.args)
except (AttributeError, TypeError):
pass
self.skips.setdefault(reason, 0)
self.skips[reason] += 1
if self.showAll:
self.stream.writeln(f"SKIP ({reason})")
elif self.dots:
self.stream.write("S")
self.stream.flush()
return
super().addError(test, err)
def printErrors(self):
super().printErrors()
for reason, num_skipped in self.skips.items():
self.stream.writeln("SKIPPED: %d tests - %s" % (num_skipped, reason))
# TestRunner subclass necessary just to get our TestResult hooked up.
class TestRunner(unittest.TextTestRunner):
def _makeResult(self):
return TestResult(self.stream, self.descriptions, self.verbosity)
# TestProgram subclass necessary just to get our TestRunner hooked up,
# which is necessary to get our TestResult hooked up *sob*
class TestProgram(unittest.TestProgram):
def runTests(self):
# clobber existing runner - *sob* - it shouldn't be this hard
self.testRunner = TestRunner(verbosity=self.verbosity)
unittest.TestProgram.runTests(self)
# A convenient entry-point - if used, 'SKIPPED' exceptions will be suppressed.
def testmain(*args, **kw):
new_kw = kw.copy()
if "testLoader" not in new_kw:
new_kw["testLoader"] = TestLoader()
program_class = new_kw.get("testProgram", TestProgram)
program_class(*args, **new_kw)

View File

@@ -0,0 +1,124 @@
# Magic utility that "redirects" to pywintypesXX.dll
import importlib.machinery
import importlib.util
import os
import sys
def __import_pywin32_system_module__(modname, globs):
# This has been through a number of iterations. The problem: how to
# locate pywintypesXX.dll when it may be in a number of places, and how
# to avoid ever loading it twice. This problem is compounded by the
# fact that the "right" way to do this requires win32api, but this
# itself requires pywintypesXX.
# And the killer problem is that someone may have done 'import win32api'
# before this code is called. In that case Windows will have already
# loaded pywintypesXX as part of loading win32api - but by the time
# we get here, we may locate a different one. This appears to work, but
# then starts raising bizarre TypeErrors complaining that something
# is not a pywintypes type when it clearly is!
# So in what we hope is the last major iteration of this, we now
# rely on a _win32sysloader module, implemented in C but not relying
# on pywintypesXX.dll. It then can check if the DLL we are looking for
# lib is already loaded.
# See if this is a debug build.
suffix = "_d" if "_d.pyd" in importlib.machinery.EXTENSION_SUFFIXES else ""
filename = "%s%d%d%s.dll" % (
modname,
sys.version_info.major,
sys.version_info.minor,
suffix,
)
if hasattr(sys, "frozen"):
# If we are running from a frozen program (py2exe, McMillan, freeze, PyInstaller)
# then we try and load the DLL from our sys.path
# XXX - This path may also benefit from _win32sysloader? However,
# MarkH has never seen the DLL load problem with py2exe programs...
for look in sys.path:
# If the sys.path entry is a (presumably) .zip file, use the
# directory
if os.path.isfile(look):
look = os.path.dirname(look)
found = os.path.join(look, filename)
if os.path.isfile(found):
break
else:
raise ImportError(f"Module '{modname}' isn't in frozen sys.path {sys.path}")
else:
# First see if it already in our process - if so, we must use that.
import _win32sysloader
found = _win32sysloader.GetModuleFilename(filename)
if found is None:
# We ask Windows to load it next. This is in an attempt to
# get the exact same module loaded should pywintypes be imported
# first (which is how we are here) or if, eg, win32api was imported
# first thereby implicitly loading the DLL.
# Sadly though, it doesn't quite work - if pywintypesXX.dll
# is in system32 *and* the executable's directory, on XP SP2, an
# import of win32api will cause Windows to load pywintypes
# from system32, where LoadLibrary for that name will
# load the one in the exe's dir.
# That shouldn't really matter though, so long as we only ever
# get one loaded.
found = _win32sysloader.LoadModule(filename)
if found is None:
# Windows can't find it - which although isn't relevent here,
# means that we *must* be the first win32 import, as an attempt
# to import win32api etc would fail when Windows attempts to
# locate the DLL.
# This is most likely to happen for "non-admin" installs, where
# we can't put the files anywhere else on the global path.
# If there is a version in our Python directory, use that
if os.path.isfile(os.path.join(sys.prefix, filename)):
found = os.path.join(sys.prefix, filename)
if found is None:
# Not in the Python directory? Maybe we were installed via
# easy_install...
if os.path.isfile(os.path.join(os.path.dirname(__file__), filename)):
found = os.path.join(os.path.dirname(__file__), filename)
# There are 2 site-packages directories - one "global" and one "user".
# We could be in either, or both (but with different versions!). Factors include
# virtualenvs, post-install script being run or not, `pip install` flags, etc.
# In a worst-case, it means, say 'python -c "import win32api"'
# will not work but 'python -c "import pywintypes, win32api"' will,
# but it's better than nothing.
# We use the same logic as pywin32_bootstrap to find potential location for the dll
# Simply import pywin32_system32 and look in the paths in pywin32_system32.__path__
if found is None:
import pywin32_system32
for path in pywin32_system32.__path__:
maybe = os.path.join(path, filename)
if os.path.isfile(maybe):
found = maybe
break
if found is None:
# give up in disgust.
raise ImportError(f"No system module '{modname}' ({filename})")
# After importing the module, sys.modules is updated to the DLL we just
# loaded - which isn't what we want. So we update sys.modules to refer to
# this module, and update our globals from it.
old_mod = sys.modules[modname]
# Load the DLL.
loader = importlib.machinery.ExtensionFileLoader(modname, found)
spec = importlib.machinery.ModuleSpec(name=modname, loader=loader, origin=found)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
# Check the sys.modules[] behaviour we describe above is true...
assert sys.modules[modname] is mod
# as above - re-reset to the *old* module object then update globs.
sys.modules[modname] = old_mod
globs.update(mod.__dict__)
__import_pywin32_system_module__("pywintypes", globals())

View File

@@ -0,0 +1,40 @@
import win32ras
stateStrings = {
win32ras.RASCS_OpenPort: "OpenPort",
win32ras.RASCS_PortOpened: "PortOpened",
win32ras.RASCS_ConnectDevice: "ConnectDevice",
win32ras.RASCS_DeviceConnected: "DeviceConnected",
win32ras.RASCS_AllDevicesConnected: "AllDevicesConnected",
win32ras.RASCS_Authenticate: "Authenticate",
win32ras.RASCS_AuthNotify: "AuthNotify",
win32ras.RASCS_AuthRetry: "AuthRetry",
win32ras.RASCS_AuthCallback: "AuthCallback",
win32ras.RASCS_AuthChangePassword: "AuthChangePassword",
win32ras.RASCS_AuthProject: "AuthProject",
win32ras.RASCS_AuthLinkSpeed: "AuthLinkSpeed",
win32ras.RASCS_AuthAck: "AuthAck",
win32ras.RASCS_ReAuthenticate: "ReAuthenticate",
win32ras.RASCS_Authenticated: "Authenticated",
win32ras.RASCS_PrepareForCallback: "PrepareForCallback",
win32ras.RASCS_WaitForModemReset: "WaitForModemReset",
win32ras.RASCS_WaitForCallback: "WaitForCallback",
win32ras.RASCS_Projected: "Projected",
win32ras.RASCS_StartAuthentication: "StartAuthentication",
win32ras.RASCS_CallbackComplete: "CallbackComplete",
win32ras.RASCS_LogonNetwork: "LogonNetwork",
win32ras.RASCS_Interactive: "Interactive",
win32ras.RASCS_RetryAuthentication: "RetryAuthentication",
win32ras.RASCS_CallbackSetByCaller: "CallbackSetByCaller",
win32ras.RASCS_PasswordExpired: "PasswordExpired",
win32ras.RASCS_Connected: "Connected",
win32ras.RASCS_Disconnected: "Disconnected",
}
def TestCallback(hras, msg, state, error, exterror):
print("Callback called with ", hras, msg, stateStrings[state], error, exterror)
def test(rasName="_ Divert Off"):
return win32ras.Dial(None, None, (rasName,), TestCallback)

View File

@@ -0,0 +1,161 @@
# This module is very old and useless in this day and age! It will be
# removed in a few years (ie, 2009 or so...)
import warnings
warnings.warn(
"The regcheck module has been pending deprecation since build 210",
category=PendingDeprecationWarning,
)
import os
import sys
import regutil
import win32api
import win32con
def CheckRegisteredExe(exename):
try:
os.stat(
win32api.RegQueryValue(
regutil.GetRootKey(), regutil.GetAppPathsKey() + "\\" + exename
)
)
except (OSError, win32api.error):
print("Registration of %s - Not registered correctly" % exename)
def CheckPathString(pathString):
for path in pathString.split(";"):
if not os.path.isdir(path):
return "'%s' is not a valid directory!" % path
return None
def CheckPythonPaths(verbose):
if verbose:
print("Python Paths:")
# Check the core path
if verbose:
print("\tCore Path:", end=" ")
try:
appPath = win32api.RegQueryValue(
regutil.GetRootKey(), regutil.BuildDefaultPythonKey() + "\\PythonPath"
)
except win32api.error as exc:
print("** does not exist - ", exc.strerror)
problem = CheckPathString(appPath)
if problem:
print(problem)
else:
if verbose:
print(appPath)
key = win32api.RegOpenKey(
regutil.GetRootKey(),
regutil.BuildDefaultPythonKey() + "\\PythonPath",
0,
win32con.KEY_READ,
)
try:
keyNo = 0
while 1:
try:
appName = win32api.RegEnumKey(key, keyNo)
appPath = win32api.RegQueryValue(key, appName)
if verbose:
print("\t" + appName + ":", end=" ")
if appPath:
problem = CheckPathString(appPath)
if problem:
print(problem)
else:
if verbose:
print(appPath)
else:
if verbose:
print("(empty)")
keyNo += 1
except win32api.error:
break
finally:
win32api.RegCloseKey(key)
def CheckHelpFiles(verbose):
if verbose:
print("Help Files:")
try:
key = win32api.RegOpenKey(
regutil.GetRootKey(),
regutil.BuildDefaultPythonKey() + "\\Help",
0,
win32con.KEY_READ,
)
except win32api.error as exc:
import winerror
if exc.winerror != winerror.ERROR_FILE_NOT_FOUND:
raise
return
try:
keyNo = 0
while 1:
try:
helpDesc = win32api.RegEnumKey(key, keyNo)
helpFile = win32api.RegQueryValue(key, helpDesc)
if verbose:
print("\t" + helpDesc + ":", end=" ")
# query the os section.
try:
os.stat(helpFile)
if verbose:
print(helpFile)
except OSError:
print("** Help file %s does not exist" % helpFile)
keyNo += 1
except win32api.error as exc:
import winerror
if exc.winerror != winerror.ERROR_NO_MORE_ITEMS:
raise
break
finally:
win32api.RegCloseKey(key)
def CheckRegisteredModules(verbose):
# Check out all registered modules.
k = regutil.BuildDefaultPythonKey() + "\\Modules"
try:
keyhandle = win32api.RegOpenKey(regutil.GetRootKey(), k)
print("WARNING: 'Modules' registry entry is deprectated and evil!")
except win32api.error as exc:
import winerror
if exc.winerror != winerror.ERROR_FILE_NOT_FOUND:
raise
return
def CheckRegistry(verbose=0):
# check the registered modules
if verbose and "pythonpath" in os.environ:
print("Warning - PythonPath in environment - please check it!")
# Check out all paths on sys.path
CheckPythonPaths(verbose)
CheckHelpFiles(verbose)
CheckRegisteredModules(verbose)
CheckRegisteredExe("Python.exe")
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "-q":
verbose = 0
else:
verbose = 1
CheckRegistry(verbose)

View File

@@ -0,0 +1,395 @@
# Some registry helpers.
import os
import sys
import win32api
import win32con
# A .py file has a CLSID associated with it (why? - dunno!)
CLSIDPyFile = "{b51df050-06ae-11cf-ad3b-524153480001}"
RegistryIDPyFile = "Python.File" # The registry "file type" of a .py file
RegistryIDPycFile = "Python.CompiledFile" # The registry "file type" of a .pyc file
def BuildDefaultPythonKey():
"""Builds a string containing the path to the current registry key.
The Python registry key contains the Python version. This function
uses the version of the DLL used by the current process to get the
registry key currently in use.
"""
return "Software\\Python\\PythonCore\\" + sys.winver
def GetRootKey():
"""Retrieves the Registry root in use by Python."""
keyname = BuildDefaultPythonKey()
try:
k = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, keyname)
k.close()
return win32con.HKEY_CURRENT_USER
except win32api.error:
return win32con.HKEY_LOCAL_MACHINE
def GetRegistryDefaultValue(subkey, rootkey=None):
"""A helper to return the default value for a key in the registry."""
if rootkey is None:
rootkey = GetRootKey()
return win32api.RegQueryValue(rootkey, subkey)
def SetRegistryDefaultValue(subKey, value, rootkey=None):
"""A helper to set the default value for a key in the registry"""
if rootkey is None:
rootkey = GetRootKey()
if isinstance(value, str):
typeId = win32con.REG_SZ
elif isinstance(value, int):
typeId = win32con.REG_DWORD
else:
raise TypeError(f"Value must be string or integer - was passed {value!r}")
win32api.RegSetValue(rootkey, subKey, typeId, value)
def GetAppPathsKey():
return "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths"
def RegisterPythonExe(exeFullPath, exeAlias=None, exeAppPath=None):
"""Register a .exe file that uses Python.
Registers the .exe with the OS. This allows the specified .exe to
be run from the command-line or start button without using the full path,
and also to setup application specific path (ie, os.environ['PATH']).
Currently the exeAppPath is not supported, so this function is general
purpose, and not specific to Python at all. Later, exeAppPath may provide
a reasonable default that is used.
exeFullPath -- The full path to the .exe
exeAlias = None -- An alias for the exe - if none, the base portion
of the filename is used.
exeAppPath -- Not supported.
"""
# Note - Don't work on win32s (but we don't care anymore!)
if exeAppPath:
raise ValueError("Do not support exeAppPath argument currently")
if exeAlias is None:
exeAlias = os.path.basename(exeFullPath)
win32api.RegSetValue(
GetRootKey(), GetAppPathsKey() + "\\" + exeAlias, win32con.REG_SZ, exeFullPath
)
def GetRegisteredExe(exeAlias):
"""Get a registered .exe"""
return win32api.RegQueryValue(GetRootKey(), GetAppPathsKey() + "\\" + exeAlias)
def UnregisterPythonExe(exeAlias):
"""Unregister a .exe file that uses Python."""
try:
win32api.RegDeleteKey(GetRootKey(), GetAppPathsKey() + "\\" + exeAlias)
except win32api.error as exc:
import winerror
if exc.winerror != winerror.ERROR_FILE_NOT_FOUND:
raise
return
def RegisterNamedPath(name, path):
"""Register a named path - ie, a named PythonPath entry."""
keyStr = BuildDefaultPythonKey() + "\\PythonPath"
if name:
keyStr += "\\" + name
win32api.RegSetValue(GetRootKey(), keyStr, win32con.REG_SZ, path)
def UnregisterNamedPath(name):
"""Unregister a named path - ie, a named PythonPath entry."""
keyStr = BuildDefaultPythonKey() + "\\PythonPath\\" + name
try:
win32api.RegDeleteKey(GetRootKey(), keyStr)
except win32api.error as exc:
import winerror
if exc.winerror != winerror.ERROR_FILE_NOT_FOUND:
raise
return
def GetRegisteredNamedPath(name):
"""Get a registered named path, or None if it doesn't exist."""
keyStr = BuildDefaultPythonKey() + "\\PythonPath"
if name:
keyStr += "\\" + name
try:
return win32api.RegQueryValue(GetRootKey(), keyStr)
except win32api.error as exc:
import winerror
if exc.winerror != winerror.ERROR_FILE_NOT_FOUND:
raise
return None
def RegisterModule(modName, modPath):
"""Register an explicit module in the registry. This forces the Python import
mechanism to locate this module directly, without a sys.path search. Thus
a registered module need not appear in sys.path at all.
modName -- The name of the module, as used by import.
modPath -- The full path and file name of the module.
"""
try:
import os
os.stat(modPath)
except OSError:
print("Warning: Registering non-existant module %s" % modPath)
win32api.RegSetValue(
GetRootKey(),
BuildDefaultPythonKey() + "\\Modules\\%s" % modName,
win32con.REG_SZ,
modPath,
)
def UnregisterModule(modName):
"""Unregister an explicit module in the registry.
modName -- The name of the module, as used by import.
"""
try:
win32api.RegDeleteKey(
GetRootKey(), BuildDefaultPythonKey() + "\\Modules\\%s" % modName
)
except win32api.error as exc:
import winerror
if exc.winerror != winerror.ERROR_FILE_NOT_FOUND:
raise
def GetRegisteredHelpFile(helpDesc):
"""Given a description, return the registered entry."""
try:
return GetRegistryDefaultValue(BuildDefaultPythonKey() + "\\Help\\" + helpDesc)
except win32api.error:
try:
return GetRegistryDefaultValue(
BuildDefaultPythonKey() + "\\Help\\" + helpDesc,
win32con.HKEY_CURRENT_USER,
)
except win32api.error:
pass
return None
def RegisterHelpFile(helpFile, helpPath, helpDesc=None, bCheckFile=1):
"""Register a help file in the registry.
Note that this used to support writing to the Windows Help
key, however this is no longer done, as it seems to be incompatible.
helpFile -- the base name of the help file.
helpPath -- the path to the help file
helpDesc -- A description for the help file. If None, the helpFile param is used.
bCheckFile -- A flag indicating if the file existence should be checked.
"""
if helpDesc is None:
helpDesc = helpFile
fullHelpFile = os.path.join(helpPath, helpFile)
try:
if bCheckFile:
os.stat(fullHelpFile)
except OSError:
raise ValueError("Help file does not exist")
# Now register with Python itself.
win32api.RegSetValue(
GetRootKey(),
BuildDefaultPythonKey() + "\\Help\\%s" % helpDesc,
win32con.REG_SZ,
fullHelpFile,
)
def UnregisterHelpFile(helpFile, helpDesc=None):
"""Unregister a help file in the registry.
helpFile -- the base name of the help file.
helpDesc -- A description for the help file. If None, the helpFile param is used.
"""
key = win32api.RegOpenKey(
win32con.HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows\\Help",
0,
win32con.KEY_ALL_ACCESS,
)
try:
try:
win32api.RegDeleteValue(key, helpFile)
except win32api.error as exc:
import winerror
if exc.winerror != winerror.ERROR_FILE_NOT_FOUND:
raise
finally:
win32api.RegCloseKey(key)
# Now de-register with Python itself.
if helpDesc is None:
helpDesc = helpFile
try:
win32api.RegDeleteKey(
GetRootKey(), BuildDefaultPythonKey() + "\\Help\\%s" % helpDesc
)
except win32api.error as exc:
import winerror
if exc.winerror != winerror.ERROR_FILE_NOT_FOUND:
raise
def RegisterCoreDLL(coredllName=None):
"""Registers the core DLL in the registry.
If no params are passed, the name of the Python DLL used in
the current process is used and registered.
"""
if coredllName is None:
coredllName = win32api.GetModuleFileName(sys.dllhandle)
# must exist!
else:
try:
os.stat(coredllName)
except OSError:
print("Warning: Registering non-existant core DLL %s" % coredllName)
hKey = win32api.RegCreateKey(GetRootKey(), BuildDefaultPythonKey())
try:
win32api.RegSetValue(hKey, "Dll", win32con.REG_SZ, coredllName)
finally:
win32api.RegCloseKey(hKey)
# Lastly, setup the current version to point to me.
win32api.RegSetValue(
GetRootKey(),
"Software\\Python\\PythonCore\\CurrentVersion",
win32con.REG_SZ,
sys.winver,
)
def RegisterFileExtensions(defPyIcon, defPycIcon, runCommand):
"""Register the core Python file extensions.
defPyIcon -- The default icon to use for .py files, in 'fname,offset' format.
defPycIcon -- The default icon to use for .pyc files, in 'fname,offset' format.
runCommand -- The command line to use for running .py files
"""
# Register the file extensions.
pythonFileId = RegistryIDPyFile
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT, ".py", win32con.REG_SZ, pythonFileId
)
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT, pythonFileId, win32con.REG_SZ, "Python File"
)
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT,
"%s\\CLSID" % pythonFileId,
win32con.REG_SZ,
CLSIDPyFile,
)
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT,
"%s\\DefaultIcon" % pythonFileId,
win32con.REG_SZ,
defPyIcon,
)
base = "%s\\Shell" % RegistryIDPyFile
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT, base + "\\Open", win32con.REG_SZ, "Run"
)
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT,
base + "\\Open\\Command",
win32con.REG_SZ,
runCommand,
)
# Register the .PYC.
pythonFileId = RegistryIDPycFile
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT, ".pyc", win32con.REG_SZ, pythonFileId
)
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT,
pythonFileId,
win32con.REG_SZ,
"Compiled Python File",
)
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT,
"%s\\DefaultIcon" % pythonFileId,
win32con.REG_SZ,
defPycIcon,
)
base = "%s\\Shell" % pythonFileId
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT, base + "\\Open", win32con.REG_SZ, "Run"
)
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT,
base + "\\Open\\Command",
win32con.REG_SZ,
runCommand,
)
def RegisterShellCommand(shellCommand, exeCommand, shellUserCommand=None):
# Last param for "Open" - for a .py file to be executed by the command line
# or shell execute (eg, just entering "foo.py"), the Command must be "Open",
# but you may associate a different name for the right-click menu.
# In our case, normally we have "Open=Run"
base = "%s\\Shell" % RegistryIDPyFile
if shellUserCommand:
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT,
base + "\\%s" % (shellCommand),
win32con.REG_SZ,
shellUserCommand,
)
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT,
base + "\\%s\\Command" % (shellCommand),
win32con.REG_SZ,
exeCommand,
)
def RegisterDDECommand(shellCommand, ddeApp, ddeTopic, ddeCommand):
base = "%s\\Shell" % RegistryIDPyFile
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT,
base + "\\%s\\ddeexec" % (shellCommand),
win32con.REG_SZ,
ddeCommand,
)
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT,
base + "\\%s\\ddeexec\\Application" % (shellCommand),
win32con.REG_SZ,
ddeApp,
)
win32api.RegSetValue(
win32con.HKEY_CLASSES_ROOT,
base + "\\%s\\ddeexec\\Topic" % (shellCommand),
win32con.REG_SZ,
ddeTopic,
)

View File

@@ -0,0 +1,413 @@
"""
Helper classes for SSPI authentication via the win32security module.
SSPI authentication involves a token-exchange "dance", the exact details
of which depends on the authentication provider used. There are also
a number of complex flags and constants that need to be used - in most
cases, there are reasonable defaults.
These classes attempt to hide these details from you until you really need
to know. They are not designed to handle all cases, just the common ones.
If you need finer control than offered here, just use the win32security
functions directly.
"""
# Based on Roger Upole's sspi demos.
# $Id$
import sspicon
import win32security
error = win32security.error # Re-exported alias
class _BaseAuth:
def __init__(self):
self.reset()
def reset(self):
"""Reset everything to an unauthorized state"""
self.ctxt: win32security.PyCtxtHandleType | None = None
self.authenticated = False
self.initiator_name = None
self.service_name = None
# The next seq_num for an encrypt/sign operation
self.next_seq_num = 0
def _get_next_seq_num(self):
"""Get the next sequence number for a transmission. Default
implementation is to increment a counter
"""
ret = self.next_seq_num
self.next_seq_num += 1
return ret
def encrypt(self, data):
"""Encrypt a string, returning a tuple of (encrypted_data, trailer).
These can be passed to decrypt to get back the original string.
"""
pkg_size_info = self.ctxt.QueryContextAttributes(sspicon.SECPKG_ATTR_SIZES)
trailersize = pkg_size_info["SecurityTrailer"]
encbuf = win32security.PySecBufferDescType()
encbuf.append(win32security.PySecBufferType(len(data), sspicon.SECBUFFER_DATA))
encbuf.append(
win32security.PySecBufferType(trailersize, sspicon.SECBUFFER_TOKEN)
)
encbuf[0].Buffer = data
self.ctxt.EncryptMessage(0, encbuf, self._get_next_seq_num())
return encbuf[0].Buffer, encbuf[1].Buffer
def decrypt(self, data, trailer):
"""Decrypt a previously encrypted string, returning the orignal data"""
encbuf = win32security.PySecBufferDescType()
encbuf.append(win32security.PySecBufferType(len(data), sspicon.SECBUFFER_DATA))
encbuf.append(
win32security.PySecBufferType(len(trailer), sspicon.SECBUFFER_TOKEN)
)
encbuf[0].Buffer = data
encbuf[1].Buffer = trailer
self.ctxt.DecryptMessage(encbuf, self._get_next_seq_num())
return encbuf[0].Buffer
def sign(self, data):
"""sign a string suitable for transmission, returning the signature.
Passing the data and signature to verify will determine if the data
is unchanged.
"""
pkg_size_info = self.ctxt.QueryContextAttributes(sspicon.SECPKG_ATTR_SIZES)
sigsize = pkg_size_info["MaxSignature"]
sigbuf = win32security.PySecBufferDescType()
sigbuf.append(win32security.PySecBufferType(len(data), sspicon.SECBUFFER_DATA))
sigbuf.append(win32security.PySecBufferType(sigsize, sspicon.SECBUFFER_TOKEN))
sigbuf[0].Buffer = data
self.ctxt.MakeSignature(0, sigbuf, self._get_next_seq_num())
return sigbuf[1].Buffer
def verify(self, data, sig):
"""Verifies data and its signature. If verification fails, an sspi.error
will be raised.
"""
sigbuf = win32security.PySecBufferDescType()
sigbuf.append(win32security.PySecBufferType(len(data), sspicon.SECBUFFER_DATA))
sigbuf.append(win32security.PySecBufferType(len(sig), sspicon.SECBUFFER_TOKEN))
sigbuf[0].Buffer = data
sigbuf[1].Buffer = sig
self.ctxt.VerifySignature(sigbuf, self._get_next_seq_num())
def unwrap(self, token):
"""
GSSAPI's unwrap with SSPI.
https://learn.microsoft.com/en-us/windows/win32/secauthn/sspi-kerberos-interoperability-with-gssapi
Usable mainly with Kerberos SSPI package, but this is not enforced.
Return the clear text, and a boolean that is True if the token was encrypted.
"""
buffer = win32security.PySecBufferDescType()
# This buffer will contain a "stream", which is the token coming from the other side
buffer.append(
win32security.PySecBufferType(len(token), sspicon.SECBUFFER_STREAM)
)
buffer[0].Buffer = token
# This buffer will receive the clear, or just unwrapped text if no encryption was used.
# Will be resized by the lib.
buffer.append(win32security.PySecBufferType(0, sspicon.SECBUFFER_DATA))
pfQOP = self.ctxt.DecryptMessage(buffer, self._get_next_seq_num())
r = buffer[1].Buffer
return r, not (pfQOP == sspicon.SECQOP_WRAP_NO_ENCRYPT)
def wrap(self, msg, encrypt=False):
"""
GSSAPI's wrap with SSPI.
https://learn.microsoft.com/en-us/windows/win32/secauthn/sspi-kerberos-interoperability-with-gssapi
Usable mainly with Kerberos SSPI package, but this is not enforced.
Wrap a message to be sent to the other side. Encrypted if encrypt is True.
"""
size_info = self.ctxt.QueryContextAttributes(sspicon.SECPKG_ATTR_SIZES)
trailer_size = size_info["SecurityTrailer"]
block_size = size_info["BlockSize"]
buffer = win32security.PySecBufferDescType()
# This buffer will contain unencrypted data to wrap, and maybe encrypt.
buffer.append(win32security.PySecBufferType(len(msg), sspicon.SECBUFFER_DATA))
buffer[0].Buffer = msg
# Will receive the token that forms the beginning of the msg
buffer.append(
win32security.PySecBufferType(trailer_size, sspicon.SECBUFFER_TOKEN)
)
# The trailer is needed in case of block encryption
buffer.append(
win32security.PySecBufferType(block_size, sspicon.SECBUFFER_PADDING)
)
fQOP = 0 if encrypt else sspicon.SECQOP_WRAP_NO_ENCRYPT
self.ctxt.EncryptMessage(fQOP, buffer, self._get_next_seq_num())
# Sec token, then data, then padding
r = buffer[1].Buffer + buffer[0].Buffer + buffer[2].Buffer
return r
def _amend_ctx_name(self):
"""Adds initiator and service names in the security context for ease of use"""
if not self.authenticated:
raise ValueError("Sec context is not completely authenticated")
try:
names = self.ctxt.QueryContextAttributes(sspicon.SECPKG_ATTR_NATIVE_NAMES)
except error:
# The SSP doesn't provide these attributes.
pass
else:
self.initiator_name, self.service_name = names
class ClientAuth(_BaseAuth):
"""Manages the client side of an SSPI authentication handshake"""
def __init__(
self,
pkg_name, # Name of the package to used.
client_name=None, # User for whom credentials are used.
auth_info=None, # or a tuple of (username, domain, password)
targetspn=None, # Target security context provider name.
scflags=None, # security context flags
datarep=sspicon.SECURITY_NETWORK_DREP,
):
if scflags is None:
scflags = (
sspicon.ISC_REQ_INTEGRITY
| sspicon.ISC_REQ_SEQUENCE_DETECT
| sspicon.ISC_REQ_REPLAY_DETECT
| sspicon.ISC_REQ_CONFIDENTIALITY
)
self.scflags = scflags
self.datarep = datarep
self.targetspn = targetspn
self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name)
(
self.credentials,
self.credentials_expiry,
) = win32security.AcquireCredentialsHandle(
client_name,
self.pkg_info["Name"],
sspicon.SECPKG_CRED_OUTBOUND,
None,
auth_info,
)
_BaseAuth.__init__(self)
def authorize(self, sec_buffer_in):
"""Perform *one* step of the client authentication process. Pass None for the first round"""
if sec_buffer_in is not None and not isinstance(
sec_buffer_in, win32security.PySecBufferDescType
):
# User passed us the raw data - wrap it into a SecBufferDesc
sec_buffer_new = win32security.PySecBufferDescType()
tokenbuf = win32security.PySecBufferType(
self.pkg_info["MaxToken"], sspicon.SECBUFFER_TOKEN
)
tokenbuf.Buffer = sec_buffer_in
sec_buffer_new.append(tokenbuf)
sec_buffer_in = sec_buffer_new
sec_buffer_out = win32security.PySecBufferDescType()
tokenbuf = win32security.PySecBufferType(
self.pkg_info["MaxToken"], sspicon.SECBUFFER_TOKEN
)
sec_buffer_out.append(tokenbuf)
## input context handle should be NULL on first call
ctxtin = self.ctxt
if self.ctxt is None:
self.ctxt = win32security.PyCtxtHandleType()
err, attr, exp = win32security.InitializeSecurityContext(
self.credentials,
ctxtin,
self.targetspn,
self.scflags,
self.datarep,
sec_buffer_in,
self.ctxt,
sec_buffer_out,
)
# Stash these away incase someone needs to know the state from the
# final call.
self.ctxt_attr = attr
self.ctxt_expiry = exp
if err in (sspicon.SEC_I_COMPLETE_NEEDED, sspicon.SEC_I_COMPLETE_AND_CONTINUE):
self.ctxt.CompleteAuthToken(sec_buffer_out)
self.authenticated = err == 0
if self.authenticated:
self._amend_ctx_name()
return err, sec_buffer_out
class ServerAuth(_BaseAuth):
"""Manages the server side of an SSPI authentication handshake"""
def __init__(
self, pkg_name, spn=None, scflags=None, datarep=sspicon.SECURITY_NETWORK_DREP
):
self.spn = spn
self.datarep = datarep
if scflags is None:
scflags = (
sspicon.ASC_REQ_INTEGRITY
| sspicon.ASC_REQ_SEQUENCE_DETECT
| sspicon.ASC_REQ_REPLAY_DETECT
| sspicon.ASC_REQ_CONFIDENTIALITY
)
# Should we default to sspicon.KerbAddExtraCredentialsMessage
# if pkg_name=='Kerberos'?
self.scflags = scflags
self.pkg_info = win32security.QuerySecurityPackageInfo(pkg_name)
(
self.credentials,
self.credentials_expiry,
) = win32security.AcquireCredentialsHandle(
spn, self.pkg_info["Name"], sspicon.SECPKG_CRED_INBOUND, None, None
)
_BaseAuth.__init__(self)
def authorize(self, sec_buffer_in):
"""Perform *one* step of the server authentication process."""
if sec_buffer_in is not None and not isinstance(
sec_buffer_in, win32security.PySecBufferDescType
):
# User passed us the raw data - wrap it into a SecBufferDesc
sec_buffer_new = win32security.PySecBufferDescType()
tokenbuf = win32security.PySecBufferType(
self.pkg_info["MaxToken"], sspicon.SECBUFFER_TOKEN
)
tokenbuf.Buffer = sec_buffer_in
sec_buffer_new.append(tokenbuf)
sec_buffer_in = sec_buffer_new
sec_buffer_out = win32security.PySecBufferDescType()
tokenbuf = win32security.PySecBufferType(
self.pkg_info["MaxToken"], sspicon.SECBUFFER_TOKEN
)
sec_buffer_out.append(tokenbuf)
## input context handle is None initially, then handle returned from last call thereafter
ctxtin = self.ctxt
if self.ctxt is None:
self.ctxt = win32security.PyCtxtHandleType()
err, attr, exp = win32security.AcceptSecurityContext(
self.credentials,
ctxtin,
sec_buffer_in,
self.scflags,
self.datarep,
self.ctxt,
sec_buffer_out,
)
# Stash these away incase someone needs to know the state from the
# final call.
self.ctxt_attr = attr
self.ctxt_expiry = exp
if err in (sspicon.SEC_I_COMPLETE_NEEDED, sspicon.SEC_I_COMPLETE_AND_CONTINUE):
self.ctxt.CompleteAuthToken(sec_buffer_out)
self.authenticated = err == 0
if self.authenticated:
self._amend_ctx_name()
return err, sec_buffer_out
if __name__ == "__main__":
# This is the security package (the security support provider / the security backend)
# we want to use for this example.
ssp = "Kerberos" # or "NTLM" or "Negotiate" which enable negotiation between
# Kerberos (prefered) and NTLM (if not supported on the other side).
flags = (
sspicon.ISC_REQ_MUTUAL_AUTH
| sspicon.ISC_REQ_INTEGRITY # mutual authentication
| sspicon.ISC_REQ_SEQUENCE_DETECT # check for integrity
| sspicon.ISC_REQ_CONFIDENTIALITY # enable out-of-order messages
| sspicon.ISC_REQ_REPLAY_DETECT # request confidentiality # request replay detection
)
# Get our identity, mandatory for the Kerberos case *for this example*
# Kerberos cannot be used if we don't tell it the target we want
# to authenticate to.
cred_handle, exp = win32security.AcquireCredentialsHandle(
None, ssp, sspicon.SECPKG_CRED_INBOUND, None, None
)
cred = cred_handle.QueryCredentialsAttributes(sspicon.SECPKG_CRED_ATTR_NAMES)
print("We are:", cred)
# Setup the 2 contexts. In real life, only one is needed: the other one is
# created in the process we want to communicate with.
sspiclient = ClientAuth(ssp, scflags=flags, targetspn=cred)
sspiserver = ServerAuth(ssp, scflags=flags)
print(
"SSP : {} ({})".format(
sspiclient.pkg_info["Name"], sspiclient.pkg_info["Comment"]
)
)
# Perform the authentication dance, each loop exchanging more information
# on the way to completing authentication.
sec_buffer = None
client_step = 0
server_step = 0
while not sspiclient.authenticated or (sec_buffer and len(sec_buffer[0].Buffer)):
client_step += 1
err, sec_buffer = sspiclient.authorize(sec_buffer)
print("Client step %s" % client_step)
if sspiserver.authenticated and len(sec_buffer[0].Buffer) == 0:
break
server_step += 1
err, sec_buffer = sspiserver.authorize(sec_buffer)
print("Server step %s" % server_step)
# Authentication process is finished.
print("Initiator name from the service side:", sspiserver.initiator_name)
print("Service name from the client side: ", sspiclient.service_name)
data = b"hello"
# Simple signature, not compatible with GSSAPI.
sig = sspiclient.sign(data)
sspiserver.verify(data, sig)
# Encryption
encrypted, sig = sspiclient.encrypt(data)
decrypted = sspiserver.decrypt(encrypted, sig)
assert decrypted == data
# GSSAPI wrapping, no encryption (NTLM always encrypts)
wrapped = sspiclient.wrap(data)
unwrapped, was_encrypted = sspiserver.unwrap(wrapped)
print("encrypted ?", was_encrypted)
assert data == unwrapped
# GSSAPI wrapping, with encryption
wrapped = sspiserver.wrap(data, encrypt=True)
unwrapped, was_encrypted = sspiclient.unwrap(wrapped)
print("encrypted ?", was_encrypted)
assert data == unwrapped
print("cool!")

View File

@@ -0,0 +1,477 @@
# Generated by h2py from c:\microsoft sdk\include\sspi.h
ISSP_LEVEL = 32
ISSP_MODE = 1
def SEC_SUCCESS(Status):
return (Status) >= 0
SECPKG_FLAG_INTEGRITY = 1
SECPKG_FLAG_PRIVACY = 2
SECPKG_FLAG_TOKEN_ONLY = 4
SECPKG_FLAG_DATAGRAM = 8
SECPKG_FLAG_CONNECTION = 16
SECPKG_FLAG_MULTI_REQUIRED = 32
SECPKG_FLAG_CLIENT_ONLY = 64
SECPKG_FLAG_EXTENDED_ERROR = 128
SECPKG_FLAG_IMPERSONATION = 256
SECPKG_FLAG_ACCEPT_WIN32_NAME = 512
SECPKG_FLAG_STREAM = 1024
SECPKG_FLAG_NEGOTIABLE = 2048
SECPKG_FLAG_GSS_COMPATIBLE = 4096
SECPKG_FLAG_LOGON = 8192
SECPKG_FLAG_ASCII_BUFFERS = 16384
SECPKG_FLAG_FRAGMENT = 32768
SECPKG_FLAG_MUTUAL_AUTH = 65536
SECPKG_FLAG_DELEGATION = 131072
SECPKG_FLAG_READONLY_WITH_CHECKSUM = 262144
SECPKG_ID_NONE = 65535
SECBUFFER_VERSION = 0
SECBUFFER_EMPTY = 0
SECBUFFER_DATA = 1
SECBUFFER_TOKEN = 2
SECBUFFER_PKG_PARAMS = 3
SECBUFFER_MISSING = 4
SECBUFFER_EXTRA = 5
SECBUFFER_STREAM_TRAILER = 6
SECBUFFER_STREAM_HEADER = 7
SECBUFFER_NEGOTIATION_INFO = 8
SECBUFFER_PADDING = 9
SECBUFFER_STREAM = 10
SECBUFFER_MECHLIST = 11
SECBUFFER_MECHLIST_SIGNATURE = 12
SECBUFFER_TARGET = 13
SECBUFFER_CHANNEL_BINDINGS = 14
SECBUFFER_ATTRMASK = -268435456
SECBUFFER_READONLY = -2147483648
SECBUFFER_READONLY_WITH_CHECKSUM = 268435456
SECBUFFER_RESERVED = 1610612736
SECURITY_NATIVE_DREP = 16
SECURITY_NETWORK_DREP = 0
SECPKG_CRED_INBOUND = 1
SECPKG_CRED_OUTBOUND = 2
SECPKG_CRED_BOTH = 3
SECPKG_CRED_DEFAULT = 4
SECPKG_CRED_RESERVED = -268435456
ISC_REQ_DELEGATE = 1
ISC_REQ_MUTUAL_AUTH = 2
ISC_REQ_REPLAY_DETECT = 4
ISC_REQ_SEQUENCE_DETECT = 8
ISC_REQ_CONFIDENTIALITY = 16
ISC_REQ_USE_SESSION_KEY = 32
ISC_REQ_PROMPT_FOR_CREDS = 64
ISC_REQ_USE_SUPPLIED_CREDS = 128
ISC_REQ_ALLOCATE_MEMORY = 256
ISC_REQ_USE_DCE_STYLE = 512
ISC_REQ_DATAGRAM = 1024
ISC_REQ_CONNECTION = 2048
ISC_REQ_CALL_LEVEL = 4096
ISC_REQ_FRAGMENT_SUPPLIED = 8192
ISC_REQ_EXTENDED_ERROR = 16384
ISC_REQ_STREAM = 32768
ISC_REQ_INTEGRITY = 65536
ISC_REQ_IDENTIFY = 131072
ISC_REQ_NULL_SESSION = 262144
ISC_REQ_MANUAL_CRED_VALIDATION = 524288
ISC_REQ_RESERVED1 = 1048576
ISC_REQ_FRAGMENT_TO_FIT = 2097152
ISC_REQ_HTTP = 0x10000000
ISC_RET_DELEGATE = 1
ISC_RET_MUTUAL_AUTH = 2
ISC_RET_REPLAY_DETECT = 4
ISC_RET_SEQUENCE_DETECT = 8
ISC_RET_CONFIDENTIALITY = 16
ISC_RET_USE_SESSION_KEY = 32
ISC_RET_USED_COLLECTED_CREDS = 64
ISC_RET_USED_SUPPLIED_CREDS = 128
ISC_RET_ALLOCATED_MEMORY = 256
ISC_RET_USED_DCE_STYLE = 512
ISC_RET_DATAGRAM = 1024
ISC_RET_CONNECTION = 2048
ISC_RET_INTERMEDIATE_RETURN = 4096
ISC_RET_CALL_LEVEL = 8192
ISC_RET_EXTENDED_ERROR = 16384
ISC_RET_STREAM = 32768
ISC_RET_INTEGRITY = 65536
ISC_RET_IDENTIFY = 131072
ISC_RET_NULL_SESSION = 262144
ISC_RET_MANUAL_CRED_VALIDATION = 524288
ISC_RET_RESERVED1 = 1048576
ISC_RET_FRAGMENT_ONLY = 2097152
ASC_REQ_DELEGATE = 1
ASC_REQ_MUTUAL_AUTH = 2
ASC_REQ_REPLAY_DETECT = 4
ASC_REQ_SEQUENCE_DETECT = 8
ASC_REQ_CONFIDENTIALITY = 16
ASC_REQ_USE_SESSION_KEY = 32
ASC_REQ_ALLOCATE_MEMORY = 256
ASC_REQ_USE_DCE_STYLE = 512
ASC_REQ_DATAGRAM = 1024
ASC_REQ_CONNECTION = 2048
ASC_REQ_CALL_LEVEL = 4096
ASC_REQ_EXTENDED_ERROR = 32768
ASC_REQ_STREAM = 65536
ASC_REQ_INTEGRITY = 131072
ASC_REQ_LICENSING = 262144
ASC_REQ_IDENTIFY = 524288
ASC_REQ_ALLOW_NULL_SESSION = 1048576
ASC_REQ_ALLOW_NON_USER_LOGONS = 2097152
ASC_REQ_ALLOW_CONTEXT_REPLAY = 4194304
ASC_REQ_FRAGMENT_TO_FIT = 8388608
ASC_REQ_FRAGMENT_SUPPLIED = 8192
ASC_REQ_NO_TOKEN = 16777216
ASC_RET_DELEGATE = 1
ASC_RET_MUTUAL_AUTH = 2
ASC_RET_REPLAY_DETECT = 4
ASC_RET_SEQUENCE_DETECT = 8
ASC_RET_CONFIDENTIALITY = 16
ASC_RET_USE_SESSION_KEY = 32
ASC_RET_ALLOCATED_MEMORY = 256
ASC_RET_USED_DCE_STYLE = 512
ASC_RET_DATAGRAM = 1024
ASC_RET_CONNECTION = 2048
ASC_RET_CALL_LEVEL = 8192
ASC_RET_THIRD_LEG_FAILED = 16384
ASC_RET_EXTENDED_ERROR = 32768
ASC_RET_STREAM = 65536
ASC_RET_INTEGRITY = 131072
ASC_RET_LICENSING = 262144
ASC_RET_IDENTIFY = 524288
ASC_RET_NULL_SESSION = 1048576
ASC_RET_ALLOW_NON_USER_LOGONS = 2097152
ASC_RET_ALLOW_CONTEXT_REPLAY = 4194304
ASC_RET_FRAGMENT_ONLY = 8388608
SECPKG_CRED_ATTR_NAMES = 1
SECPKG_ATTR_SIZES = 0
SECPKG_ATTR_NAMES = 1
SECPKG_ATTR_LIFESPAN = 2
SECPKG_ATTR_DCE_INFO = 3
SECPKG_ATTR_STREAM_SIZES = 4
SECPKG_ATTR_KEY_INFO = 5
SECPKG_ATTR_AUTHORITY = 6
SECPKG_ATTR_PROTO_INFO = 7
SECPKG_ATTR_PASSWORD_EXPIRY = 8
SECPKG_ATTR_SESSION_KEY = 9
SECPKG_ATTR_PACKAGE_INFO = 10
SECPKG_ATTR_USER_FLAGS = 11
SECPKG_ATTR_NEGOTIATION_INFO = 12
SECPKG_ATTR_NATIVE_NAMES = 13
SECPKG_ATTR_FLAGS = 14
SECPKG_ATTR_USE_VALIDATED = 15
SECPKG_ATTR_CREDENTIAL_NAME = 16
SECPKG_ATTR_TARGET_INFORMATION = 17
SECPKG_ATTR_ACCESS_TOKEN = 18
SECPKG_ATTR_TARGET = 19
SECPKG_ATTR_AUTHENTICATION_ID = 20
## attributes from schannel.h
SECPKG_ATTR_REMOTE_CERT_CONTEXT = 83
SECPKG_ATTR_LOCAL_CERT_CONTEXT = 84
SECPKG_ATTR_ROOT_STORE = 85
SECPKG_ATTR_SUPPORTED_ALGS = 86
SECPKG_ATTR_CIPHER_STRENGTHS = 87
SECPKG_ATTR_SUPPORTED_PROTOCOLS = 88
SECPKG_ATTR_ISSUER_LIST_EX = 89
SECPKG_ATTR_CONNECTION_INFO = 90
SECPKG_ATTR_EAP_KEY_BLOCK = 91
SECPKG_ATTR_MAPPED_CRED_ATTR = 92
SECPKG_ATTR_SESSION_INFO = 93
SECPKG_ATTR_APP_DATA = 94
SECPKG_NEGOTIATION_COMPLETE = 0
SECPKG_NEGOTIATION_OPTIMISTIC = 1
SECPKG_NEGOTIATION_IN_PROGRESS = 2
SECPKG_NEGOTIATION_DIRECT = 3
SECPKG_NEGOTIATION_TRY_MULTICRED = 4
SECPKG_CONTEXT_EXPORT_RESET_NEW = 1
SECPKG_CONTEXT_EXPORT_DELETE_OLD = 2
SECQOP_WRAP_NO_ENCRYPT = -2147483647
SECURITY_ENTRYPOINT_ANSIW = "InitSecurityInterfaceW"
SECURITY_ENTRYPOINT_ANSIA = "InitSecurityInterfaceA"
SECURITY_ENTRYPOINT16 = "INITSECURITYINTERFACEA"
SECURITY_ENTRYPOINT = SECURITY_ENTRYPOINT16
SECURITY_ENTRYPOINT_ANSI = SECURITY_ENTRYPOINT16
SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION = 1
SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION_2 = 2
SASL_OPTION_SEND_SIZE = 1
SASL_OPTION_RECV_SIZE = 2
SASL_OPTION_AUTHZ_STRING = 3
SASL_OPTION_AUTHZ_PROCESSING = 4
SEC_WINNT_AUTH_IDENTITY_ANSI = 1
SEC_WINNT_AUTH_IDENTITY_UNICODE = 2
SEC_WINNT_AUTH_IDENTITY_VERSION = 512
SEC_WINNT_AUTH_IDENTITY_MARSHALLED = 4
SEC_WINNT_AUTH_IDENTITY_ONLY = 8
SECPKG_OPTIONS_TYPE_UNKNOWN = 0
SECPKG_OPTIONS_TYPE_LSA = 1
SECPKG_OPTIONS_TYPE_SSPI = 2
SECPKG_OPTIONS_PERMANENT = 1
SEC_E_INSUFFICIENT_MEMORY = -2146893056
SEC_E_INVALID_HANDLE = -2146893055
SEC_E_UNSUPPORTED_FUNCTION = -2146893054
SEC_E_TARGET_UNKNOWN = -2146893053
SEC_E_INTERNAL_ERROR = -2146893052
SEC_E_SECPKG_NOT_FOUND = -2146893051
SEC_E_NOT_OWNER = -2146893050
SEC_E_CANNOT_INSTALL = -2146893049
SEC_E_INVALID_TOKEN = -2146893048
SEC_E_CANNOT_PACK = -2146893047
SEC_E_QOP_NOT_SUPPORTED = -2146893046
SEC_E_NO_IMPERSONATION = -2146893045
SEC_E_LOGON_DENIED = -2146893044
SEC_E_UNKNOWN_CREDENTIALS = -2146893043
SEC_E_NO_CREDENTIALS = -2146893042
SEC_E_MESSAGE_ALTERED = -2146893041
SEC_E_OUT_OF_SEQUENCE = -2146893040
SEC_E_NO_AUTHENTICATING_AUTHORITY = -2146893039
SEC_I_CONTINUE_NEEDED = 590610
SEC_I_COMPLETE_NEEDED = 590611
SEC_I_COMPLETE_AND_CONTINUE = 590612
SEC_I_LOCAL_LOGON = 590613
SEC_E_BAD_PKGID = -2146893034
SEC_E_CONTEXT_EXPIRED = -2146893033
SEC_I_CONTEXT_EXPIRED = 590615
SEC_E_INCOMPLETE_MESSAGE = -2146893032
SEC_E_INCOMPLETE_CREDENTIALS = -2146893024
SEC_E_BUFFER_TOO_SMALL = -2146893023
SEC_I_INCOMPLETE_CREDENTIALS = 590624
SEC_I_RENEGOTIATE = 590625
SEC_E_WRONG_PRINCIPAL = -2146893022
SEC_I_NO_LSA_CONTEXT = 590627
SEC_E_TIME_SKEW = -2146893020
SEC_E_UNTRUSTED_ROOT = -2146893019
SEC_E_ILLEGAL_MESSAGE = -2146893018
SEC_E_CERT_UNKNOWN = -2146893017
SEC_E_CERT_EXPIRED = -2146893016
SEC_E_ENCRYPT_FAILURE = -2146893015
SEC_E_DECRYPT_FAILURE = -2146893008
SEC_E_ALGORITHM_MISMATCH = -2146893007
SEC_E_SECURITY_QOS_FAILED = -2146893006
SEC_E_UNFINISHED_CONTEXT_DELETED = -2146893005
SEC_E_NO_TGT_REPLY = -2146893004
SEC_E_NO_IP_ADDRESSES = -2146893003
SEC_E_WRONG_CREDENTIAL_HANDLE = -2146893002
SEC_E_CRYPTO_SYSTEM_INVALID = -2146893001
SEC_E_MAX_REFERRALS_EXCEEDED = -2146893000
SEC_E_MUST_BE_KDC = -2146892999
SEC_E_STRONG_CRYPTO_NOT_SUPPORTED = -2146892998
SEC_E_TOO_MANY_PRINCIPALS = -2146892997
SEC_E_NO_PA_DATA = -2146892996
SEC_E_PKINIT_NAME_MISMATCH = -2146892995
SEC_E_SMARTCARD_LOGON_REQUIRED = -2146892994
SEC_E_SHUTDOWN_IN_PROGRESS = -2146892993
SEC_E_KDC_INVALID_REQUEST = -2146892992
SEC_E_KDC_UNABLE_TO_REFER = -2146892991
SEC_E_KDC_UNKNOWN_ETYPE = -2146892990
SEC_E_UNSUPPORTED_PREAUTH = -2146892989
SEC_E_DELEGATION_REQUIRED = -2146892987
SEC_E_BAD_BINDINGS = -2146892986
SEC_E_MULTIPLE_ACCOUNTS = -2146892985
SEC_E_NO_KERB_KEY = -2146892984
ERROR_IPSEC_QM_POLICY_EXISTS = 13000
ERROR_IPSEC_QM_POLICY_NOT_FOUND = 13001
ERROR_IPSEC_QM_POLICY_IN_USE = 13002
ERROR_IPSEC_MM_POLICY_EXISTS = 13003
ERROR_IPSEC_MM_POLICY_NOT_FOUND = 13004
ERROR_IPSEC_MM_POLICY_IN_USE = 13005
ERROR_IPSEC_MM_FILTER_EXISTS = 13006
ERROR_IPSEC_MM_FILTER_NOT_FOUND = 13007
ERROR_IPSEC_TRANSPORT_FILTER_EXISTS = 13008
ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND = 13009
ERROR_IPSEC_MM_AUTH_EXISTS = 13010
ERROR_IPSEC_MM_AUTH_NOT_FOUND = 13011
ERROR_IPSEC_MM_AUTH_IN_USE = 13012
ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND = 13013
ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND = 13014
ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND = 13015
ERROR_IPSEC_TUNNEL_FILTER_EXISTS = 13016
ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND = 13017
ERROR_IPSEC_MM_FILTER_PENDING_DELETION = 13018
ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION = 13019
ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION = 13020
ERROR_IPSEC_MM_POLICY_PENDING_DELETION = 13021
ERROR_IPSEC_MM_AUTH_PENDING_DELETION = 13022
ERROR_IPSEC_QM_POLICY_PENDING_DELETION = 13023
WARNING_IPSEC_MM_POLICY_PRUNED = 13024
WARNING_IPSEC_QM_POLICY_PRUNED = 13025
ERROR_IPSEC_IKE_NEG_STATUS_BEGIN = 13800
ERROR_IPSEC_IKE_AUTH_FAIL = 13801
ERROR_IPSEC_IKE_ATTRIB_FAIL = 13802
ERROR_IPSEC_IKE_NEGOTIATION_PENDING = 13803
ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR = 13804
ERROR_IPSEC_IKE_TIMED_OUT = 13805
ERROR_IPSEC_IKE_NO_CERT = 13806
ERROR_IPSEC_IKE_SA_DELETED = 13807
ERROR_IPSEC_IKE_SA_REAPED = 13808
ERROR_IPSEC_IKE_MM_ACQUIRE_DROP = 13809
ERROR_IPSEC_IKE_QM_ACQUIRE_DROP = 13810
ERROR_IPSEC_IKE_QUEUE_DROP_MM = 13811
ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM = 13812
ERROR_IPSEC_IKE_DROP_NO_RESPONSE = 13813
ERROR_IPSEC_IKE_MM_DELAY_DROP = 13814
ERROR_IPSEC_IKE_QM_DELAY_DROP = 13815
ERROR_IPSEC_IKE_ERROR = 13816
ERROR_IPSEC_IKE_CRL_FAILED = 13817
ERROR_IPSEC_IKE_INVALID_KEY_USAGE = 13818
ERROR_IPSEC_IKE_INVALID_CERT_TYPE = 13819
ERROR_IPSEC_IKE_NO_PRIVATE_KEY = 13820
ERROR_IPSEC_IKE_DH_FAIL = 13822
ERROR_IPSEC_IKE_INVALID_HEADER = 13824
ERROR_IPSEC_IKE_NO_POLICY = 13825
ERROR_IPSEC_IKE_INVALID_SIGNATURE = 13826
ERROR_IPSEC_IKE_KERBEROS_ERROR = 13827
ERROR_IPSEC_IKE_NO_PUBLIC_KEY = 13828
ERROR_IPSEC_IKE_PROCESS_ERR = 13829
ERROR_IPSEC_IKE_PROCESS_ERR_SA = 13830
ERROR_IPSEC_IKE_PROCESS_ERR_PROP = 13831
ERROR_IPSEC_IKE_PROCESS_ERR_TRANS = 13832
ERROR_IPSEC_IKE_PROCESS_ERR_KE = 13833
ERROR_IPSEC_IKE_PROCESS_ERR_ID = 13834
ERROR_IPSEC_IKE_PROCESS_ERR_CERT = 13835
ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ = 13836
ERROR_IPSEC_IKE_PROCESS_ERR_HASH = 13837
ERROR_IPSEC_IKE_PROCESS_ERR_SIG = 13838
ERROR_IPSEC_IKE_PROCESS_ERR_NONCE = 13839
ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY = 13840
ERROR_IPSEC_IKE_PROCESS_ERR_DELETE = 13841
ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR = 13842
ERROR_IPSEC_IKE_INVALID_PAYLOAD = 13843
ERROR_IPSEC_IKE_LOAD_SOFT_SA = 13844
ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN = 13845
ERROR_IPSEC_IKE_INVALID_COOKIE = 13846
ERROR_IPSEC_IKE_NO_PEER_CERT = 13847
ERROR_IPSEC_IKE_PEER_CRL_FAILED = 13848
ERROR_IPSEC_IKE_POLICY_CHANGE = 13849
ERROR_IPSEC_IKE_NO_MM_POLICY = 13850
ERROR_IPSEC_IKE_NOTCBPRIV = 13851
ERROR_IPSEC_IKE_SECLOADFAIL = 13852
ERROR_IPSEC_IKE_FAILSSPINIT = 13853
ERROR_IPSEC_IKE_FAILQUERYSSP = 13854
ERROR_IPSEC_IKE_SRVACQFAIL = 13855
ERROR_IPSEC_IKE_SRVQUERYCRED = 13856
ERROR_IPSEC_IKE_GETSPIFAIL = 13857
ERROR_IPSEC_IKE_INVALID_FILTER = 13858
ERROR_IPSEC_IKE_OUT_OF_MEMORY = 13859
ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED = 13860
ERROR_IPSEC_IKE_INVALID_POLICY = 13861
ERROR_IPSEC_IKE_UNKNOWN_DOI = 13862
ERROR_IPSEC_IKE_INVALID_SITUATION = 13863
ERROR_IPSEC_IKE_DH_FAILURE = 13864
ERROR_IPSEC_IKE_INVALID_GROUP = 13865
ERROR_IPSEC_IKE_ENCRYPT = 13866
ERROR_IPSEC_IKE_DECRYPT = 13867
ERROR_IPSEC_IKE_POLICY_MATCH = 13868
ERROR_IPSEC_IKE_UNSUPPORTED_ID = 13869
ERROR_IPSEC_IKE_INVALID_HASH = 13870
ERROR_IPSEC_IKE_INVALID_HASH_ALG = 13871
ERROR_IPSEC_IKE_INVALID_HASH_SIZE = 13872
ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG = 13873
ERROR_IPSEC_IKE_INVALID_AUTH_ALG = 13874
ERROR_IPSEC_IKE_INVALID_SIG = 13875
ERROR_IPSEC_IKE_LOAD_FAILED = 13876
ERROR_IPSEC_IKE_RPC_DELETE = 13877
ERROR_IPSEC_IKE_BENIGN_REINIT = 13878
ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY = 13879
ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN = 13881
ERROR_IPSEC_IKE_MM_LIMIT = 13882
ERROR_IPSEC_IKE_NEGOTIATION_DISABLED = 13883
ERROR_IPSEC_IKE_NEG_STATUS_END = 13884
CRYPT_E_MSG_ERROR = -2146889727
CRYPT_E_UNKNOWN_ALGO = -2146889726
CRYPT_E_OID_FORMAT = -2146889725
CRYPT_E_INVALID_MSG_TYPE = -2146889724
CRYPT_E_UNEXPECTED_ENCODING = -2146889723
CRYPT_E_AUTH_ATTR_MISSING = -2146889722
CRYPT_E_HASH_VALUE = -2146889721
CRYPT_E_INVALID_INDEX = -2146889720
CRYPT_E_ALREADY_DECRYPTED = -2146889719
CRYPT_E_NOT_DECRYPTED = -2146889718
CRYPT_E_RECIPIENT_NOT_FOUND = -2146889717
CRYPT_E_CONTROL_TYPE = -2146889716
CRYPT_E_ISSUER_SERIALNUMBER = -2146889715
CRYPT_E_SIGNER_NOT_FOUND = -2146889714
CRYPT_E_ATTRIBUTES_MISSING = -2146889713
CRYPT_E_STREAM_MSG_NOT_READY = -2146889712
CRYPT_E_STREAM_INSUFFICIENT_DATA = -2146889711
CRYPT_I_NEW_PROTECTION_REQUIRED = 593938
CRYPT_E_BAD_LEN = -2146885631
CRYPT_E_BAD_ENCODE = -2146885630
CRYPT_E_FILE_ERROR = -2146885629
CRYPT_E_NOT_FOUND = -2146885628
CRYPT_E_EXISTS = -2146885627
CRYPT_E_NO_PROVIDER = -2146885626
CRYPT_E_SELF_SIGNED = -2146885625
CRYPT_E_DELETED_PREV = -2146885624
CRYPT_E_NO_MATCH = -2146885623
CRYPT_E_UNEXPECTED_MSG_TYPE = -2146885622
CRYPT_E_NO_KEY_PROPERTY = -2146885621
CRYPT_E_NO_DECRYPT_CERT = -2146885620
CRYPT_E_BAD_MSG = -2146885619
CRYPT_E_NO_SIGNER = -2146885618
CRYPT_E_PENDING_CLOSE = -2146885617
CRYPT_E_REVOKED = -2146885616
CRYPT_E_NO_REVOCATION_DLL = -2146885615
CRYPT_E_NO_REVOCATION_CHECK = -2146885614
CRYPT_E_REVOCATION_OFFLINE = -2146885613
CRYPT_E_NOT_IN_REVOCATION_DATABASE = -2146885612
CRYPT_E_INVALID_NUMERIC_STRING = -2146885600
CRYPT_E_INVALID_PRINTABLE_STRING = -2146885599
CRYPT_E_INVALID_IA5_STRING = -2146885598
CRYPT_E_INVALID_X500_STRING = -2146885597
CRYPT_E_NOT_CHAR_STRING = -2146885596
CRYPT_E_FILERESIZED = -2146885595
CRYPT_E_SECURITY_SETTINGS = -2146885594
CRYPT_E_NO_VERIFY_USAGE_DLL = -2146885593
CRYPT_E_NO_VERIFY_USAGE_CHECK = -2146885592
CRYPT_E_VERIFY_USAGE_OFFLINE = -2146885591
CRYPT_E_NOT_IN_CTL = -2146885590
CRYPT_E_NO_TRUSTED_SIGNER = -2146885589
CRYPT_E_MISSING_PUBKEY_PARA = -2146885588
CRYPT_E_OSS_ERROR = -2146881536
## Kerberos message types for LsaCallAuthenticationPackage (from ntsecapi.h)
KerbDebugRequestMessage = 0
KerbQueryTicketCacheMessage = 1
KerbChangeMachinePasswordMessage = 2
KerbVerifyPacMessage = 3
KerbRetrieveTicketMessage = 4
KerbUpdateAddressesMessage = 5
KerbPurgeTicketCacheMessage = 6
KerbChangePasswordMessage = 7
KerbRetrieveEncodedTicketMessage = 8
KerbDecryptDataMessage = 9
KerbAddBindingCacheEntryMessage = 10
KerbSetPasswordMessage = 11
KerbSetPasswordExMessage = 12
KerbVerifyCredentialsMessage = 13
KerbQueryTicketCacheExMessage = 14
KerbPurgeTicketCacheExMessage = 15
KerbRefreshSmartcardCredentialsMessage = 16
KerbAddExtraCredentialsMessage = 17
KerbQuerySupplementalCredentialsMessage = 18
## messages used with msv1_0 from ntsecapi.h
MsV1_0Lm20ChallengeRequest = 0
MsV1_0Lm20GetChallengeResponse = 1
MsV1_0EnumerateUsers = 2
MsV1_0GetUserInfo = 3
MsV1_0ReLogonUsers = 4
MsV1_0ChangePassword = 5
MsV1_0ChangeCachedPassword = 6
MsV1_0GenericPassthrough = 7
MsV1_0CacheLogon = 8
MsV1_0SubAuth = 9
MsV1_0DeriveCredential = 10
MsV1_0CacheLookup = 11
MsV1_0SetProcessOption = 12
SEC_E_OK = 0

View File

@@ -0,0 +1,14 @@
"""\
win2kras used to be an extension module with wrapped the "new" RAS functions \
in Windows 2000, so win32ras could still be used on NT/etc.
I think in 2021 we can be confident pywin32 is not used on earlier OSs, so \
that functionality is now in win32ras.
This exists just to avoid breaking old scripts.\
"""
import warnings
from win32ras import * # nopycln: import
warnings.warn(str(__doc__), category=DeprecationWarning)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,225 @@
"""Event Log Utilities - helper for win32evtlog.pyd"""
import win32api
import win32con
import win32evtlog
import winerror
error = win32api.error # Re-exported alias (The error the evtlog module raises).
langid = win32api.MAKELANGID(win32con.LANG_NEUTRAL, win32con.SUBLANG_NEUTRAL)
def AddSourceToRegistry(
appName,
msgDLL=None,
eventLogType="Application",
eventLogFlags=None,
categoryDLL=None,
categoryCount=0,
):
"""Add a source of messages to the event log.
Allows Python program to register a custom source of messages in the
registry. You must also provide the DLL name that has the message table, so the
full message text appears in the event log.
Note that the win32evtlog.pyd file has a number of string entries with just "%1"
built in, so many Python programs can simply use this DLL. Disadvantages are that
you do not get language translation, and the full text is stored in the event log,
blowing the size of the log up.
"""
# When an application uses the RegisterEventSource or OpenEventLog
# function to get a handle of an event log, the event logging service
# searches for the specified source name in the registry. You can add a
# new source name to the registry by opening a new registry subkey
# under the Application key and adding registry values to the new
# subkey.
if msgDLL is None:
msgDLL = win32evtlog.__file__
# Create a new key for our application
hkey = win32api.RegCreateKey(
win32con.HKEY_LOCAL_MACHINE,
f"SYSTEM\\CurrentControlSet\\Services\\EventLog\\{eventLogType}\\{appName}",
)
# Add the Event-ID message-file name to the subkey.
win32api.RegSetValueEx(
hkey,
"EventMessageFile", # value name \
0, # reserved \
win32con.REG_EXPAND_SZ, # value type \
msgDLL,
)
# Set the supported types flags and add it to the subkey.
if eventLogFlags is None:
eventLogFlags = (
win32evtlog.EVENTLOG_ERROR_TYPE
| win32evtlog.EVENTLOG_WARNING_TYPE
| win32evtlog.EVENTLOG_INFORMATION_TYPE
)
win32api.RegSetValueEx(
hkey, # subkey handle \
"TypesSupported", # value name \
0, # reserved \
win32con.REG_DWORD, # value type \
eventLogFlags,
)
if categoryCount > 0:
# Optionally, you can specify a message file that contains the categories
if categoryDLL is None:
categoryDLL = win32evtlog.__file__
win32api.RegSetValueEx(
hkey, # subkey handle \
"CategoryMessageFile", # value name \
0, # reserved \
win32con.REG_EXPAND_SZ, # value type \
categoryDLL,
)
win32api.RegSetValueEx(
hkey, # subkey handle \
"CategoryCount", # value name \
0, # reserved \
win32con.REG_DWORD, # value type \
categoryCount,
)
win32api.RegCloseKey(hkey)
def RemoveSourceFromRegistry(appName, eventLogType="Application"):
"""Removes a source of messages from the event log."""
# Delete our key
try:
win32api.RegDeleteKey(
win32con.HKEY_LOCAL_MACHINE,
f"SYSTEM\\CurrentControlSet\\Services\\EventLog\\{eventLogType}\\{appName}",
)
except win32api.error as exc:
if exc.winerror != winerror.ERROR_FILE_NOT_FOUND:
raise
def ReportEvent(
appName,
eventID,
eventCategory=0,
eventType=win32evtlog.EVENTLOG_ERROR_TYPE,
strings=None,
data=None,
sid=None,
):
"""Report an event for a previously added event source."""
# Get a handle to the Application event log
hAppLog = win32evtlog.RegisterEventSource(None, appName)
# Now report the event, which will add this event to the event log */
win32evtlog.ReportEvent(
hAppLog, # event-log handle \
eventType,
eventCategory,
eventID,
sid,
strings,
data,
)
win32evtlog.DeregisterEventSource(hAppLog)
def FormatMessage(eventLogRecord, logType="Application"):
"""Given a tuple from ReadEventLog, and optionally where the event
record came from, load the message, and process message inserts.
Note that this function may raise win32api.error. See also the
function SafeFormatMessage which will return None if the message can
not be processed.
"""
# From the event log source name, we know the name of the registry
# key to look under for the name of the message DLL that contains
# the messages we need to extract with FormatMessage. So first get
# the event log source name...
keyName = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\{}\\{}".format(
logType,
eventLogRecord.SourceName,
)
# Now open this key and get the EventMessageFile value, which is
# the name of the message DLL.
handle = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, keyName)
try:
dllNames = win32api.RegQueryValueEx(handle, "EventMessageFile")[0].split(";")
# Win2k etc appear to allow multiple DLL names
data = None
for dllName in dllNames:
try:
# Expand environment variable strings in the message DLL path name,
# in case any are there.
dllName = win32api.ExpandEnvironmentStrings(dllName)
dllHandle = win32api.LoadLibraryEx(
dllName, 0, win32con.LOAD_LIBRARY_AS_DATAFILE
)
try:
data = win32api.FormatMessageW(
win32con.FORMAT_MESSAGE_FROM_HMODULE,
dllHandle,
eventLogRecord.EventID,
langid,
eventLogRecord.StringInserts,
)
finally:
win32api.FreeLibrary(dllHandle)
except win32api.error:
pass # Not in this DLL - try the next
if data is not None:
break
finally:
win32api.RegCloseKey(handle)
return data or "" # Don't want "None" ever being returned.
def SafeFormatMessage(eventLogRecord, logType=None):
"""As for FormatMessage, except returns an error message if
the message can not be processed.
"""
if logType is None:
logType = "Application"
try:
return FormatMessage(eventLogRecord, logType)
except win32api.error:
if eventLogRecord.StringInserts is None:
desc = ""
else:
desc = ", ".join(eventLogRecord.StringInserts)
return (
"<The description for Event ID ( %d ) in Source ( %r ) could not be found. It contains the following insertion string(s):%r.>"
% (
winerror.HRESULT_CODE(eventLogRecord.EventID),
eventLogRecord.SourceName,
desc,
)
)
def FeedEventLogRecords(
feeder, machineName=None, logName="Application", readFlags=None
):
if readFlags is None:
readFlags = (
win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ
)
h = win32evtlog.OpenEventLog(machineName, logName)
try:
while 1:
objects = win32evtlog.ReadEventLog(h, readFlags, 0)
if not objects:
break
map(lambda item, feeder=feeder: feeder(*(item,)), objects)
finally:
win32evtlog.CloseEventLog(h)

View File

@@ -0,0 +1,957 @@
# This is a work in progress - see Demos/win32gui_menu.py
# win32gui_struct.py - helpers for working with various win32gui structures.
# As win32gui is "light-weight", it does not define objects for all possible
# win32 structures - in general, "buffer" objects are passed around - it is
# the callers responsibility to pack the buffer in the correct format.
#
# This module defines some helpers for the commonly used structures.
#
# In general, each structure has 3 functions:
#
# buffer, extras = PackSTRUCTURE(items, ...)
# item, ... = UnpackSTRUCTURE(buffer)
# buffer, extras = EmtpySTRUCTURE(...)
#
# 'extras' is always items that must be held along with the buffer, as the
# buffer refers to these object's memory.
# For structures that support a 'mask', this mask is hidden from the user - if
# 'None' is passed, the mask flag will not be set, or on return, None will
# be returned for the value if the mask is not set.
#
# NOTE: I considered making these structures look like real classes, and
# support 'attributes' etc - however, ctypes already has a good structure
# mechanism - I think it makes more sense to support ctype structures
# at the win32gui level, then there will be no need for this module at all.
# XXX - the above makes sense in terms of what is built and passed to
# win32gui (ie, the Pack* functions) - but doesn't make as much sense for
# the Unpack* functions, where the aim is user convenience.
import array
import struct
import sys
from collections import namedtuple
import commctrl
import pywintypes
import win32con
import win32gui
def _MakeResult(names_str, values):
names = names_str.split()
# TODO: Dynamic namedtuple. This could be made static, also exposing the types
nt = namedtuple(names[0], names[1:]) # noqa: PYI024
return nt(*values)
is64bit = "64 bit" in sys.version
_nmhdr_fmt = "PPi"
if is64bit:
# When the item past the NMHDR gets aligned (eg, when it is a struct)
# we need this many bytes padding.
_nmhdr_align_padding = "xxxx"
else:
_nmhdr_align_padding = ""
# Encode a string suitable for passing in a win32gui related structure
def _make_text_buffer(text):
if not isinstance(text, str):
raise TypeError("MENUITEMINFO text must be unicode")
data = (text + "\0").encode("utf-16le")
return array.array("b", data)
# make an 'empty' buffer, ready for filling with cch characters.
def _make_empty_text_buffer(cch):
return _make_text_buffer("\0" * cch)
# Generic WM_NOTIFY unpacking
def UnpackWMNOTIFY(lparam):
format = "PPi"
buf = win32gui.PyGetMemory(lparam, struct.calcsize(format))
return _MakeResult("WMNOTIFY hwndFrom idFrom code", struct.unpack(format, buf))
def UnpackNMITEMACTIVATE(lparam):
format = _nmhdr_fmt + _nmhdr_align_padding
if is64bit:
# the struct module doesn't handle this correctly as some of the items
# are actually structs in structs, which get individually aligned.
format += "iiiiiiixxxxP"
else:
format += "iiiiiiiP"
buf = win32gui.PyMakeBuffer(struct.calcsize(format), lparam)
return _MakeResult(
"NMITEMACTIVATE hwndFrom idFrom code iItem iSubItem uNewState uOldState uChanged actionx actiony lParam",
struct.unpack(format, buf),
)
# MENUITEMINFO struct
# https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-menuiteminfow
# We use the struct module to pack and unpack strings as MENUITEMINFO
# structures. We also have special handling for the 'fMask' item in that
# structure to avoid the caller needing to explicitly check validity
# (None is used if the mask excludes/should exclude the value)
_menuiteminfo_fmt = "5i5PiP"
def PackMENUITEMINFO(
fType=None,
fState=None,
wID=None,
hSubMenu=None,
hbmpChecked=None,
hbmpUnchecked=None,
dwItemData=None,
text=None,
hbmpItem=None,
dwTypeData=None,
):
# 'extras' are objects the caller must keep a reference to (as their
# memory is used) for the lifetime of the INFO item.
extras = []
# ack - dwItemData and dwTypeData were confused for a while...
assert (
dwItemData is None or dwTypeData is None
), "sorry - these were confused - you probably want dwItemData"
# if we are a long way past 209, then we can nuke the above...
if dwTypeData is not None:
import warnings
warnings.warn("PackMENUITEMINFO: please use dwItemData instead of dwTypeData")
if dwItemData is None:
dwItemData = dwTypeData or 0
fMask = 0
if fType is None:
fType = 0
else:
fMask |= win32con.MIIM_FTYPE
if fState is None:
fState = 0
else:
fMask |= win32con.MIIM_STATE
if wID is None:
wID = 0
else:
fMask |= win32con.MIIM_ID
if hSubMenu is None:
hSubMenu = 0
else:
fMask |= win32con.MIIM_SUBMENU
if hbmpChecked is None:
assert hbmpUnchecked is None, "neither or both checkmark bmps must be given"
hbmpChecked = hbmpUnchecked = 0
else:
assert hbmpUnchecked is not None, "neither or both checkmark bmps must be given"
fMask |= win32con.MIIM_CHECKMARKS
if dwItemData is None:
dwItemData = 0
else:
fMask |= win32con.MIIM_DATA
if hbmpItem is None:
hbmpItem = 0
else:
fMask |= win32con.MIIM_BITMAP
if text is not None:
fMask |= win32con.MIIM_STRING
str_buf = _make_text_buffer(text)
cch = len(text)
# We are taking address of strbuf - it must not die until windows
# has finished with our structure.
lptext = str_buf.buffer_info()[0]
extras.append(str_buf)
else:
lptext = 0
cch = 0
# Create the struct.
# 'P' format does not accept PyHANDLE's !
item = struct.pack(
_menuiteminfo_fmt,
struct.calcsize(_menuiteminfo_fmt), # cbSize
fMask,
fType,
fState,
wID,
int(hSubMenu),
int(hbmpChecked),
int(hbmpUnchecked),
dwItemData,
lptext,
cch,
int(hbmpItem),
)
# Now copy the string to a writable buffer, so that the result
# could be passed to a 'Get' function
return array.array("b", item), extras
def UnpackMENUITEMINFO(s):
(
cb,
fMask,
fType,
fState,
wID,
hSubMenu,
hbmpChecked,
hbmpUnchecked,
dwItemData,
lptext,
cch,
hbmpItem,
) = struct.unpack(_menuiteminfo_fmt, s)
assert cb == len(s)
if fMask & win32con.MIIM_FTYPE == 0:
fType = None
if fMask & win32con.MIIM_STATE == 0:
fState = None
if fMask & win32con.MIIM_ID == 0:
wID = None
if fMask & win32con.MIIM_SUBMENU == 0:
hSubMenu = None
if fMask & win32con.MIIM_CHECKMARKS == 0:
hbmpChecked = hbmpUnchecked = None
if fMask & win32con.MIIM_DATA == 0:
dwItemData = None
if fMask & win32con.MIIM_BITMAP == 0:
hbmpItem = None
if fMask & win32con.MIIM_STRING:
text = win32gui.PyGetString(lptext, cch)
else:
text = None
return _MakeResult(
"MENUITEMINFO fType fState wID hSubMenu hbmpChecked "
"hbmpUnchecked dwItemData text hbmpItem",
(
fType,
fState,
wID,
hSubMenu,
hbmpChecked,
hbmpUnchecked,
dwItemData,
text,
hbmpItem,
),
)
def EmptyMENUITEMINFO(mask=None, text_buf_size=512):
# text_buf_size is number of *characters* - not necessarily no of bytes.
extra = []
if mask is None:
mask = (
win32con.MIIM_BITMAP
| win32con.MIIM_CHECKMARKS
| win32con.MIIM_DATA
| win32con.MIIM_FTYPE
| win32con.MIIM_ID
| win32con.MIIM_STATE
| win32con.MIIM_STRING
| win32con.MIIM_SUBMENU
)
# Note: No MIIM_TYPE - this screws win2k/98.
if mask & win32con.MIIM_STRING:
text_buffer = _make_empty_text_buffer(text_buf_size)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
else:
text_addr = text_buf_size = 0
# Now copy the string to a writable buffer, so that the result
# could be passed to a 'Get' function
buf = struct.pack(
_menuiteminfo_fmt,
struct.calcsize(_menuiteminfo_fmt), # cbSize
mask,
0, # fType,
0, # fState,
0, # wID,
0, # hSubMenu,
0, # hbmpChecked,
0, # hbmpUnchecked,
0, # dwItemData,
text_addr,
text_buf_size,
0, # hbmpItem
)
return array.array("b", buf), extra
# MENUINFO struct
_menuinfo_fmt = "iiiiPiP"
def PackMENUINFO(
dwStyle=None,
cyMax=None,
hbrBack=None,
dwContextHelpID=None,
dwMenuData=None,
fMask=0,
):
if dwStyle is None:
dwStyle = 0
else:
fMask |= win32con.MIM_STYLE
if cyMax is None:
cyMax = 0
else:
fMask |= win32con.MIM_MAXHEIGHT
if hbrBack is None:
hbrBack = 0
else:
fMask |= win32con.MIM_BACKGROUND
if dwContextHelpID is None:
dwContextHelpID = 0
else:
fMask |= win32con.MIM_HELPID
if dwMenuData is None:
dwMenuData = 0
else:
fMask |= win32con.MIM_MENUDATA
# Create the struct.
item = struct.pack(
_menuinfo_fmt,
struct.calcsize(_menuinfo_fmt), # cbSize
fMask,
dwStyle,
cyMax,
hbrBack,
dwContextHelpID,
dwMenuData,
)
return array.array("b", item)
def UnpackMENUINFO(s):
(cb, fMask, dwStyle, cyMax, hbrBack, dwContextHelpID, dwMenuData) = struct.unpack(
_menuinfo_fmt, s
)
assert cb == len(s)
if fMask & win32con.MIM_STYLE == 0:
dwStyle = None
if fMask & win32con.MIM_MAXHEIGHT == 0:
cyMax = None
if fMask & win32con.MIM_BACKGROUND == 0:
hbrBack = None
if fMask & win32con.MIM_HELPID == 0:
dwContextHelpID = None
if fMask & win32con.MIM_MENUDATA == 0:
dwMenuData = None
return _MakeResult(
"MENUINFO dwStyle cyMax hbrBack dwContextHelpID dwMenuData",
(dwStyle, cyMax, hbrBack, dwContextHelpID, dwMenuData),
)
def EmptyMENUINFO(mask=None):
if mask is None:
mask = (
win32con.MIM_STYLE
| win32con.MIM_MAXHEIGHT
| win32con.MIM_BACKGROUND
| win32con.MIM_HELPID
| win32con.MIM_MENUDATA
)
buf = struct.pack(
_menuinfo_fmt,
struct.calcsize(_menuinfo_fmt), # cbSize
mask,
0, # dwStyle
0, # cyMax
0, # hbrBack,
0, # dwContextHelpID,
0, # dwMenuData,
)
return array.array("b", buf)
##########################################################################
#
# Tree View structure support - TVITEM, TVINSERTSTRUCT and TVDISPINFO
#
##########################################################################
# XXX - Note that the following implementation of TreeView structures is ripped
# XXX - from the SpamBayes project. It may not quite work correctly yet - I
# XXX - intend checking them later - but having them is better than not at all!
_tvitem_fmt = "iPiiPiiiiP"
# Helpers for the ugly win32 structure packing/unpacking
# XXX - Note that functions using _GetMaskAndVal run 3x faster if they are
# 'inlined' into the function - see PackLVITEM. If the profiler points at
# _GetMaskAndVal(), you should nuke it (patches welcome once they have been
# tested)
def _GetMaskAndVal(val, default, mask, flag):
if val is None:
return mask, default
else:
if flag is not None:
mask |= flag
return mask, val
def PackTVINSERTSTRUCT(parent, insertAfter, tvitem):
tvitem_buf, extra = PackTVITEM(*tvitem)
tvitem_buf = tvitem_buf.tobytes()
format = "PP%ds" % len(tvitem_buf)
return struct.pack(format, parent, insertAfter, tvitem_buf), extra
def PackTVITEM(hitem, state, stateMask, text, image, selimage, citems, param):
extra = [] # objects we must keep references to
mask = 0
mask, hitem = _GetMaskAndVal(hitem, 0, mask, commctrl.TVIF_HANDLE)
mask, state = _GetMaskAndVal(state, 0, mask, commctrl.TVIF_STATE)
if not mask & commctrl.TVIF_STATE:
stateMask = 0
mask, text = _GetMaskAndVal(text, None, mask, commctrl.TVIF_TEXT)
mask, image = _GetMaskAndVal(image, 0, mask, commctrl.TVIF_IMAGE)
mask, selimage = _GetMaskAndVal(selimage, 0, mask, commctrl.TVIF_SELECTEDIMAGE)
mask, citems = _GetMaskAndVal(citems, 0, mask, commctrl.TVIF_CHILDREN)
mask, param = _GetMaskAndVal(param, 0, mask, commctrl.TVIF_PARAM)
if text is None:
text_addr = text_len = 0
else:
text_buffer = _make_text_buffer(text)
text_len = len(text)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
buf = struct.pack(
_tvitem_fmt,
mask,
hitem,
state,
stateMask,
text_addr,
text_len, # text
image,
selimage,
citems,
param,
)
return array.array("b", buf), extra
# Make a new buffer suitable for querying hitem's attributes.
def EmptyTVITEM(hitem, mask=None, text_buf_size=512):
extra = [] # objects we must keep references to
if mask is None:
mask = (
commctrl.TVIF_HANDLE
| commctrl.TVIF_STATE
| commctrl.TVIF_TEXT
| commctrl.TVIF_IMAGE
| commctrl.TVIF_SELECTEDIMAGE
| commctrl.TVIF_CHILDREN
| commctrl.TVIF_PARAM
)
if mask & commctrl.TVIF_TEXT:
text_buffer = _make_empty_text_buffer(text_buf_size)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
else:
text_addr = text_buf_size = 0
buf = struct.pack(
_tvitem_fmt, mask, hitem, 0, 0, text_addr, text_buf_size, 0, 0, 0, 0
)
return array.array("b", buf), extra
def UnpackTVITEM(buffer):
(
item_mask,
item_hItem,
item_state,
item_stateMask,
item_textptr,
item_cchText,
item_image,
item_selimage,
item_cChildren,
item_param,
) = struct.unpack(_tvitem_fmt, buffer)
# ensure only items listed by the mask are valid (except we assume the
# handle is always valid - some notifications (eg, TVN_ENDLABELEDIT) set a
# mask that doesn't include the handle, but the docs explicity say it is.)
if not (item_mask & commctrl.TVIF_TEXT):
item_textptr = item_cchText = None
if not (item_mask & commctrl.TVIF_CHILDREN):
item_cChildren = None
if not (item_mask & commctrl.TVIF_IMAGE):
item_image = None
if not (item_mask & commctrl.TVIF_PARAM):
item_param = None
if not (item_mask & commctrl.TVIF_SELECTEDIMAGE):
item_selimage = None
if not (item_mask & commctrl.TVIF_STATE):
item_state = item_stateMask = None
if item_textptr:
text = win32gui.PyGetString(item_textptr)
else:
text = None
return _MakeResult(
"TVITEM item_hItem item_state item_stateMask "
"text item_image item_selimage item_cChildren item_param",
(
item_hItem,
item_state,
item_stateMask,
text,
item_image,
item_selimage,
item_cChildren,
item_param,
),
)
# Unpack the lparm from a "TVNOTIFY" message
def UnpackTVNOTIFY(lparam):
item_size = struct.calcsize(_tvitem_fmt)
format = _nmhdr_fmt + _nmhdr_align_padding
if is64bit:
format += "ixxxx"
else:
format += "i"
format += "%ds%ds" % (item_size, item_size)
buf = win32gui.PyGetMemory(lparam, struct.calcsize(format))
hwndFrom, id, code, action, buf_old, buf_new = struct.unpack(format, buf)
item_old = UnpackTVITEM(buf_old)
item_new = UnpackTVITEM(buf_new)
return _MakeResult(
"TVNOTIFY hwndFrom id code action item_old item_new",
(hwndFrom, id, code, action, item_old, item_new),
)
def UnpackTVDISPINFO(lparam):
item_size = struct.calcsize(_tvitem_fmt)
format = "PPi%ds" % (item_size,)
buf = win32gui.PyGetMemory(lparam, struct.calcsize(format))
hwndFrom, id, code, buf_item = struct.unpack(format, buf)
item = UnpackTVITEM(buf_item)
return _MakeResult("TVDISPINFO hwndFrom id code item", (hwndFrom, id, code, item))
#
# List view items
_lvitem_fmt = "iiiiiPiiPi"
def PackLVITEM(
item=None,
subItem=None,
state=None,
stateMask=None,
text=None,
image=None,
param=None,
indent=None,
):
extra = [] # objects we must keep references to
mask = 0
# _GetMaskAndVal adds quite a bit of overhead to this function.
if item is None:
item = 0 # No mask for item
if subItem is None:
subItem = 0 # No mask for sibItem
if state is None:
state = 0
stateMask = 0
else:
mask |= commctrl.LVIF_STATE
if stateMask is None:
stateMask = state
if image is None:
image = 0
else:
mask |= commctrl.LVIF_IMAGE
if param is None:
param = 0
else:
mask |= commctrl.LVIF_PARAM
if indent is None:
indent = 0
else:
mask |= commctrl.LVIF_INDENT
if text is None:
text_addr = text_len = 0
else:
mask |= commctrl.LVIF_TEXT
text_buffer = _make_text_buffer(text)
text_len = len(text)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
buf = struct.pack(
_lvitem_fmt,
mask,
item,
subItem,
state,
stateMask,
text_addr,
text_len, # text
image,
param,
indent,
)
return array.array("b", buf), extra
def UnpackLVITEM(buffer):
(
item_mask,
item_item,
item_subItem,
item_state,
item_stateMask,
item_textptr,
item_cchText,
item_image,
item_param,
item_indent,
) = struct.unpack(_lvitem_fmt, buffer)
# ensure only items listed by the mask are valid
if not (item_mask & commctrl.LVIF_TEXT):
item_textptr = item_cchText = None
if not (item_mask & commctrl.LVIF_IMAGE):
item_image = None
if not (item_mask & commctrl.LVIF_PARAM):
item_param = None
if not (item_mask & commctrl.LVIF_INDENT):
item_indent = None
if not (item_mask & commctrl.LVIF_STATE):
item_state = item_stateMask = None
if item_textptr:
text = win32gui.PyGetString(item_textptr)
else:
text = None
return _MakeResult(
"LVITEM item_item item_subItem item_state "
"item_stateMask text item_image item_param item_indent",
(
item_item,
item_subItem,
item_state,
item_stateMask,
text,
item_image,
item_param,
item_indent,
),
)
# Unpack an "LVNOTIFY" message
def UnpackLVDISPINFO(lparam):
item_size = struct.calcsize(_lvitem_fmt)
format = _nmhdr_fmt + _nmhdr_align_padding + ("%ds" % (item_size,))
buf = win32gui.PyGetMemory(lparam, struct.calcsize(format))
hwndFrom, id, code, buf_item = struct.unpack(format, buf)
item = UnpackLVITEM(buf_item)
return _MakeResult("LVDISPINFO hwndFrom id code item", (hwndFrom, id, code, item))
def UnpackLVNOTIFY(lparam):
format = _nmhdr_fmt + _nmhdr_align_padding + "7i"
if is64bit:
format += "xxxx" # point needs padding.
format += "P"
buf = win32gui.PyGetMemory(lparam, struct.calcsize(format))
(
hwndFrom,
id,
code,
item,
subitem,
newstate,
oldstate,
changed,
pt_x,
pt_y,
lparam,
) = struct.unpack(format, buf)
return _MakeResult(
"UnpackLVNOTIFY hwndFrom id code item subitem "
"newstate oldstate changed pt lparam",
(
hwndFrom,
id,
code,
item,
subitem,
newstate,
oldstate,
changed,
(pt_x, pt_y),
lparam,
),
)
# Make a new buffer suitable for querying an items attributes.
def EmptyLVITEM(item, subitem, mask=None, text_buf_size=512):
extra = [] # objects we must keep references to
if mask is None:
mask = (
commctrl.LVIF_IMAGE
| commctrl.LVIF_INDENT
| commctrl.LVIF_TEXT
| commctrl.LVIF_PARAM
| commctrl.LVIF_STATE
)
if mask & commctrl.LVIF_TEXT:
text_buffer = _make_empty_text_buffer(text_buf_size)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
else:
text_addr = text_buf_size = 0
buf = struct.pack(
_lvitem_fmt,
mask,
item,
subitem,
0,
0,
text_addr,
text_buf_size, # text
0,
0,
0,
)
return array.array("b", buf), extra
# List view column structure
_lvcolumn_fmt = "iiiPiiii"
def PackLVCOLUMN(fmt=None, cx=None, text=None, subItem=None, image=None, order=None):
extra = [] # objects we must keep references to
mask = 0
mask, fmt = _GetMaskAndVal(fmt, 0, mask, commctrl.LVCF_FMT)
mask, cx = _GetMaskAndVal(cx, 0, mask, commctrl.LVCF_WIDTH)
mask, text = _GetMaskAndVal(text, None, mask, commctrl.LVCF_TEXT)
mask, subItem = _GetMaskAndVal(subItem, 0, mask, commctrl.LVCF_SUBITEM)
mask, image = _GetMaskAndVal(image, 0, mask, commctrl.LVCF_IMAGE)
mask, order = _GetMaskAndVal(order, 0, mask, commctrl.LVCF_ORDER)
if text is None:
text_addr = text_len = 0
else:
text_buffer = _make_text_buffer(text)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
text_len = len(text)
buf = struct.pack(
_lvcolumn_fmt, mask, fmt, cx, text_addr, text_len, subItem, image, order
)
return array.array("b", buf), extra
def UnpackLVCOLUMN(lparam):
mask, fmt, cx, text_addr, text_size, subItem, image, order = struct.unpack(
_lvcolumn_fmt, lparam
)
# ensure only items listed by the mask are valid
if not (mask & commctrl.LVCF_FMT):
fmt = None
if not (mask & commctrl.LVCF_WIDTH):
cx = None
if not (mask & commctrl.LVCF_TEXT):
text_addr = text_size = None
if not (mask & commctrl.LVCF_SUBITEM):
subItem = None
if not (mask & commctrl.LVCF_IMAGE):
image = None
if not (mask & commctrl.LVCF_ORDER):
order = None
if text_addr:
text = win32gui.PyGetString(text_addr)
else:
text = None
return _MakeResult(
"LVCOLUMN fmt cx text subItem image order",
(fmt, cx, text, subItem, image, order),
)
# Make a new buffer suitable for querying an items attributes.
def EmptyLVCOLUMN(mask=None, text_buf_size=512):
extra = [] # objects we must keep references to
if mask is None:
mask = (
commctrl.LVCF_FMT
| commctrl.LVCF_WIDTH
| commctrl.LVCF_TEXT
| commctrl.LVCF_SUBITEM
| commctrl.LVCF_IMAGE
| commctrl.LVCF_ORDER
)
if mask & commctrl.LVCF_TEXT:
text_buffer = _make_empty_text_buffer(text_buf_size)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
else:
text_addr = text_buf_size = 0
buf = struct.pack(_lvcolumn_fmt, mask, 0, 0, text_addr, text_buf_size, 0, 0, 0)
return array.array("b", buf), extra
# List view hit-test.
def PackLVHITTEST(pt):
format = "iiiii"
buf = struct.pack(format, pt[0], pt[1], 0, 0, 0)
return array.array("b", buf), None
def UnpackLVHITTEST(buf):
format = "iiiii"
x, y, flags, item, subitem = struct.unpack(format, buf)
return _MakeResult(
"LVHITTEST pt flags item subitem", ((x, y), flags, item, subitem)
)
def PackHDITEM(
cxy=None, text=None, hbm=None, fmt=None, param=None, image=None, order=None
):
extra = [] # objects we must keep references to
mask = 0
mask, cxy = _GetMaskAndVal(cxy, 0, mask, commctrl.HDI_HEIGHT)
mask, text = _GetMaskAndVal(text, None, mask, commctrl.LVCF_TEXT)
mask, hbm = _GetMaskAndVal(hbm, 0, mask, commctrl.HDI_BITMAP)
mask, fmt = _GetMaskAndVal(fmt, 0, mask, commctrl.HDI_FORMAT)
mask, param = _GetMaskAndVal(param, 0, mask, commctrl.HDI_LPARAM)
mask, image = _GetMaskAndVal(image, 0, mask, commctrl.HDI_IMAGE)
mask, order = _GetMaskAndVal(order, 0, mask, commctrl.HDI_ORDER)
if text is None:
text_addr = text_len = 0
else:
text_buffer = _make_text_buffer(text)
extra.append(text_buffer)
text_addr, _ = text_buffer.buffer_info()
text_len = len(text)
format = "iiPPiiPiiii"
buf = struct.pack(
format, mask, cxy, text_addr, hbm, text_len, fmt, param, image, order, 0, 0
)
return array.array("b", buf), extra
# Device notification stuff
# Generic function for packing a DEV_BROADCAST_* structure - generally used
# by the other PackDEV_BROADCAST_* functions in this module.
def PackDEV_BROADCAST(devicetype, rest_fmt, rest_data, extra_data=b""):
# It seems a requirement is 4 byte alignment, even for the 'BYTE data[1]'
# field (eg, that would make DEV_BROADCAST_HANDLE 41 bytes, but we must
# be 44.
extra_data += b"\0" * (4 - len(extra_data) % 4)
format = "iii" + rest_fmt
full_size = struct.calcsize(format) + len(extra_data)
data = (full_size, devicetype, 0) + rest_data
return struct.pack(format, *data) + extra_data
def PackDEV_BROADCAST_HANDLE(
handle,
hdevnotify=0,
guid=b"\0" * 16,
name_offset=0,
data=b"\0",
):
return PackDEV_BROADCAST(
win32con.DBT_DEVTYP_HANDLE,
"PP16sl",
(int(handle), int(hdevnotify), bytes(memoryview(guid)), name_offset),
data,
)
def PackDEV_BROADCAST_VOLUME(unitmask, flags):
return PackDEV_BROADCAST(win32con.DBT_DEVTYP_VOLUME, "II", (unitmask, flags))
def PackDEV_BROADCAST_DEVICEINTERFACE(classguid, name=""):
if not isinstance(name, str):
raise TypeError("Must provide unicode for the name")
name = name.encode("utf-16le")
# 16 bytes for the IID followed by \0 term'd string.
rest_fmt = "16s%ds" % len(name)
# bytes(memoryview(iid)) hoops necessary to get the raw IID bytes.
rest_data = (bytes(memoryview(pywintypes.IID(classguid))), name)
return PackDEV_BROADCAST(win32con.DBT_DEVTYP_DEVICEINTERFACE, rest_fmt, rest_data)
# An object returned by UnpackDEV_BROADCAST.
class DEV_BROADCAST_INFO:
def __init__(self, devicetype, **kw):
self.devicetype = devicetype
self.__dict__.update(kw)
def __str__(self):
return "DEV_BROADCAST_INFO:" + str(self.__dict__)
# Support for unpacking the 'lparam'
def UnpackDEV_BROADCAST(lparam):
if lparam == 0:
return None
hdr_format = "iii"
hdr_size = struct.calcsize(hdr_format)
hdr_buf = win32gui.PyGetMemory(lparam, hdr_size)
size, devtype, reserved = struct.unpack("iii", hdr_buf)
# Due to x64 alignment issues, we need to use the full format string over
# the entire buffer. ie, on x64:
# calcsize('iiiP') != calcsize('iii')+calcsize('P')
buf = win32gui.PyGetMemory(lparam, size)
extra = x = {}
if devtype == win32con.DBT_DEVTYP_HANDLE:
# 2 handles, a GUID, a LONG and possibly an array following...
fmt = hdr_format + "PP16sl"
(
_,
_,
_,
x["handle"],
x["hdevnotify"],
guid_bytes,
x["nameoffset"],
) = struct.unpack(fmt, buf[: struct.calcsize(fmt)])
x["eventguid"] = pywintypes.IID(guid_bytes, True)
elif devtype == win32con.DBT_DEVTYP_DEVICEINTERFACE:
fmt = hdr_format + "16s"
_, _, _, guid_bytes = struct.unpack(fmt, buf[: struct.calcsize(fmt)])
x["classguid"] = pywintypes.IID(guid_bytes, True)
x["name"] = win32gui.PyGetString(lparam + struct.calcsize(fmt))
elif devtype == win32con.DBT_DEVTYP_VOLUME:
# int mask and flags
fmt = hdr_format + "II"
_, _, _, x["unitmask"], x["flags"] = struct.unpack(
fmt, buf[: struct.calcsize(fmt)]
)
elif devtype == win32con.DBT_DEVTYP_PORT:
x["name"] = win32gui.PyGetString(lparam + struct.calcsize(hdr_format))
else:
raise NotImplementedError("unknown device type %d" % (devtype,))
return DEV_BROADCAST_INFO(devtype, **extra)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,627 @@
# Generated by h2py from lmaccess.h
# Included from lmcons.h
CNLEN = 15
LM20_CNLEN = 15
DNLEN = CNLEN
LM20_DNLEN = LM20_CNLEN
UNCLEN = CNLEN + 2
LM20_UNCLEN = LM20_CNLEN + 2
NNLEN = 80
LM20_NNLEN = 12
RMLEN = UNCLEN + 1 + NNLEN
LM20_RMLEN = LM20_UNCLEN + 1 + LM20_NNLEN
SNLEN = 80
LM20_SNLEN = 15
STXTLEN = 256
LM20_STXTLEN = 63
PATHLEN = 256
LM20_PATHLEN = 256
DEVLEN = 80
LM20_DEVLEN = 8
EVLEN = 16
UNLEN = 256
LM20_UNLEN = 20
GNLEN = UNLEN
LM20_GNLEN = LM20_UNLEN
PWLEN = 256
LM20_PWLEN = 14
SHPWLEN = 8
CLTYPE_LEN = 12
MAXCOMMENTSZ = 256
LM20_MAXCOMMENTSZ = 48
QNLEN = NNLEN
LM20_QNLEN = LM20_NNLEN
ALERTSZ = 128
NETBIOS_NAME_LEN = 16
CRYPT_KEY_LEN = 7
CRYPT_TXT_LEN = 8
ENCRYPTED_PWLEN = 16
SESSION_PWLEN = 24
SESSION_CRYPT_KLEN = 21
PARMNUM_ALL = 0
PARM_ERROR_NONE = 0
PARMNUM_BASE_INFOLEVEL = 1000
NULL = 0
PLATFORM_ID_DOS = 300
PLATFORM_ID_OS2 = 400
PLATFORM_ID_NT = 500
PLATFORM_ID_OSF = 600
PLATFORM_ID_VMS = 700
MAX_LANMAN_MESSAGE_ID = 5799
UF_SCRIPT = 1
UF_ACCOUNTDISABLE = 2
UF_HOMEDIR_REQUIRED = 8
UF_LOCKOUT = 16
UF_PASSWD_NOTREQD = 32
UF_PASSWD_CANT_CHANGE = 64
UF_TEMP_DUPLICATE_ACCOUNT = 256
UF_NORMAL_ACCOUNT = 512
UF_INTERDOMAIN_TRUST_ACCOUNT = 2048
UF_WORKSTATION_TRUST_ACCOUNT = 4096
UF_SERVER_TRUST_ACCOUNT = 8192
UF_MACHINE_ACCOUNT_MASK = (
UF_INTERDOMAIN_TRUST_ACCOUNT
| UF_WORKSTATION_TRUST_ACCOUNT
| UF_SERVER_TRUST_ACCOUNT
)
UF_ACCOUNT_TYPE_MASK = (
UF_TEMP_DUPLICATE_ACCOUNT
| UF_NORMAL_ACCOUNT
| UF_INTERDOMAIN_TRUST_ACCOUNT
| UF_WORKSTATION_TRUST_ACCOUNT
| UF_SERVER_TRUST_ACCOUNT
)
UF_DONT_EXPIRE_PASSWD = 65536
UF_MNS_LOGON_ACCOUNT = 131072
UF_SETTABLE_BITS = (
UF_SCRIPT
| UF_ACCOUNTDISABLE
| UF_LOCKOUT
| UF_HOMEDIR_REQUIRED
| UF_PASSWD_NOTREQD
| UF_PASSWD_CANT_CHANGE
| UF_ACCOUNT_TYPE_MASK
| UF_DONT_EXPIRE_PASSWD
| UF_MNS_LOGON_ACCOUNT
)
FILTER_TEMP_DUPLICATE_ACCOUNT = 1
FILTER_NORMAL_ACCOUNT = 2
FILTER_INTERDOMAIN_TRUST_ACCOUNT = 8
FILTER_WORKSTATION_TRUST_ACCOUNT = 16
FILTER_SERVER_TRUST_ACCOUNT = 32
LG_INCLUDE_INDIRECT = 1
AF_OP_PRINT = 1
AF_OP_COMM = 2
AF_OP_SERVER = 4
AF_OP_ACCOUNTS = 8
AF_SETTABLE_BITS = AF_OP_PRINT | AF_OP_COMM | AF_OP_SERVER | AF_OP_ACCOUNTS
UAS_ROLE_STANDALONE = 0
UAS_ROLE_MEMBER = 1
UAS_ROLE_BACKUP = 2
UAS_ROLE_PRIMARY = 3
USER_NAME_PARMNUM = 1
USER_PASSWORD_PARMNUM = 3
USER_PASSWORD_AGE_PARMNUM = 4
USER_PRIV_PARMNUM = 5
USER_HOME_DIR_PARMNUM = 6
USER_COMMENT_PARMNUM = 7
USER_FLAGS_PARMNUM = 8
USER_SCRIPT_PATH_PARMNUM = 9
USER_AUTH_FLAGS_PARMNUM = 10
USER_FULL_NAME_PARMNUM = 11
USER_USR_COMMENT_PARMNUM = 12
USER_PARMS_PARMNUM = 13
USER_WORKSTATIONS_PARMNUM = 14
USER_LAST_LOGON_PARMNUM = 15
USER_LAST_LOGOFF_PARMNUM = 16
USER_ACCT_EXPIRES_PARMNUM = 17
USER_MAX_STORAGE_PARMNUM = 18
USER_UNITS_PER_WEEK_PARMNUM = 19
USER_LOGON_HOURS_PARMNUM = 20
USER_PAD_PW_COUNT_PARMNUM = 21
USER_NUM_LOGONS_PARMNUM = 22
USER_LOGON_SERVER_PARMNUM = 23
USER_COUNTRY_CODE_PARMNUM = 24
USER_CODE_PAGE_PARMNUM = 25
USER_PRIMARY_GROUP_PARMNUM = 51
USER_PROFILE = 52
USER_PROFILE_PARMNUM = 52
USER_HOME_DIR_DRIVE_PARMNUM = 53
USER_NAME_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_NAME_PARMNUM
USER_PASSWORD_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_PASSWORD_PARMNUM
USER_PASSWORD_AGE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_PASSWORD_AGE_PARMNUM
USER_PRIV_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_PRIV_PARMNUM
USER_HOME_DIR_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_HOME_DIR_PARMNUM
USER_COMMENT_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_COMMENT_PARMNUM
USER_FLAGS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_FLAGS_PARMNUM
USER_SCRIPT_PATH_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_SCRIPT_PATH_PARMNUM
USER_AUTH_FLAGS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_AUTH_FLAGS_PARMNUM
USER_FULL_NAME_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_FULL_NAME_PARMNUM
USER_USR_COMMENT_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_USR_COMMENT_PARMNUM
USER_PARMS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_PARMS_PARMNUM
USER_WORKSTATIONS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_WORKSTATIONS_PARMNUM
USER_LAST_LOGON_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_LAST_LOGON_PARMNUM
USER_LAST_LOGOFF_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_LAST_LOGOFF_PARMNUM
USER_ACCT_EXPIRES_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_ACCT_EXPIRES_PARMNUM
USER_MAX_STORAGE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_MAX_STORAGE_PARMNUM
USER_UNITS_PER_WEEK_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_UNITS_PER_WEEK_PARMNUM
USER_LOGON_HOURS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_LOGON_HOURS_PARMNUM
USER_PAD_PW_COUNT_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_PAD_PW_COUNT_PARMNUM
USER_NUM_LOGONS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_NUM_LOGONS_PARMNUM
USER_LOGON_SERVER_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_LOGON_SERVER_PARMNUM
USER_COUNTRY_CODE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_COUNTRY_CODE_PARMNUM
USER_CODE_PAGE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_CODE_PAGE_PARMNUM
USER_PRIMARY_GROUP_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_PRIMARY_GROUP_PARMNUM
USER_HOME_DIR_DRIVE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + USER_HOME_DIR_DRIVE_PARMNUM
NULL_USERSETINFO_PASSWD = " "
UNITS_PER_DAY = 24
UNITS_PER_WEEK = UNITS_PER_DAY * 7
USER_PRIV_MASK = 3
USER_PRIV_GUEST = 0
USER_PRIV_USER = 1
USER_PRIV_ADMIN = 2
MAX_PASSWD_LEN = PWLEN
DEF_MIN_PWLEN = 6
DEF_PWUNIQUENESS = 5
DEF_MAX_PWHIST = 8
DEF_MAX_BADPW = 0
VALIDATED_LOGON = 0
PASSWORD_EXPIRED = 2
NON_VALIDATED_LOGON = 3
VALID_LOGOFF = 1
MODALS_MIN_PASSWD_LEN_PARMNUM = 1
MODALS_MAX_PASSWD_AGE_PARMNUM = 2
MODALS_MIN_PASSWD_AGE_PARMNUM = 3
MODALS_FORCE_LOGOFF_PARMNUM = 4
MODALS_PASSWD_HIST_LEN_PARMNUM = 5
MODALS_ROLE_PARMNUM = 6
MODALS_PRIMARY_PARMNUM = 7
MODALS_DOMAIN_NAME_PARMNUM = 8
MODALS_DOMAIN_ID_PARMNUM = 9
MODALS_LOCKOUT_DURATION_PARMNUM = 10
MODALS_LOCKOUT_OBSERVATION_WINDOW_PARMNUM = 11
MODALS_LOCKOUT_THRESHOLD_PARMNUM = 12
MODALS_MIN_PASSWD_LEN_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + MODALS_MIN_PASSWD_LEN_PARMNUM
MODALS_MAX_PASSWD_AGE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + MODALS_MAX_PASSWD_AGE_PARMNUM
MODALS_MIN_PASSWD_AGE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + MODALS_MIN_PASSWD_AGE_PARMNUM
MODALS_FORCE_LOGOFF_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + MODALS_FORCE_LOGOFF_PARMNUM
MODALS_PASSWD_HIST_LEN_INFOLEVEL = (
PARMNUM_BASE_INFOLEVEL + MODALS_PASSWD_HIST_LEN_PARMNUM
)
MODALS_ROLE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + MODALS_ROLE_PARMNUM
MODALS_PRIMARY_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + MODALS_PRIMARY_PARMNUM
MODALS_DOMAIN_NAME_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + MODALS_DOMAIN_NAME_PARMNUM
MODALS_DOMAIN_ID_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + MODALS_DOMAIN_ID_PARMNUM
GROUPIDMASK = 32768
GROUP_ALL_PARMNUM = 0
GROUP_NAME_PARMNUM = 1
GROUP_COMMENT_PARMNUM = 2
GROUP_ATTRIBUTES_PARMNUM = 3
GROUP_ALL_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + GROUP_ALL_PARMNUM
GROUP_NAME_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + GROUP_NAME_PARMNUM
GROUP_COMMENT_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + GROUP_COMMENT_PARMNUM
GROUP_ATTRIBUTES_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + GROUP_ATTRIBUTES_PARMNUM
LOCALGROUP_NAME_PARMNUM = 1
LOCALGROUP_COMMENT_PARMNUM = 2
MAXPERMENTRIES = 64
ACCESS_NONE = 0
ACCESS_READ = 1
ACCESS_WRITE = 2
ACCESS_CREATE = 4
ACCESS_EXEC = 8
ACCESS_DELETE = 16
ACCESS_ATRIB = 32
ACCESS_PERM = 64
ACCESS_GROUP = 32768
ACCESS_AUDIT = 1
ACCESS_SUCCESS_OPEN = 16
ACCESS_SUCCESS_WRITE = 32
ACCESS_SUCCESS_DELETE = 64
ACCESS_SUCCESS_ACL = 128
ACCESS_SUCCESS_MASK = 240
ACCESS_FAIL_OPEN = 256
ACCESS_FAIL_WRITE = 512
ACCESS_FAIL_DELETE = 1024
ACCESS_FAIL_ACL = 2048
ACCESS_FAIL_MASK = 3840
ACCESS_FAIL_SHIFT = 4
ACCESS_RESOURCE_NAME_PARMNUM = 1
ACCESS_ATTR_PARMNUM = 2
ACCESS_COUNT_PARMNUM = 3
ACCESS_ACCESS_LIST_PARMNUM = 4
ACCESS_RESOURCE_NAME_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + ACCESS_RESOURCE_NAME_PARMNUM
ACCESS_ATTR_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + ACCESS_ATTR_PARMNUM
ACCESS_COUNT_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + ACCESS_COUNT_PARMNUM
ACCESS_ACCESS_LIST_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + ACCESS_ACCESS_LIST_PARMNUM
ACCESS_LETTERS = "RWCXDAP "
NETLOGON_CONTROL_QUERY = 1
NETLOGON_CONTROL_REPLICATE = 2
NETLOGON_CONTROL_SYNCHRONIZE = 3
NETLOGON_CONTROL_PDC_REPLICATE = 4
NETLOGON_CONTROL_REDISCOVER = 5
NETLOGON_CONTROL_TC_QUERY = 6
NETLOGON_CONTROL_TRANSPORT_NOTIFY = 7
NETLOGON_CONTROL_FIND_USER = 8
NETLOGON_CONTROL_UNLOAD_NETLOGON_DLL = 65531
NETLOGON_CONTROL_BACKUP_CHANGE_LOG = 65532
NETLOGON_CONTROL_TRUNCATE_LOG = 65533
NETLOGON_CONTROL_SET_DBFLAG = 65534
NETLOGON_CONTROL_BREAKPOINT = 65535
NETLOGON_REPLICATION_NEEDED = 1
NETLOGON_REPLICATION_IN_PROGRESS = 2
NETLOGON_FULL_SYNC_REPLICATION = 4
NETLOGON_REDO_NEEDED = 8
######################
# Manual stuff
TEXT = lambda x: x
MAX_PREFERRED_LENGTH = -1
PARM_ERROR_UNKNOWN = -1
MESSAGE_FILENAME = TEXT("NETMSG")
OS2MSG_FILENAME = TEXT("BASE")
HELP_MSG_FILENAME = TEXT("NETH")
BACKUP_MSG_FILENAME = TEXT("BAK.MSG")
TIMEQ_FOREVER = -1
USER_MAXSTORAGE_UNLIMITED = -1
USER_NO_LOGOFF = -1
DEF_MAX_PWAGE = TIMEQ_FOREVER
DEF_MIN_PWAGE = 0
DEF_FORCE_LOGOFF = -1
ONE_DAY = 1 * 24 * 3600
GROUP_SPECIALGRP_USERS = "USERS"
GROUP_SPECIALGRP_ADMINS = "ADMINS"
GROUP_SPECIALGRP_GUESTS = "GUESTS"
GROUP_SPECIALGRP_LOCAL = "LOCAL"
ACCESS_ALL = (
ACCESS_READ
| ACCESS_WRITE
| ACCESS_CREATE
| ACCESS_EXEC
| ACCESS_DELETE
| ACCESS_ATRIB
| ACCESS_PERM
)
# From lmserver.h
SV_PLATFORM_ID_OS2 = 400
SV_PLATFORM_ID_NT = 500
MAJOR_VERSION_MASK = 15
SV_TYPE_WORKSTATION = 1
SV_TYPE_SERVER = 2
SV_TYPE_SQLSERVER = 4
SV_TYPE_DOMAIN_CTRL = 8
SV_TYPE_DOMAIN_BAKCTRL = 16
SV_TYPE_TIME_SOURCE = 32
SV_TYPE_AFP = 64
SV_TYPE_NOVELL = 128
SV_TYPE_DOMAIN_MEMBER = 256
SV_TYPE_PRINTQ_SERVER = 512
SV_TYPE_DIALIN_SERVER = 1024
SV_TYPE_XENIX_SERVER = 2048
SV_TYPE_SERVER_UNIX = SV_TYPE_XENIX_SERVER
SV_TYPE_NT = 4096
SV_TYPE_WFW = 8192
SV_TYPE_SERVER_MFPN = 16384
SV_TYPE_SERVER_NT = 32768
SV_TYPE_POTENTIAL_BROWSER = 65536
SV_TYPE_BACKUP_BROWSER = 131072
SV_TYPE_MASTER_BROWSER = 262144
SV_TYPE_DOMAIN_MASTER = 524288
SV_TYPE_SERVER_OSF = 1048576
SV_TYPE_SERVER_VMS = 2097152
SV_TYPE_WINDOWS = 4194304
SV_TYPE_DFS = 8388608
SV_TYPE_CLUSTER_NT = 16777216
SV_TYPE_DCE = 268435456
SV_TYPE_ALTERNATE_XPORT = 536870912
SV_TYPE_LOCAL_LIST_ONLY = 1073741824
SV_TYPE_DOMAIN_ENUM = -2147483648
SV_TYPE_ALL = -1
SV_NODISC = -1
SV_USERSECURITY = 1
SV_SHARESECURITY = 0
SV_HIDDEN = 1
SV_VISIBLE = 0
SV_PLATFORM_ID_PARMNUM = 101
SV_NAME_PARMNUM = 102
SV_VERSION_MAJOR_PARMNUM = 103
SV_VERSION_MINOR_PARMNUM = 104
SV_TYPE_PARMNUM = 105
SV_COMMENT_PARMNUM = 5
SV_USERS_PARMNUM = 107
SV_DISC_PARMNUM = 10
SV_HIDDEN_PARMNUM = 16
SV_ANNOUNCE_PARMNUM = 17
SV_ANNDELTA_PARMNUM = 18
SV_USERPATH_PARMNUM = 112
SV_ULIST_MTIME_PARMNUM = 401
SV_GLIST_MTIME_PARMNUM = 402
SV_ALIST_MTIME_PARMNUM = 403
SV_ALERTS_PARMNUM = 11
SV_SECURITY_PARMNUM = 405
SV_NUMADMIN_PARMNUM = 406
SV_LANMASK_PARMNUM = 407
SV_GUESTACC_PARMNUM = 408
SV_CHDEVQ_PARMNUM = 410
SV_CHDEVJOBS_PARMNUM = 411
SV_CONNECTIONS_PARMNUM = 412
SV_SHARES_PARMNUM = 413
SV_OPENFILES_PARMNUM = 414
SV_SESSREQS_PARMNUM = 417
SV_ACTIVELOCKS_PARMNUM = 419
SV_NUMREQBUF_PARMNUM = 420
SV_NUMBIGBUF_PARMNUM = 422
SV_NUMFILETASKS_PARMNUM = 423
SV_ALERTSCHED_PARMNUM = 37
SV_ERRORALERT_PARMNUM = 38
SV_LOGONALERT_PARMNUM = 39
SV_ACCESSALERT_PARMNUM = 40
SV_DISKALERT_PARMNUM = 41
SV_NETIOALERT_PARMNUM = 42
SV_MAXAUDITSZ_PARMNUM = 43
SV_SRVHEURISTICS_PARMNUM = 431
SV_SESSOPENS_PARMNUM = 501
SV_SESSVCS_PARMNUM = 502
SV_OPENSEARCH_PARMNUM = 503
SV_SIZREQBUF_PARMNUM = 504
SV_INITWORKITEMS_PARMNUM = 505
SV_MAXWORKITEMS_PARMNUM = 506
SV_RAWWORKITEMS_PARMNUM = 507
SV_IRPSTACKSIZE_PARMNUM = 508
SV_MAXRAWBUFLEN_PARMNUM = 509
SV_SESSUSERS_PARMNUM = 510
SV_SESSCONNS_PARMNUM = 511
SV_MAXNONPAGEDMEMORYUSAGE_PARMNUM = 512
SV_MAXPAGEDMEMORYUSAGE_PARMNUM = 513
SV_ENABLESOFTCOMPAT_PARMNUM = 514
SV_ENABLEFORCEDLOGOFF_PARMNUM = 515
SV_TIMESOURCE_PARMNUM = 516
SV_ACCEPTDOWNLEVELAPIS_PARMNUM = 517
SV_LMANNOUNCE_PARMNUM = 518
SV_DOMAIN_PARMNUM = 519
SV_MAXCOPYREADLEN_PARMNUM = 520
SV_MAXCOPYWRITELEN_PARMNUM = 521
SV_MINKEEPSEARCH_PARMNUM = 522
SV_MAXKEEPSEARCH_PARMNUM = 523
SV_MINKEEPCOMPLSEARCH_PARMNUM = 524
SV_MAXKEEPCOMPLSEARCH_PARMNUM = 525
SV_THREADCOUNTADD_PARMNUM = 526
SV_NUMBLOCKTHREADS_PARMNUM = 527
SV_SCAVTIMEOUT_PARMNUM = 528
SV_MINRCVQUEUE_PARMNUM = 529
SV_MINFREEWORKITEMS_PARMNUM = 530
SV_XACTMEMSIZE_PARMNUM = 531
SV_THREADPRIORITY_PARMNUM = 532
SV_MAXMPXCT_PARMNUM = 533
SV_OPLOCKBREAKWAIT_PARMNUM = 534
SV_OPLOCKBREAKRESPONSEWAIT_PARMNUM = 535
SV_ENABLEOPLOCKS_PARMNUM = 536
SV_ENABLEOPLOCKFORCECLOSE_PARMNUM = 537
SV_ENABLEFCBOPENS_PARMNUM = 538
SV_ENABLERAW_PARMNUM = 539
SV_ENABLESHAREDNETDRIVES_PARMNUM = 540
SV_MINFREECONNECTIONS_PARMNUM = 541
SV_MAXFREECONNECTIONS_PARMNUM = 542
SV_INITSESSTABLE_PARMNUM = 543
SV_INITCONNTABLE_PARMNUM = 544
SV_INITFILETABLE_PARMNUM = 545
SV_INITSEARCHTABLE_PARMNUM = 546
SV_ALERTSCHEDULE_PARMNUM = 547
SV_ERRORTHRESHOLD_PARMNUM = 548
SV_NETWORKERRORTHRESHOLD_PARMNUM = 549
SV_DISKSPACETHRESHOLD_PARMNUM = 550
SV_MAXLINKDELAY_PARMNUM = 552
SV_MINLINKTHROUGHPUT_PARMNUM = 553
SV_LINKINFOVALIDTIME_PARMNUM = 554
SV_SCAVQOSINFOUPDATETIME_PARMNUM = 555
SV_MAXWORKITEMIDLETIME_PARMNUM = 556
SV_MAXRAWWORKITEMS_PARMNUM = 557
SV_PRODUCTTYPE_PARMNUM = 560
SV_SERVERSIZE_PARMNUM = 561
SV_CONNECTIONLESSAUTODISC_PARMNUM = 562
SV_SHARINGVIOLATIONRETRIES_PARMNUM = 563
SV_SHARINGVIOLATIONDELAY_PARMNUM = 564
SV_MAXGLOBALOPENSEARCH_PARMNUM = 565
SV_REMOVEDUPLICATESEARCHES_PARMNUM = 566
SV_LOCKVIOLATIONRETRIES_PARMNUM = 567
SV_LOCKVIOLATIONOFFSET_PARMNUM = 568
SV_LOCKVIOLATIONDELAY_PARMNUM = 569
SV_MDLREADSWITCHOVER_PARMNUM = 570
SV_CACHEDOPENLIMIT_PARMNUM = 571
SV_CRITICALTHREADS_PARMNUM = 572
SV_RESTRICTNULLSESSACCESS_PARMNUM = 573
SV_ENABLEWFW311DIRECTIPX_PARMNUM = 574
SV_OTHERQUEUEAFFINITY_PARMNUM = 575
SV_QUEUESAMPLESECS_PARMNUM = 576
SV_BALANCECOUNT_PARMNUM = 577
SV_PREFERREDAFFINITY_PARMNUM = 578
SV_MAXFREERFCBS_PARMNUM = 579
SV_MAXFREEMFCBS_PARMNUM = 580
SV_MAXFREELFCBS_PARMNUM = 581
SV_MAXFREEPAGEDPOOLCHUNKS_PARMNUM = 582
SV_MINPAGEDPOOLCHUNKSIZE_PARMNUM = 583
SV_MAXPAGEDPOOLCHUNKSIZE_PARMNUM = 584
SV_SENDSFROMPREFERREDPROCESSOR_PARMNUM = 585
SV_MAXTHREADSPERQUEUE_PARMNUM = 586
SV_CACHEDDIRECTORYLIMIT_PARMNUM = 587
SV_MAXCOPYLENGTH_PARMNUM = 588
SV_ENABLEBULKTRANSFER_PARMNUM = 589
SV_ENABLECOMPRESSION_PARMNUM = 590
SV_AUTOSHAREWKS_PARMNUM = 591
SV_AUTOSHARESERVER_PARMNUM = 592
SV_ENABLESECURITYSIGNATURE_PARMNUM = 593
SV_REQUIRESECURITYSIGNATURE_PARMNUM = 594
SV_MINCLIENTBUFFERSIZE_PARMNUM = 595
SV_CONNECTIONNOSESSIONSTIMEOUT_PARMNUM = 596
SVI1_NUM_ELEMENTS = 5
SVI2_NUM_ELEMENTS = 40
SVI3_NUM_ELEMENTS = 44
SW_AUTOPROF_LOAD_MASK = 1
SW_AUTOPROF_SAVE_MASK = 2
SV_MAX_SRV_HEUR_LEN = 32
SV_USERS_PER_LICENSE = 5
SVTI2_REMAP_PIPE_NAMES = 2
# Generated by h2py from lmshare.h
SHARE_NETNAME_PARMNUM = 1
SHARE_TYPE_PARMNUM = 3
SHARE_REMARK_PARMNUM = 4
SHARE_PERMISSIONS_PARMNUM = 5
SHARE_MAX_USES_PARMNUM = 6
SHARE_CURRENT_USES_PARMNUM = 7
SHARE_PATH_PARMNUM = 8
SHARE_PASSWD_PARMNUM = 9
SHARE_FILE_SD_PARMNUM = 501
SHI1_NUM_ELEMENTS = 4
SHI2_NUM_ELEMENTS = 10
STYPE_DISKTREE = 0
STYPE_PRINTQ = 1
STYPE_DEVICE = 2
STYPE_IPC = 3
STYPE_SPECIAL = -2147483648
SHI1005_FLAGS_DFS = 1
SHI1005_FLAGS_DFS_ROOT = 2
COW_PERMACHINE = 4
COW_PERUSER = 8
CSC_CACHEABLE = 16
CSC_NOFLOWOPS = 32
CSC_AUTO_INWARD = 64
CSC_AUTO_OUTWARD = 128
SHI1005_VALID_FLAGS_SET = (
CSC_CACHEABLE
| CSC_NOFLOWOPS
| CSC_AUTO_INWARD
| CSC_AUTO_OUTWARD
| COW_PERMACHINE
| COW_PERUSER
)
SHI1007_VALID_FLAGS_SET = SHI1005_VALID_FLAGS_SET
SESS_GUEST = 1
SESS_NOENCRYPTION = 2
SESI1_NUM_ELEMENTS = 8
SESI2_NUM_ELEMENTS = 9
PERM_FILE_READ = 1
PERM_FILE_WRITE = 2
PERM_FILE_CREATE = 4
# Generated by h2py from d:\mssdk\include\winnetwk.h
WNNC_NET_MSNET = 65536
WNNC_NET_LANMAN = 131072
WNNC_NET_NETWARE = 196608
WNNC_NET_VINES = 262144
WNNC_NET_10NET = 327680
WNNC_NET_LOCUS = 393216
WNNC_NET_SUN_PC_NFS = 458752
WNNC_NET_LANSTEP = 524288
WNNC_NET_9TILES = 589824
WNNC_NET_LANTASTIC = 655360
WNNC_NET_AS400 = 720896
WNNC_NET_FTP_NFS = 786432
WNNC_NET_PATHWORKS = 851968
WNNC_NET_LIFENET = 917504
WNNC_NET_POWERLAN = 983040
WNNC_NET_BWNFS = 1048576
WNNC_NET_COGENT = 1114112
WNNC_NET_FARALLON = 1179648
WNNC_NET_APPLETALK = 1245184
WNNC_NET_INTERGRAPH = 1310720
WNNC_NET_SYMFONET = 1376256
WNNC_NET_CLEARCASE = 1441792
WNNC_NET_FRONTIER = 1507328
WNNC_NET_BMC = 1572864
WNNC_NET_DCE = 1638400
WNNC_NET_DECORB = 2097152
WNNC_NET_PROTSTOR = 2162688
WNNC_NET_FJ_REDIR = 2228224
WNNC_NET_DISTINCT = 2293760
WNNC_NET_TWINS = 2359296
WNNC_NET_RDR2SAMPLE = 2424832
RESOURCE_CONNECTED = 1
RESOURCE_GLOBALNET = 2
RESOURCE_REMEMBERED = 3
RESOURCE_RECENT = 4
RESOURCE_CONTEXT = 5
RESOURCETYPE_ANY = 0
RESOURCETYPE_DISK = 1
RESOURCETYPE_PRINT = 2
RESOURCETYPE_RESERVED = 8
RESOURCETYPE_UNKNOWN = -1
RESOURCEUSAGE_CONNECTABLE = 1
RESOURCEUSAGE_CONTAINER = 2
RESOURCEUSAGE_NOLOCALDEVICE = 4
RESOURCEUSAGE_SIBLING = 8
RESOURCEUSAGE_ATTACHED = 16
RESOURCEUSAGE_ALL = (
RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED
)
RESOURCEUSAGE_RESERVED = -2147483648
RESOURCEDISPLAYTYPE_GENERIC = 0
RESOURCEDISPLAYTYPE_DOMAIN = 1
RESOURCEDISPLAYTYPE_SERVER = 2
RESOURCEDISPLAYTYPE_SHARE = 3
RESOURCEDISPLAYTYPE_FILE = 4
RESOURCEDISPLAYTYPE_GROUP = 5
RESOURCEDISPLAYTYPE_NETWORK = 6
RESOURCEDISPLAYTYPE_ROOT = 7
RESOURCEDISPLAYTYPE_SHAREADMIN = 8
RESOURCEDISPLAYTYPE_DIRECTORY = 9
RESOURCEDISPLAYTYPE_TREE = 10
RESOURCEDISPLAYTYPE_NDSCONTAINER = 11
NETPROPERTY_PERSISTENT = 1
CONNECT_UPDATE_PROFILE = 1
CONNECT_UPDATE_RECENT = 2
CONNECT_TEMPORARY = 4
CONNECT_INTERACTIVE = 8
CONNECT_PROMPT = 16
CONNECT_NEED_DRIVE = 32
CONNECT_REFCOUNT = 64
CONNECT_REDIRECT = 128
CONNECT_LOCALDRIVE = 256
CONNECT_CURRENT_MEDIA = 512
CONNECT_DEFERRED = 1024
CONNECT_RESERVED = -16777216
CONNDLG_RO_PATH = 1
CONNDLG_CONN_POINT = 2
CONNDLG_USE_MRU = 4
CONNDLG_HIDE_BOX = 8
CONNDLG_PERSIST = 16
CONNDLG_NOT_PERSIST = 32
DISC_UPDATE_PROFILE = 1
DISC_NO_FORCE = 64
UNIVERSAL_NAME_INFO_LEVEL = 1
REMOTE_NAME_INFO_LEVEL = 2
WNFMT_MULTILINE = 1
WNFMT_ABBREVIATED = 2
WNFMT_INENUM = 16
WNFMT_CONNECTION = 32
NETINFO_DLL16 = 1
NETINFO_DISKRED = 4
NETINFO_PRINTERRED = 8
RP_LOGON = 1
RP_INIFILE = 2
PP_DISPLAYERRORS = 1
WNCON_FORNETCARD = 1
WNCON_NOTROUTED = 2
WNCON_SLOWLINK = 4
WNCON_DYNAMIC = 8
## NETSETUP_NAME_TYPE, used with NetValidateName
NetSetupUnknown = 0
NetSetupMachine = 1
NetSetupWorkgroup = 2
NetSetupDomain = 3
NetSetupNonExistentDomain = 4
NetSetupDnsMachine = 5
## NETSETUP_JOIN_STATUS, use with NetGetJoinInformation
NetSetupUnknownStatus = 0
NetSetupUnjoined = 1
NetSetupWorkgroupName = 2
NetSetupDomainName = 3
NetValidateAuthentication = 1
NetValidatePasswordChange = 2
NetValidatePasswordReset = 3

View File

@@ -0,0 +1,570 @@
"""
Performance Data Helper (PDH) Query Classes
Wrapper classes for end-users and high-level access to the PDH query
mechanisms. PDH is a win32-specific mechanism for accessing the
performance data made available by the system. The Python for Windows
PDH module does not implement the "Registry" interface, implementing
the more straightforward Query-based mechanism.
The basic idea of a PDH Query is an object which can query the system
about the status of any number of "counters." The counters are paths
to a particular piece of performance data. For instance, the path
'\\Memory\\Available Bytes' describes just about exactly what it says
it does, the amount of free memory on the default computer expressed
in Bytes. These paths can be considerably more complex than this,
but part of the point of this wrapper module is to hide that
complexity from the end-user/programmer.
EXAMPLE: A more complex Path
'\\\\RAISTLIN\\PhysicalDisk(_Total)\\Avg. Disk Bytes/Read'
Raistlin --> Computer Name
PhysicalDisk --> Object Name
_Total --> The particular Instance (in this case, all instances, i.e. all drives)
Avg. Disk Bytes/Read --> The piece of data being monitored.
EXAMPLE: Collecting Data with a Query
As an example, the following code implements a logger which allows the
user to choose what counters they would like to log, and logs those
counters for 30 seconds, at two-second intervals.
query = Query()
query.addcounterbybrowsing()
query.collectdatafor(30,2)
The data is now stored in a list of lists as:
query.curresults
The counters(paths) which were used to collect the data are:
query.curpaths
You can use the win32pdh.ParseCounterPath(path) utility function
to turn the paths into more easily read values for your task, or
write the data to a file, or do whatever you want with it.
OTHER NOTABLE METHODS:
query.collectdatawhile(period) # start a logging thread for collecting data
query.collectdatawhile_stop() # signal the logging thread to stop logging
query.collectdata() # run the query only once
query.addperfcounter(object, counter, machine=None) # add a standard performance counter
query.addinstcounter(object, counter,machine=None,objtype = 'Process',volatile=1,format = win32pdh.PDH_FMT_LONG) # add a possibly volatile counter
### Known bugs and limitations ###
Due to a problem with threading under the PythonWin interpreter, there
will be no data logged if the PythonWin window is not the foreground
application. Workaround: scripts using threading should be run in the
python.exe interpreter.
The volatile-counter handlers are possibly buggy, they haven't been
tested to any extent. The wrapper Query makes it safe to pass invalid
paths (a -1 will be returned, or the Query will be totally ignored,
depending on the missing element), so you should be able to work around
the error by including all possible paths and filtering out the -1's.
There is no way I know of to stop a thread which is currently sleeping,
so you have to wait until the thread in collectdatawhile is activated
again. This might become a problem in situations where the collection
period is multiple minutes (or hours, or whatever).
Should make the win32pdh.ParseCounter function available to the Query
classes as a method or something similar, so that it can be accessed
by programmes that have just picked up an instance from somewhere.
Should explicitly mention where QueryErrors can be raised, and create a
full test set to see if there are any uncaught win32api.error's still
hanging around.
When using the python.exe interpreter, the addcounterbybrowsing-
generated browser window is often hidden behind other windows. No known
workaround other than Alt-tabing to reach the browser window.
### Other References ###
The win32pdhutil module (which should be in the %pythonroot%/win32/lib
directory) provides quick-and-dirty utilities for one-off access to
variables from the PDH. Almost everything in that module can be done
with a Query object, but it provides task-oriented functions for a
number of common one-off tasks.
If you can access the MS Developers Network Library, you can find
information about the PDH API as MS describes it. For a background article,
try:
https://web.archive.org/web/20040926110045/http://msdn.microsoft.com:80/library/en-us/dnperfmo/html/msdn_pdhlib.asp
The reference guide for the PDH API was last spotted at:
https://learn.microsoft.com/en-us/windows/win32/perfctrs/using-the-pdh-functions-to-consume-counter-data
In general the Python version of the API is just a wrapper around the
Query-based version of this API (as far as I can see), so you can learn what
you need to from there. From what I understand, the MSDN Online
resources are available for the price of signing up for them. I can't
guarantee how long that's supposed to last. (Or anything for that
matter).
http://premium.microsoft.com/isapi/devonly/prodinfo/msdnprod/msdnlib.idc?theURL=/msdn/library/sdkdoc/perfdata_4982.htm
The eventual plan is for my (Mike Fletcher's) Starship account to include
a section on NT Administration, and the Query is the first project
in this plan. There should be an article describing the creation of
a simple logger there, but the example above is 90% of the work of
that project, so don't sweat it if you don't find anything there.
(currently the account hasn't been set up).
https://web.archive.org/web/19980422204546/http://starship.skyport.net/crew/mcfletch/
If you need to contact me immediately, (why I can't imagine), you can
email me at mcfletch@golden.net, or just post your question to the
Python newsgroup with a catchy subject line.
news:comp.lang.python
### Other Stuff ###
The Query classes are by Mike Fletcher, with the working code
being corruptions of Mark Hammonds win32pdhutil module.
Use at your own risk, no warranties, no guarantees, no assurances,
if you use it, you accept the risk of using it, etceteras.
"""
# Feb 12, 98 - MH added "rawaddcounter" so caller can get exception details.
import _thread
import copy
import time
import win32api
import win32pdh
class BaseQuery:
"""
Provides wrapped access to the Performance Data Helper query
objects, generally you should use the child class Query
unless you have need of doing weird things :)
This class supports two major working paradigms. In the first,
you open the query, and run it as many times as you need, closing
the query when you're done with it. This is suitable for static
queries (ones where processes being monitored don't disappear).
In the second, you allow the query to be opened each time and
closed afterward. This causes the base query object to be
destroyed after each call. Suitable for dynamic queries (ones
which watch processes which might be closed while watching.)
"""
def __init__(self, paths=None):
"""
The PDH Query object is initialised with a single, optional
list argument, that must be properly formatted PDH Counter
paths. Generally this list will only be provided by the class
when it is being unpickled (removed from storage). Normal
use is to call the class with no arguments and use the various
addcounter functions (particularly, for end user's, the use of
addcounterbybrowsing is the most common approach) You might
want to provide the list directly if you want to hard-code the
elements with which your query deals (and thereby avoid the
overhead of unpickling the class).
"""
self.counters = []
if paths:
self.paths = paths
else:
self.paths = []
self._base = None
self.active = 0
self.curpaths = []
def addcounterbybrowsing(
self, flags=win32pdh.PERF_DETAIL_WIZARD, windowtitle="Python Browser"
):
"""
Adds possibly multiple paths to the paths attribute of the query,
does this by calling the standard counter browsing dialogue. Within
this dialogue, find the counter you want to log, and click: Add,
repeat for every path you want to log, then click on close. The
paths are appended to the non-volatile paths list for this class,
subclasses may create a function which parses the paths and decides
(via heuristics) whether to add the path to the volatile or non-volatile
path list.
e.g.:
query.addcounter()
"""
win32pdh.BrowseCounters(None, 0, self.paths.append, flags, windowtitle)
def rawaddcounter(self, object, counter, instance=None, inum=-1, machine=None):
"""
Adds a single counter path, without catching any exceptions.
See addcounter for details.
"""
path = win32pdh.MakeCounterPath(
(machine, object, instance, None, inum, counter)
)
self.paths.append(path)
def addcounter(self, object, counter, instance=None, inum=-1, machine=None):
"""
Adds a single counter path to the paths attribute. Normally
this will be called by a child class' speciality functions,
rather than being called directly by the user. (Though it isn't
hard to call manually, since almost everything is given a default)
This method is only functional when the query is closed (or hasn't
yet been opened). This is to prevent conflict in multi-threaded
query applications).
e.g.:
query.addcounter('Memory','Available Bytes')
"""
if not self.active:
try:
self.rawaddcounter(object, counter, instance, inum, machine)
return 0
except win32api.error:
return -1
else:
return -1
def open(self):
"""
Build the base query object for this wrapper,
then add all of the counters required for the query.
Raise a QueryError if we can't complete the functions.
If we are already open, then do nothing.
"""
if not self.active: # to prevent having multiple open queries
# curpaths are made accessible here because of the possibility of volatile paths
# which may be dynamically altered by subclasses.
self.curpaths = copy.copy(self.paths)
try:
base = win32pdh.OpenQuery()
for path in self.paths:
try:
self.counters.append(win32pdh.AddCounter(base, path))
except win32api.error: # we passed a bad path
self.counters.append(0)
pass
self._base = base
self.active = 1
return 0 # open succeeded
except: # if we encounter any errors, kill the Query
try:
self.killbase(base)
except NameError: # failed in creating query
pass
self.active = 0
self.curpaths = []
raise QueryError(self)
return 1 # already open
def killbase(self, base=None):
"""
### This is not a public method
Mission critical function to kill the win32pdh objects held
by this object. User's should generally use the close method
instead of this method, in case a sub-class has overridden
close to provide some special functionality.
"""
# Kill Pythonic references to the objects in this object's namespace
self._base = None
counters = self.counters
self.counters = []
# we don't kill the curpaths for convenience, this allows the
# user to close a query and still access the last paths
self.active = 0
# Now call the delete functions on all of the objects
try:
map(win32pdh.RemoveCounter, counters)
except:
pass
try:
win32pdh.CloseQuery(base)
except:
pass
del counters
del base
def close(self):
"""
Makes certain that the underlying query object has been closed,
and that all counters have been removed from it. This is
important for reference counting.
You should only need to call close if you have previously called
open. The collectdata methods all can handle opening and
closing the query. Calling close multiple times is acceptable.
"""
try:
self.killbase(self._base)
except AttributeError:
self.killbase()
__del__ = close
def collectdata(self, format=win32pdh.PDH_FMT_LONG):
"""
Returns the formatted current values for the Query
"""
if self._base: # we are currently open, don't change this
return self.collectdataslave(format)
else: # need to open and then close the _base, should be used by one-offs and elements tracking application instances
self.open() # will raise QueryError if couldn't open the query
temp = self.collectdataslave(format)
self.close() # will always close
return temp
def collectdataslave(self, format=win32pdh.PDH_FMT_LONG):
"""
### Not a public method
Called only when the Query is known to be open, runs over
the whole set of counters, appending results to the temp,
returns the values as a list.
"""
try:
win32pdh.CollectQueryData(self._base)
temp = []
for counter in self.counters:
ok = 0
try:
if counter:
temp.append(
win32pdh.GetFormattedCounterValue(counter, format)[1]
)
ok = 1
except win32api.error:
pass
if not ok:
temp.append(-1) # a better way to signal failure???
return temp
# will happen if, for instance, no counters are part of the query and we attempt to collect data for it.
except win32api.error:
return [-1] * len(self.counters)
# pickle functions
def __getinitargs__(self):
"""
### Not a public method
"""
return (self.paths,)
class Query(BaseQuery):
"""
Performance Data Helper(PDH) Query object:
Provides a wrapper around the native PDH query object which
allows for query reuse, query storage, and general maintenance
functions (adding counter paths in various ways being the most
obvious ones).
"""
def __init__(self, *args, **namedargs):
"""
The PDH Query object is initialised with a single, optional
list argument, that must be properly formatted PDH Counter
paths. Generally this list will only be provided by the class
when it is being unpickled (removed from storage). Normal
use is to call the class with no arguments and use the various
addcounter functions (particularly, for end user's, the use of
addcounterbybrowsing is the most common approach) You might
want to provide the list directly if you want to hard-code the
elements with which your query deals (and thereby avoid the
overhead of unpickling the class).
"""
self.volatilecounters = []
BaseQuery.__init__(*(self,) + args, **namedargs)
def addperfcounter(self, object, counter, machine=None):
"""
A "Performance Counter" is a stable, known, common counter,
such as Memory, or Processor. The use of addperfcounter by
end-users is deprecated, since the use of
addcounterbybrowsing is considerably more flexible and general.
It is provided here to allow the easy development of scripts
which need to access variables so common we know them by name
(such as Memory|Available Bytes), and to provide symmetry with
the add inst counter method.
usage:
query.addperfcounter('Memory', 'Available Bytes')
It is just as easy to access addcounter directly, the following
has an identicle effect.
query.addcounter('Memory', 'Available Bytes')
"""
BaseQuery.addcounter(self, object=object, counter=counter, machine=machine)
def addinstcounter(
self,
object,
counter,
machine=None,
objtype="Process",
volatile=1,
format=win32pdh.PDH_FMT_LONG,
):
"""
The purpose of using an instcounter is to track particular
instances of a counter object (e.g. a single processor, a single
running copy of a process). For instance, to track all python.exe
instances, you would need merely to ask:
query.addinstcounter('python','Virtual Bytes')
You can find the names of the objects and their available counters
by doing an addcounterbybrowsing() call on a query object (or by
looking in performance monitor's add dialog.)
Beyond merely rearranging the call arguments to make more sense,
if the volatile flag is true, the instcounters also recalculate
the paths of the available instances on every call to open the
query.
"""
if volatile:
self.volatilecounters.append((object, counter, machine, objtype, format))
else:
self.paths[len(self.paths) :] = self.getinstpaths(
object, counter, machine, objtype, format
)
def getinstpaths(
self,
object,
counter,
machine=None,
objtype="Process",
format=win32pdh.PDH_FMT_LONG,
):
"""
### Not an end-user function
Calculate the paths for an instance object. Should alter
to allow processing for lists of object-counter pairs.
"""
items, instances = win32pdh.EnumObjectItems(None, None, objtype, -1)
# find out how many instances of this element we have...
instances.sort()
try:
cur = instances.index(object)
except ValueError:
return [] # no instances of this object
temp = [object]
try:
while instances[cur + 1] == object:
temp.append(object)
cur += 1
except IndexError: # if we went over the end
pass
paths = []
for ind in range(len(temp)):
# can this raise an error?
paths.append(
win32pdh.MakeCounterPath(
(machine, "Process", object, None, ind, counter)
)
)
return paths # should also return the number of elements for naming purposes
def open(self, *args, **namedargs):
"""
Explicitly open a query:
When you are needing to make multiple calls to the same query,
it is most efficient to open the query, run all of the calls,
then close the query, instead of having the collectdata method
automatically open and close the query each time it runs.
There are currently no arguments to open.
"""
# do all the normal opening stuff, self._base is now the query object
BaseQuery.open(*(self,) + args, **namedargs)
# should rewrite getinstpaths to take a single tuple
paths = []
for tup in self.volatilecounters:
paths[len(paths) :] = self.getinstpaths(*tup)
for path in paths:
try:
self.counters.append(win32pdh.AddCounter(self._base, path))
self.curpaths.append(
path
) # if we fail on the line above, this path won't be in the table or the counters
except win32api.error:
pass # again, what to do with a malformed path???
def collectdatafor(self, totalperiod, period=1):
"""
Non-threaded collection of performance data:
This method allows you to specify the total period for which you would
like to run the Query, and the time interval between individual
runs. The collected data is stored in query.curresults at the
_end_ of the run. The pathnames for the query are stored in
query.curpaths.
e.g.:
query.collectdatafor(30,2)
Will collect data for 30seconds at 2 second intervals
"""
tempresults = []
try:
self.open()
for ind in range(int(totalperiod / period)):
tempresults.append(self.collectdata())
time.sleep(period)
self.curresults = tempresults
finally:
self.close()
def collectdatawhile(self, period=1):
"""
Threaded collection of performance data:
This method sets up a simple semaphore system for signalling
when you would like to start and stop a threaded data collection
method. The collection runs every period seconds until the
semaphore attribute is set to a non-true value (which normally
should be done by calling query.collectdatawhile_stop() .)
e.g.:
query.collectdatawhile(2)
# starts the query running, returns control to the caller immediately
# is collecting data every two seconds.
# do whatever you want to do while the thread runs, then call:
query.collectdatawhile_stop()
# when you want to deal with the data. It is generally a good idea
# to sleep for period seconds yourself, since the query will not copy
# the required data until the next iteration:
time.sleep(2)
# now you can access the data from the attributes of the query
query.curresults
query.curpaths
"""
self.collectdatawhile_active = 1
_thread.start_new_thread(self.collectdatawhile_slave, (period,))
def collectdatawhile_stop(self):
"""
Signals the collectdatawhile slave thread to stop collecting data
on the next logging iteration.
"""
self.collectdatawhile_active = 0
def collectdatawhile_slave(self, period):
"""
### Not a public function
Does the threaded work of collecting the data and storing it
in an attribute of the class.
"""
tempresults = []
try:
self.open() # also sets active, so can't be changed.
while self.collectdatawhile_active:
tempresults.append(self.collectdata())
time.sleep(period)
self.curresults = tempresults
finally:
self.close()
# pickle functions
def __getinitargs__(self):
return (self.paths,)
def __getstate__(self):
return self.volatilecounters
def __setstate__(self, volatilecounters):
self.volatilecounters = volatilecounters
class QueryError(Exception):
def __init__(self, query: BaseQuery):
self.query = query
def __repr__(self):
return f"<Query Error in {self.query!r}>"
__str__ = __repr__

View File

@@ -0,0 +1,212 @@
"""Utilities for the win32 Performance Data Helper module
Example:
To get a single bit of data:
>>> import win32pdhutil
>>> win32pdhutil.GetPerformanceAttributes("Memory", "Available Bytes")
6053888
>>> win32pdhutil.FindPerformanceAttributesByName("python", counter="Virtual Bytes")
[22278144]
First example returns data which is not associated with any specific instance.
The second example reads data for a specific instance - hence the list return -
it would return one result for each instance of Python running.
In general, it can be tricky finding exactly the "name" of the data you wish to query.
Although you can use <om win32pdh.EnumObjectItems>(None,None,(eg)"Memory", -1) to do this,
the easiest way is often to simply use PerfMon to find out the names.
"""
from __future__ import annotations
import time
import win32pdh
error = win32pdh.error # Re-exported alias
# Handle some localization issues.
# see https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/287159
# Build a map of english_counter_name: counter_id
counter_english_map: dict[str, int] = {}
def find_pdh_counter_localized_name(english_name, machine_name=None):
if not counter_english_map:
import win32api
import win32con
counter_reg_value = win32api.RegQueryValueEx(
win32con.HKEY_PERFORMANCE_DATA, "Counter 009"
)
counter_list = counter_reg_value[0]
for i in range(0, len(counter_list) - 1, 2):
try:
counter_id = int(counter_list[i])
except ValueError:
continue
counter_english_map[counter_list[i + 1].lower()] = counter_id
return win32pdh.LookupPerfNameByIndex(
machine_name, counter_english_map[english_name.lower()]
)
def GetPerformanceAttributes(
object, counter, instance=None, inum=-1, format=win32pdh.PDH_FMT_LONG, machine=None
):
# NOTE: Many counters require 2 samples to give accurate results,
# including "% Processor Time" (as by definition, at any instant, a
# thread's CPU usage is either 0 or 100). To read counters like this,
# you should copy this function, but keep the counter open, and call
# CollectQueryData() each time you need to know.
# See https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/262938
# and https://web.archive.org/web/20040926105842/http://msdn.microsoft.com:80/library/en-us/dnperfmo/html/perfmonpt2.asp
# My older explanation for this was that the "AddCounter" process forced
# the CPU to 100%, but the above makes more sense :)
path = win32pdh.MakeCounterPath((machine, object, instance, None, inum, counter))
hq = win32pdh.OpenQuery()
try:
hc = win32pdh.AddCounter(hq, path)
try:
win32pdh.CollectQueryData(hq)
type, val = win32pdh.GetFormattedCounterValue(hc, format)
return val
finally:
win32pdh.RemoveCounter(hc)
finally:
win32pdh.CloseQuery(hq)
def FindPerformanceAttributesByName(
instanceName,
object=None,
counter=None,
format=win32pdh.PDH_FMT_LONG,
machine=None,
bRefresh=0,
):
"""Find performance attributes by (case insensitive) instance name.
Given a process name, return a list with the requested attributes.
Most useful for returning a tuple of PIDs given a process name.
"""
if object is None:
object = find_pdh_counter_localized_name("Process", machine)
if counter is None:
counter = find_pdh_counter_localized_name("ID Process", machine)
if bRefresh: # PDH docs say this is how you do a refresh.
win32pdh.EnumObjects(None, machine, 0, 1)
instanceName = instanceName.lower()
items, instances = win32pdh.EnumObjectItems(None, None, object, -1)
# Track multiple instances.
instance_dict = {}
for instance in instances:
try:
instance_dict[instance] += 1
except KeyError:
instance_dict[instance] = 0
ret = []
for instance, max_instances in instance_dict.items():
for inum in range(max_instances + 1):
if instance.lower() == instanceName:
ret.append(
GetPerformanceAttributes(
object, counter, instance, inum, format, machine
)
)
return ret
def ShowAllProcesses():
object = find_pdh_counter_localized_name("Process")
items, instances = win32pdh.EnumObjectItems(
None, None, object, win32pdh.PERF_DETAIL_WIZARD
)
# Need to track multiple instances of the same name.
instance_dict = {}
for instance in instances:
try:
instance_dict[instance] += 1
except KeyError:
instance_dict[instance] = 0
# Bit of a hack to get useful info.
items = [find_pdh_counter_localized_name("ID Process")] + items[:5]
print("Process Name", ",".join(items))
for instance, max_instances in instance_dict.items():
for inum in range(max_instances + 1):
hq = win32pdh.OpenQuery()
hcs = []
for item in items:
path = win32pdh.MakeCounterPath(
(None, object, instance, None, inum, item)
)
hcs.append(win32pdh.AddCounter(hq, path))
win32pdh.CollectQueryData(hq)
# as per https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/262938
# some "%" based counters need two collections
time.sleep(0.01)
win32pdh.CollectQueryData(hq)
print("%-15s\t" % (instance[:15]), end=" ")
for hc in hcs:
type, val = win32pdh.GetFormattedCounterValue(hc, win32pdh.PDH_FMT_LONG)
print("%5d" % (val), end=" ")
win32pdh.RemoveCounter(hc)
print()
win32pdh.CloseQuery(hq)
# NOTE: This BrowseCallback doesn't seem to work on Vista for markh.
# XXX - look at why!?
# Some counters on Vista require elevation, and callback would previously
# clear exceptions without printing them.
def BrowseCallBackDemo(counters):
## BrowseCounters can now return multiple counter paths
for counter in counters:
(
machine,
object,
instance,
parentInstance,
index,
counterName,
) = win32pdh.ParseCounterPath(counter)
result = GetPerformanceAttributes(
object, counterName, instance, index, win32pdh.PDH_FMT_DOUBLE, machine
)
print("Value of '%s' is" % counter, result)
print(
"Added '%s' on object '%s' (machine %s), instance %s(%d)-parent of %s"
% (counterName, object, machine, instance, index, parentInstance)
)
return 0
def browse(
callback=BrowseCallBackDemo,
title="Python Browser",
level=win32pdh.PERF_DETAIL_WIZARD,
):
win32pdh.BrowseCounters(None, 0, callback, level, title, ReturnMultiple=True)
if __name__ == "__main__":
ShowAllProcesses()
# Show how to get a couple of attributes by name.
counter = find_pdh_counter_localized_name("Virtual Bytes")
print(
"Virtual Bytes = ", FindPerformanceAttributesByName("python", counter=counter)
)
print(
"Available Bytes = ",
GetPerformanceAttributes(
find_pdh_counter_localized_name("Memory"),
find_pdh_counter_localized_name("Available Bytes"),
),
)
# And a browser.
print("Browsing for counters...")
browse()

View File

@@ -0,0 +1,674 @@
# Windows dialog .RC file parser, by Adam Walker.
# This module was adapted from the spambayes project, and is Copyright
# 2003/2004 The Python Software Foundation and is covered by the Python
# Software Foundation license.
"""
This is a parser for Windows .rc files, which are text files which define
dialogs and other Windows UI resources.
"""
from __future__ import annotations
import os
import pprint
import shlex
import stat
import sys
import commctrl
import win32con
__author__ = "Adam Walker"
__version__ = "0.11"
_controlMap = {
"DEFPUSHBUTTON": 0x80,
"PUSHBUTTON": 0x80,
"Button": 0x80,
"GROUPBOX": 0x80,
"Static": 0x82,
"CTEXT": 0x82,
"RTEXT": 0x82,
"LTEXT": 0x82,
"LISTBOX": 0x83,
"SCROLLBAR": 0x84,
"COMBOBOX": 0x85,
"EDITTEXT": 0x81,
"ICON": 0x82,
"RICHEDIT": "RichEdit20A",
}
# These are "default styles" for certain controls - ie, Visual Studio assumes
# the styles will be applied, and emits a "NOT {STYLE_NAME}" if it is to be
# disabled. These defaults have been determined by experimentation, so may
# not be completely accurate (most notably, some styles and/or control-types
# may be missing.
_addDefaults = {
"EDITTEXT": win32con.WS_BORDER | win32con.WS_TABSTOP,
"GROUPBOX": win32con.BS_GROUPBOX,
"LTEXT": win32con.SS_LEFT,
"DEFPUSHBUTTON": win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP,
"PUSHBUTTON": win32con.WS_TABSTOP,
"CTEXT": win32con.SS_CENTER,
"RTEXT": win32con.SS_RIGHT,
"ICON": win32con.SS_ICON,
"LISTBOX": win32con.LBS_NOTIFY,
}
defaultControlStyle = win32con.WS_CHILD | win32con.WS_VISIBLE
defaultControlStyleEx = 0
class DialogDef:
name = ""
id = 0
style = 0
styleEx = None
caption = ""
font = "MS Sans Serif"
fontSize = 8
x = 0
y = 0
w = 0
h = 0
template = None
def __init__(self, n, i):
self.name = n
self.id = i
self.styles = []
self.stylesEx = []
self.controls = []
# print("dialog def for ", self.name, self.id)
def createDialogTemplate(self):
t = None
self.template = [
[
self.caption,
(self.x, self.y, self.w, self.h),
self.style,
self.styleEx,
(self.fontSize, self.font),
]
]
# Add the controls
for control in self.controls:
self.template.append(control.createDialogTemplate())
return self.template
class ControlDef:
id = ""
controlType = ""
subType = ""
idNum = 0
style = defaultControlStyle
styleEx = defaultControlStyleEx
label = ""
x = 0
y = 0
w = 0
h = 0
def __init__(self):
self.styles = []
self.stylesEx = []
def toString(self):
s = (
"<Control id:"
+ self.id
+ " controlType:"
+ self.controlType
+ " subType:"
+ self.subType
+ " idNum:"
+ str(self.idNum)
+ " style:"
+ str(self.style)
+ " styles:"
+ str(self.styles)
+ " label:"
+ self.label
+ " x:"
+ str(self.x)
+ " y:"
+ str(self.y)
+ " w:"
+ str(self.w)
+ " h:"
+ str(self.h)
+ ">"
)
return s
def createDialogTemplate(self):
ct = self.controlType
if "CONTROL" == ct:
ct = self.subType
if ct in _controlMap:
ct = _controlMap[ct]
t = [
ct,
self.label,
self.idNum,
(self.x, self.y, self.w, self.h),
self.style,
self.styleEx,
]
# print(t)
return t
class StringDef:
def __init__(self, id, idNum, value):
self.id = id
self.idNum = idNum
self.value = value
def __repr__(self):
return f"StringDef({self.id!r}, {self.idNum!r}, {self.value!r})"
class RCParser:
next_id = 1001
dialogs: dict[str, list[list[str | int | None | tuple[str | int, ...]]]] = {}
_dialogs: dict[str, DialogDef] = {}
debugEnabled = False
token = ""
def __init__(self):
self.ungot = False
self.ids = {"IDC_STATIC": -1}
self.names = {-1: "IDC_STATIC"}
self.bitmaps = {}
self.stringTable = {}
self.icons = {}
def debug(self, *args):
if self.debugEnabled:
print(args)
def getToken(self):
if self.ungot:
self.ungot = False
self.debug("getToken returns (ungot):", self.token)
return self.token
self.token = self.lex.get_token()
self.debug("getToken returns:", self.token)
if self.token == "":
self.token = None
return self.token
def ungetToken(self):
self.ungot = True
def getCheckToken(self, expected):
tok = self.getToken()
assert tok == expected, f"Expected token '{expected}', but got token '{tok}'!"
return tok
def getCommaToken(self):
return self.getCheckToken(",")
# Return the *current* token as a number, only consuming a token
# if it is the negative-sign.
def currentNumberToken(self):
mult = 1
if self.token == "-":
mult = -1
self.getToken()
return int(self.token) * mult
# Return the *current* token as a string literal (ie, self.token will be a
# quote. consumes all tokens until the end of the string
def currentQuotedString(self):
# Handle quoted strings - pity shlex doesn't handle it.
assert self.token.startswith('"'), self.token
bits = [self.token]
while 1:
tok = self.getToken()
if not tok.startswith('"'):
self.ungetToken()
break
bits.append(tok)
sval = "".join(bits)[1:-1] # Remove end quotes.
# Fixup quotes in the body, and all (some?) quoted characters back
# to their raw value.
for i, o in ('""', '"'), ("\\r", "\r"), ("\\n", "\n"), ("\\t", "\t"):
sval = sval.replace(i, o)
return sval
def load(self, rcstream):
"""
RCParser.loadDialogs(rcFileName) -> None
Load the dialog information into the parser. Dialog Definations can then be accessed
using the "dialogs" dictionary member (name->DialogDef). The "ids" member contains the dictionary of id->name.
The "names" member contains the dictionary of name->id
"""
self.open(rcstream)
self.getToken()
while self.token is not None:
self.parse()
self.getToken()
def open(self, rcstream):
self.lex = shlex.shlex(rcstream)
self.lex.commenters = "//#"
def parseH(self, file):
lex = shlex.shlex(file)
lex.commenters = "//"
token = " "
while token is not None:
token = lex.get_token()
if token == "" or token is None:
token = None
else:
if token == "define":
n = lex.get_token()
i = int(lex.get_token())
self.ids[n] = i
if i in self.names:
# Dupe ID really isn't a problem - most consumers
# want to go from name->id, and this is OK.
# It means you can't go from id->name though.
pass
# ignore AppStudio special ones
# if not n.startswith("_APS_"):
# print("Duplicate id", i, "for", n, "is", self.names[i])
else:
self.names[i] = n
if self.next_id <= i:
self.next_id = i + 1
def parse(self):
noid_parsers = {
"STRINGTABLE": self.parse_stringtable,
}
id_parsers = {
"DIALOG": self.parse_dialog,
"DIALOGEX": self.parse_dialog,
# "TEXTINCLUDE": self.parse_textinclude,
"BITMAP": self.parse_bitmap,
"ICON": self.parse_icon,
}
deep = 0
base_token = self.token
rp = noid_parsers.get(base_token)
if rp is not None:
rp()
else:
# Not something we parse that isn't prefixed by an ID
# See if it is an ID prefixed item - if it is, our token
# is the resource ID.
resource_id = self.token
self.getToken()
if self.token is None:
return
if "BEGIN" == self.token:
# A 'BEGIN' for a structure we don't understand - skip to the
# matching 'END'
deep = 1
while deep != 0 and self.token is not None:
self.getToken()
self.debug("Zooming over", self.token)
if "BEGIN" == self.token:
deep += 1
elif "END" == self.token:
deep -= 1
else:
rp = id_parsers.get(self.token)
if rp is not None:
self.debug(f"Dispatching '{self.token}'")
rp(resource_id)
else:
# We don't know what the resource type is, but we
# have already consumed the next, which can cause problems,
# so push it back.
self.debug("Skipping top-level '%s'" % base_token)
self.ungetToken()
def addId(self, id_name):
if id_name in self.ids:
id = self.ids[id_name]
else:
# IDOK, IDCANCEL etc are special - if a real resource has this value
for n in ["IDOK", "IDCANCEL", "IDYES", "IDNO", "IDABORT"]:
if id_name == n:
v = getattr(win32con, n)
self.ids[n] = v
self.names[v] = n
return v
id = self.next_id
self.next_id += 1
self.ids[id_name] = id
self.names[id] = id_name
return id
def lang(self):
while (
self.token[0:4] == "LANG"
or self.token[0:7] == "SUBLANG"
or self.token == ","
):
self.getToken()
def parse_textinclude(self, res_id):
while self.getToken() != "BEGIN":
pass
while 1:
if self.token == "END":
break
s = self.getToken()
def parse_stringtable(self):
while self.getToken() != "BEGIN":
pass
while 1:
self.getToken()
if self.token == "END":
break
sid = self.token
self.getToken()
sd = StringDef(sid, self.addId(sid), self.currentQuotedString())
self.stringTable[sid] = sd
def parse_bitmap(self, name):
return self.parse_bitmap_or_icon(name, self.bitmaps)
def parse_icon(self, name):
return self.parse_bitmap_or_icon(name, self.icons)
def parse_bitmap_or_icon(self, name, dic):
self.getToken()
while not self.token.startswith('"'):
self.getToken()
bmf = self.token[1:-1] # quotes
dic[name] = bmf
def parse_dialog(self, name):
dlg = DialogDef(name, self.addId(name))
assert len(dlg.controls) == 0
self._dialogs[name] = dlg
extras = []
self.getToken()
while not self.token.isdigit():
self.debug("extra", self.token)
extras.append(self.token)
self.getToken()
dlg.x = int(self.token)
self.getCommaToken()
self.getToken() # number
dlg.y = int(self.token)
self.getCommaToken()
self.getToken() # number
dlg.w = int(self.token)
self.getCommaToken()
self.getToken() # number
dlg.h = int(self.token)
self.getToken()
while not (self.token is None or self.token == "" or self.token == "END"):
if self.token == "STYLE":
self.dialogStyle(dlg)
elif self.token == "EXSTYLE":
self.dialogExStyle(dlg)
elif self.token == "CAPTION":
self.dialogCaption(dlg)
elif self.token == "FONT":
self.dialogFont(dlg)
elif self.token == "BEGIN":
self.controls(dlg)
else:
break
self.dialogs[name] = dlg.createDialogTemplate()
def dialogStyle(self, dlg):
dlg.style, dlg.styles = self.styles([], win32con.DS_SETFONT)
def dialogExStyle(self, dlg):
self.getToken()
dlg.styleEx, dlg.stylesEx = self.styles([], 0)
def styles(self, defaults, defaultStyle):
list = defaults
style = defaultStyle
if "STYLE" == self.token:
self.getToken()
i = 0
Not = False
while (
(i % 2 == 1 and ("|" == self.token or "NOT" == self.token)) or (i % 2 == 0)
) and not self.token is None:
Not = False
if "NOT" == self.token:
Not = True
self.getToken()
i += 1
if self.token != "|":
if self.token in win32con.__dict__:
value = getattr(win32con, self.token)
else:
if self.token in commctrl.__dict__:
value = getattr(commctrl, self.token)
else:
value = 0
if Not:
list.append("NOT " + self.token)
self.debug("styles add Not", self.token, value)
style &= ~value
else:
list.append(self.token)
self.debug("styles add", self.token, value)
style |= value
self.getToken()
self.debug("style is ", style)
return style, list
def dialogCaption(self, dlg):
if "CAPTION" == self.token:
self.getToken()
self.token = self.token[1:-1]
self.debug("Caption is:", self.token)
dlg.caption = self.token
self.getToken()
def dialogFont(self, dlg):
if "FONT" == self.token:
self.getToken()
dlg.fontSize = int(self.token)
self.getCommaToken()
self.getToken() # Font name
dlg.font = self.token[1:-1] # it's quoted
self.getToken()
while "BEGIN" != self.token:
self.getToken()
def controls(self, dlg):
if self.token == "BEGIN":
self.getToken()
# All controls look vaguely like:
# TYPE [text, ] Control_id, l, t, r, b [, style]
# .rc parser documents all control types as:
# CHECKBOX, COMBOBOX, CONTROL, CTEXT, DEFPUSHBUTTON, EDITTEXT, GROUPBOX,
# ICON, LISTBOX, LTEXT, PUSHBUTTON, RADIOBUTTON, RTEXT, SCROLLBAR
without_text = ["EDITTEXT", "COMBOBOX", "LISTBOX", "SCROLLBAR"]
while self.token != "END":
control = ControlDef()
control.controlType = self.token
self.getToken()
if control.controlType not in without_text:
if self.token[0:1] == '"':
control.label = self.currentQuotedString()
# Some funny controls, like icons and picture controls use
# the "window text" as extra resource ID (ie, the ID of the
# icon itself). This may be either a literal, or an ID string.
elif self.token == "-" or self.token.isdigit():
control.label = str(self.currentNumberToken())
else:
# An ID - use the numeric equiv.
control.label = str(self.addId(self.token))
self.getCommaToken()
self.getToken()
# Control IDs may be "names" or literal ints
if self.token == "-" or self.token.isdigit():
control.id = self.currentNumberToken()
control.idNum = control.id
else:
# name of an ID
control.id = self.token
control.idNum = self.addId(control.id)
self.getCommaToken()
if control.controlType == "CONTROL":
self.getToken()
control.subType = self.token[1:-1]
thisDefaultStyle = defaultControlStyle | _addDefaults.get(
control.subType, 0
)
# Styles
self.getCommaToken()
self.getToken()
control.style, control.styles = self.styles([], thisDefaultStyle)
else:
thisDefaultStyle = defaultControlStyle | _addDefaults.get(
control.controlType, 0
)
# incase no style is specified.
control.style = thisDefaultStyle
# Rect
control.x = int(self.getToken())
self.getCommaToken()
control.y = int(self.getToken())
self.getCommaToken()
control.w = int(self.getToken())
self.getCommaToken()
self.getToken()
control.h = int(self.token)
self.getToken()
if self.token == ",":
self.getToken()
control.style, control.styles = self.styles([], thisDefaultStyle)
if self.token == ",":
self.getToken()
control.styleEx, control.stylesEx = self.styles(
[], defaultControlStyleEx
)
# print(control.toString())
dlg.controls.append(control)
def ParseStreams(rc_file, h_file):
rcp = RCParser()
if h_file:
rcp.parseH(h_file)
try:
rcp.load(rc_file)
except:
lex = getattr(rcp, "lex", None)
if lex:
print("ERROR parsing dialogs at line", lex.lineno)
print("Next 10 tokens are:")
for i in range(10):
print(lex.get_token(), end=" ")
print()
raise
return rcp
def Parse(rc_name, h_name=None):
if h_name:
h_file = open(h_name, "r")
else:
# See if same basename as the .rc
h_name = rc_name[:-2] + "h"
try:
h_file = open(h_name, "r")
except OSError:
# See if MSVC default of 'resource.h' in the same dir.
h_name = os.path.join(os.path.dirname(rc_name), "resource.h")
try:
h_file = open(h_name, "r")
except OSError:
# .h files are optional anyway
h_file = None
rc_file = open(rc_name, "r")
try:
return ParseStreams(rc_file, h_file)
finally:
if h_file is not None:
h_file.close()
rc_file.close()
def GenerateFrozenResource(rc_name, output_name, h_name=None):
"""Converts an .rc windows resource source file into a python source file
with the same basic public interface as the rest of this module.
Particularly useful for py2exe or other 'freeze' type solutions,
where a frozen .py file can be used inplace of a real .rc file.
"""
rcp = Parse(rc_name, h_name)
in_stat = os.stat(rc_name)
out = open(output_name, "wt")
out.write("#%s\n" % output_name)
out.write("#This is a generated file. Please edit %s instead.\n" % rc_name)
out.write("__version__=%r\n" % __version__)
out.write(
"_rc_size_=%d\n_rc_mtime_=%d\n"
% (in_stat[stat.ST_SIZE], in_stat[stat.ST_MTIME])
)
out.write("class StringDef:\n")
out.write("\tdef __init__(self, id, idNum, value):\n")
out.write("\t\tself.id = id\n")
out.write("\t\tself.idNum = idNum\n")
out.write("\t\tself.value = value\n")
out.write("\tdef __repr__(self):\n")
out.write(
'\t\treturn "StringDef(%r, %r, %r)" % (self.id, self.idNum, self.value)\n'
)
out.write("class FakeParser:\n")
for name in "dialogs", "ids", "names", "bitmaps", "icons", "stringTable":
out.write(f"\t{name} = \\\n")
pprint.pprint(getattr(rcp, name), out)
out.write("\n")
out.write("def Parse(s):\n")
out.write("\treturn FakeParser()\n")
out.close()
if __name__ == "__main__":
if len(sys.argv) <= 1:
print(__doc__)
print()
print("See test_win32rcparser.py, and the win32rcparser directory (both")
print("in the test suite) for an example of this module's usage.")
else:
filename = sys.argv[1]
if "-v" in sys.argv:
RCParser.debugEnabled = True
print("Dumping all resources in '%s'" % filename)
resources = Parse(filename)
for id, ddef in resources.dialogs.items():
print("Dialog %s (%d controls)" % (id, len(ddef)))
pprint.pprint(ddef)
print()
for id, sdef in resources.stringTable.items():
print(f"String {id}={sdef.value!r}")
print()
for id, sdef in resources.bitmaps.items():
print(f"Bitmap {id}={sdef!r}")
print()
for id, sdef in resources.icons.items():
print(f"Icon {id}={sdef!r}")
print()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
# This is a helper for the win32trace module
# If imported from a normal Python program, it sets up sys.stdout and sys.stderr
# so output goes to the collector.
# If run from the command line, it creates a collector loop.
# Eg:
# C:>start win32traceutil.py (or python.exe win32traceutil.py)
# will start a process with a (pretty much) blank screen.
#
# then, switch to a DOS prompt, and type:
# C:>python.exe
# Python X.X.X (#0, Apr 13 1999, ...
# >>> import win32traceutil
# Redirecting output to win32trace remote collector
# >>> print("Hello")
# >>>
# And the output will appear in the first collector process.
# Note - the client or the collector can be started first.
# There is a 0x20000 byte buffer. If this gets full, it is reset, and new
# output appended from the start.
import win32trace
def RunAsCollector():
import sys
try:
import win32api
win32api.SetConsoleTitle("Python Trace Collector")
except:
pass # Oh well!
win32trace.InitRead()
print("Collecting Python Trace Output...")
try:
while 1:
# a short timeout means ctrl+c works next time we wake...
sys.stdout.write(win32trace.blockingread(500))
except KeyboardInterrupt:
print("Ctrl+C")
def SetupForPrint():
win32trace.InitWrite()
try: # Under certain servers, sys.stdout may be invalid.
print("Redirecting output to win32trace remote collector")
except:
pass
win32trace.setprint() # this works in an rexec environment.
if __name__ == "__main__":
RunAsCollector()
else:
SetupForPrint()

View File

@@ -0,0 +1,235 @@
"""Stamp a Win32 binary with version information."""
import glob
import optparse
import os
import struct
from _win32verstamp_pywin32ctypes import (
BeginUpdateResource,
EndUpdateResource,
UpdateResource,
)
VS_FFI_SIGNATURE = -17890115 # 0xFEEF04BD
VS_FFI_STRUCVERSION = 0x00010000
VS_FFI_FILEFLAGSMASK = 0x0000003F
VOS_NT_WINDOWS32 = 0x00040004
null_byte = b"\0"
#
# Set VS_FF_PRERELEASE and DEBUG if Debug
#
def file_flags(debug):
if debug:
return 3 # VS_FF_DEBUG | VS_FF_PRERELEASE
return 0
def file_type(is_dll):
if is_dll:
return 2 # VFT_DLL
return 1 # VFT_APP
def VS_FIXEDFILEINFO(maj, min, sub, build, debug=0, is_dll=1):
return struct.pack(
"lllllllllllll",
VS_FFI_SIGNATURE, # dwSignature
VS_FFI_STRUCVERSION, # dwStrucVersion
(maj << 16) | min, # dwFileVersionMS
(sub << 16) | build, # dwFileVersionLS
(maj << 16) | min, # dwProductVersionMS
(sub << 16) | build, # dwProductVersionLS
VS_FFI_FILEFLAGSMASK, # dwFileFlagsMask
file_flags(debug), # dwFileFlags
VOS_NT_WINDOWS32, # dwFileOS
file_type(is_dll), # dwFileType
0x00000000, # dwFileSubtype
0x00000000, # dwFileDateMS
0x00000000, # dwFileDateLS
)
def nullterm(s):
# get raw bytes for a NULL terminated unicode string.
return (str(s) + "\0").encode("utf-16le")
def pad32(s, extra=2):
# extra is normally 2 to deal with wLength
l = 4 - ((len(s) + extra) & 3)
if l < 4:
return s + (null_byte * l)
return s
def addlen(s):
return struct.pack("h", len(s) + 2) + s
def String(key, value):
key = nullterm(key)
value = nullterm(value)
result = struct.pack("hh", len(value) // 2, 1) # wValueLength, wType
result += key
result = pad32(result) + value
return addlen(result)
def StringTable(key, data):
key = nullterm(key)
result = struct.pack("hh", 0, 1) # wValueLength, wType
result += key
for k, v in data.items():
result += String(k, v)
result = pad32(result)
return addlen(result)
def StringFileInfo(data):
result = struct.pack("hh", 0, 1) # wValueLength, wType
result += nullterm("StringFileInfo")
# result = pad32(result) + StringTable('040904b0', data)
result = pad32(result) + StringTable("040904E4", data)
return addlen(result)
def Var(key, value):
result = struct.pack("hh", len(value), 0) # wValueLength, wType
result += nullterm(key)
result = pad32(result) + value
return addlen(result)
def VarFileInfo(data):
result = struct.pack("hh", 0, 1) # wValueLength, wType
result += nullterm("VarFileInfo")
result = pad32(result)
for k, v in data.items():
result += Var(k, v)
return addlen(result)
def VS_VERSION_INFO(maj, min, sub, build, sdata, vdata, debug=0, is_dll=1):
ffi = VS_FIXEDFILEINFO(maj, min, sub, build, debug, is_dll)
result = struct.pack("hh", len(ffi), 0) # wValueLength, wType
result += nullterm("VS_VERSION_INFO")
result = pad32(result) + ffi
result = pad32(result) + StringFileInfo(sdata) + VarFileInfo(vdata)
return addlen(result)
def stamp(pathname, options):
# For some reason, the API functions report success if the file is open
# but doesn't work! Try and open the file for writing, just to see if it is
# likely the stamp will work!
try:
f = open(pathname, "a+b")
f.close()
except OSError as why:
print(f"WARNING: File {pathname} could not be opened - {why}")
ver = options.version
try:
bits = [int(i) for i in ver.split(".")]
vmaj, vmin, vsub, vbuild = bits
except (IndexError, TypeError, ValueError):
raise ValueError("--version must be a.b.c.d (all integers) - got %r" % ver)
ifn = options.internal_name
if not ifn:
ifn = os.path.basename(pathname)
ofn = options.original_filename
if ofn is None:
ofn = os.path.basename(pathname)
sdata = {
"Comments": options.comments,
"CompanyName": options.company,
"FileDescription": options.description,
"FileVersion": ver,
"InternalName": ifn,
"LegalCopyright": options.copyright,
"LegalTrademarks": options.trademarks,
"OriginalFilename": ofn,
"ProductName": options.product,
"ProductVersion": ver,
}
vdata = {
"Translation": struct.pack("hh", 0x409, 1252),
}
is_dll = options.dll
if is_dll is None:
is_dll = os.path.splitext(pathname)[1].lower() in ".dll .pyd".split()
is_debug = options.debug
if is_debug is None:
is_debug = os.path.splitext(pathname)[0].lower().endswith("_d")
# convert None to blank strings
for k, v in sdata.items():
if v is None:
sdata[k] = ""
vs = VS_VERSION_INFO(vmaj, vmin, vsub, vbuild, sdata, vdata, is_debug, is_dll)
h = BeginUpdateResource(pathname, 0)
UpdateResource(h, 16, 1, vs)
EndUpdateResource(h, 0)
if options.verbose:
print("Stamped:", pathname)
if __name__ == "__main__":
parser = optparse.OptionParser("%prog [options] filespec ...", description=__doc__)
parser.add_option(
"-q",
"--quiet",
action="store_false",
dest="verbose",
default=True,
help="don't print status messages to stdout",
)
parser.add_option(
"", "--version", default="0.0.0.0", help="The version number as m.n.s.b"
)
parser.add_option(
"",
"--dll",
help="""Stamp the file as a DLL. Default is to look at the
file extension for .dll or .pyd.""",
)
parser.add_option("", "--debug", help="""Stamp the file as a debug binary.""")
parser.add_option("", "--product", help="""The product name to embed.""")
parser.add_option("", "--company", help="""The company name to embed.""")
parser.add_option("", "--trademarks", help="The trademark string to embed.")
parser.add_option("", "--comments", help="The comments string to embed.")
parser.add_option(
"", "--copyright", help="""The copyright message string to embed."""
)
parser.add_option(
"", "--description", metavar="DESC", help="The description to embed."
)
parser.add_option(
"",
"--internal-name",
metavar="NAME",
help="""The internal filename to embed. If not specified
the base filename is used.""",
)
parser.add_option(
"",
"--original-filename",
help="""The original filename to embed. If not specified
the base filename is used.""",
)
options, args = parser.parse_args()
if not args:
parser.error("You must supply a file to stamp. Use --help for details.")
for g in args:
for f in glob.glob(g):
stamp(f, options)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,236 @@
# Generated by h2py from winperf.h
PERF_DATA_VERSION = 1
PERF_DATA_REVISION = 1
PERF_NO_INSTANCES = -1
PERF_SIZE_DWORD = 0x00000000
PERF_SIZE_LARGE = 0x00000100
PERF_SIZE_ZERO = 0x00000200
PERF_SIZE_VARIABLE_LEN = 0x00000300
PERF_TYPE_NUMBER = 0x00000000
PERF_TYPE_COUNTER = 0x00000400
PERF_TYPE_TEXT = 0x00000800
PERF_TYPE_ZERO = 0x00000C00
PERF_NUMBER_HEX = 0x00000000
PERF_NUMBER_DECIMAL = 0x00010000
PERF_NUMBER_DEC_1000 = 0x00020000
PERF_COUNTER_VALUE = 0x00000000
PERF_COUNTER_RATE = 0x00010000
PERF_COUNTER_FRACTION = 0x00020000
PERF_COUNTER_BASE = 0x00030000
PERF_COUNTER_ELAPSED = 0x00040000
PERF_COUNTER_QUEUELEN = 0x00050000
PERF_COUNTER_HISTOGRAM = 0x00060000
PERF_TEXT_UNICODE = 0x00000000
PERF_TEXT_ASCII = 0x00010000
PERF_TIMER_TICK = 0x00000000
PERF_TIMER_100NS = 0x00100000
PERF_OBJECT_TIMER = 0x00200000
PERF_DELTA_COUNTER = 0x00400000
PERF_DELTA_BASE = 0x00800000
PERF_INVERSE_COUNTER = 0x01000000
PERF_MULTI_COUNTER = 0x02000000
PERF_DISPLAY_NO_SUFFIX = 0x00000000
PERF_DISPLAY_PER_SEC = 0x10000000
PERF_DISPLAY_PERCENT = 0x20000000
PERF_DISPLAY_SECONDS = 0x30000000
PERF_DISPLAY_NOSHOW = 0x40000000
PERF_COUNTER_COUNTER = (
PERF_SIZE_DWORD
| PERF_TYPE_COUNTER
| PERF_COUNTER_RATE
| PERF_TIMER_TICK
| PERF_DELTA_COUNTER
| PERF_DISPLAY_PER_SEC
)
PERF_COUNTER_TIMER = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_COUNTER_RATE
| PERF_TIMER_TICK
| PERF_DELTA_COUNTER
| PERF_DISPLAY_PERCENT
)
PERF_COUNTER_QUEUELEN_TYPE = (
PERF_SIZE_DWORD
| PERF_TYPE_COUNTER
| PERF_COUNTER_QUEUELEN
| PERF_TIMER_TICK
| PERF_DELTA_COUNTER
| PERF_DISPLAY_NO_SUFFIX
)
PERF_COUNTER_LARGE_QUEUELEN_TYPE = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_COUNTER_QUEUELEN
| PERF_TIMER_TICK
| PERF_DELTA_COUNTER
| PERF_DISPLAY_NO_SUFFIX
)
PERF_COUNTER_BULK_COUNT = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_COUNTER_RATE
| PERF_TIMER_TICK
| PERF_DELTA_COUNTER
| PERF_DISPLAY_PER_SEC
)
PERF_COUNTER_TEXT = (
PERF_SIZE_VARIABLE_LEN | PERF_TYPE_TEXT | PERF_TEXT_UNICODE | PERF_DISPLAY_NO_SUFFIX
)
PERF_COUNTER_RAWCOUNT = (
PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX
)
PERF_COUNTER_LARGE_RAWCOUNT = (
PERF_SIZE_LARGE | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX
)
PERF_COUNTER_RAWCOUNT_HEX = (
PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_HEX | PERF_DISPLAY_NO_SUFFIX
)
PERF_COUNTER_LARGE_RAWCOUNT_HEX = (
PERF_SIZE_LARGE | PERF_TYPE_NUMBER | PERF_NUMBER_HEX | PERF_DISPLAY_NO_SUFFIX
)
PERF_SAMPLE_FRACTION = (
PERF_SIZE_DWORD
| PERF_TYPE_COUNTER
| PERF_COUNTER_FRACTION
| PERF_DELTA_COUNTER
| PERF_DELTA_BASE
| PERF_DISPLAY_PERCENT
)
PERF_SAMPLE_COUNTER = (
PERF_SIZE_DWORD
| PERF_TYPE_COUNTER
| PERF_COUNTER_RATE
| PERF_TIMER_TICK
| PERF_DELTA_COUNTER
| PERF_DISPLAY_NO_SUFFIX
)
PERF_COUNTER_NODATA = PERF_SIZE_ZERO | PERF_DISPLAY_NOSHOW
PERF_COUNTER_TIMER_INV = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_COUNTER_RATE
| PERF_TIMER_TICK
| PERF_DELTA_COUNTER
| PERF_INVERSE_COUNTER
| PERF_DISPLAY_PERCENT
)
PERF_SAMPLE_BASE = (
PERF_SIZE_DWORD
| PERF_TYPE_COUNTER
| PERF_COUNTER_BASE
| PERF_DISPLAY_NOSHOW
| 0x00000001
)
PERF_AVERAGE_TIMER = (
PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_FRACTION | PERF_DISPLAY_SECONDS
)
PERF_AVERAGE_BASE = (
PERF_SIZE_DWORD
| PERF_TYPE_COUNTER
| PERF_COUNTER_BASE
| PERF_DISPLAY_NOSHOW
| 0x00000002
)
PERF_AVERAGE_BULK = (
PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_FRACTION | PERF_DISPLAY_NOSHOW
)
PERF_100NSEC_TIMER = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_COUNTER_RATE
| PERF_TIMER_100NS
| PERF_DELTA_COUNTER
| PERF_DISPLAY_PERCENT
)
PERF_100NSEC_TIMER_INV = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_COUNTER_RATE
| PERF_TIMER_100NS
| PERF_DELTA_COUNTER
| PERF_INVERSE_COUNTER
| PERF_DISPLAY_PERCENT
)
PERF_COUNTER_MULTI_TIMER = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_COUNTER_RATE
| PERF_DELTA_COUNTER
| PERF_TIMER_TICK
| PERF_MULTI_COUNTER
| PERF_DISPLAY_PERCENT
)
PERF_COUNTER_MULTI_TIMER_INV = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_COUNTER_RATE
| PERF_DELTA_COUNTER
| PERF_MULTI_COUNTER
| PERF_TIMER_TICK
| PERF_INVERSE_COUNTER
| PERF_DISPLAY_PERCENT
)
PERF_COUNTER_MULTI_BASE = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_COUNTER_BASE
| PERF_MULTI_COUNTER
| PERF_DISPLAY_NOSHOW
)
PERF_100NSEC_MULTI_TIMER = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_DELTA_COUNTER
| PERF_COUNTER_RATE
| PERF_TIMER_100NS
| PERF_MULTI_COUNTER
| PERF_DISPLAY_PERCENT
)
PERF_100NSEC_MULTI_TIMER_INV = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_DELTA_COUNTER
| PERF_COUNTER_RATE
| PERF_TIMER_100NS
| PERF_MULTI_COUNTER
| PERF_INVERSE_COUNTER
| PERF_DISPLAY_PERCENT
)
PERF_RAW_FRACTION = (
PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_FRACTION | PERF_DISPLAY_PERCENT
)
PERF_RAW_BASE = (
PERF_SIZE_DWORD
| PERF_TYPE_COUNTER
| PERF_COUNTER_BASE
| PERF_DISPLAY_NOSHOW
| 0x00000003
)
PERF_ELAPSED_TIME = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_COUNTER_ELAPSED
| PERF_OBJECT_TIMER
| PERF_DISPLAY_SECONDS
)
PERF_COUNTER_HISTOGRAM_TYPE = -2147483648 # 0x80000000
PERF_COUNTER_DELTA = (
PERF_SIZE_DWORD
| PERF_TYPE_COUNTER
| PERF_COUNTER_VALUE
| PERF_DELTA_COUNTER
| PERF_DISPLAY_NO_SUFFIX
)
PERF_COUNTER_LARGE_DELTA = (
PERF_SIZE_LARGE
| PERF_TYPE_COUNTER
| PERF_COUNTER_VALUE
| PERF_DELTA_COUNTER
| PERF_DISPLAY_NO_SUFFIX
)
PERF_DETAIL_NOVICE = 100
PERF_DETAIL_ADVANCED = 200
PERF_DETAIL_EXPERT = 300
PERF_DETAIL_WIZARD = 400
PERF_NO_UNIQUE_ID = -1

View File

@@ -0,0 +1,8 @@
"""A useful wrapper around the "_winxptheme" module.
Originally used when we couldn't be sure Windows XP apis were going to
be available. In 2022, it's safe to assume they are, so this is just a wrapper
around _winxptheme.
"""
from _winxptheme import * # nopycln: import