Skip to content

Commit

Permalink
Merge pull request #103 from opalmer/enhance_wintypes
Browse files Browse the repository at this point in the history
Enhance pywincffi.wintypes
  • Loading branch information
opalmer authored Jun 27, 2016
2 parents cd13a3f + b6bc41a commit 5163e08
Show file tree
Hide file tree
Showing 13 changed files with 390 additions and 329 deletions.
5 changes: 2 additions & 3 deletions pywincffi/core/typesbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ def __setattr__(self, name, value):
return

# support descriptor attributes in child classes
self_class = type(self)
if hasattr(self_class, name):
if hasattr(self.__class__, name):
try:
# getattr on class, otherwise descriptor's __get__ is called
attr = getattr(self_class, name)
attr = getattr(self.__class__, name)
# use descriptor protocol to set
attr.__set__(self, value)
return
Expand Down
2 changes: 1 addition & 1 deletion pywincffi/kernel32/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
UnlockFileEx)
from pywincffi.kernel32.handle import (
CloseHandle, GetStdHandle, GetHandleInformation, SetHandleInformation,
DuplicateHandle, handle_from_file)
DuplicateHandle)
from pywincffi.kernel32.pipe import (
CreatePipe, PeekNamedPipe, PeekNamedPipeResult, SetNamedPipeHandleState)
from pywincffi.kernel32.process import (
Expand Down
23 changes: 0 additions & 23 deletions pywincffi/kernel32/handle.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,6 @@
INVALID_HANDLE_VALUE = -1


def handle_from_file(python_file):
"""
Given a standard Python file object produce a Windows
handle object that be be used in Windows function calls.
:param file python_file:
The Python file object to convert to a Windows handle.
:return:
Returns a :class:`pywincffi.wintypes.HANDLE` for the provided
``python_file``.
"""
_, library = dist.load()
input_check("python_file", python_file, Enums.PYFILE)

# WARNING:
# Be aware that passing in an invalid file descriptor
# number can crash Python. The input_check function
# above should handle this for us by checking to
# ensure the file descriptor is valid first.
return HANDLE(library.handle_from_fd(python_file.fileno()))


def GetStdHandle(nStdHandle):
"""
Retrieves a handle to the specified standard
Expand Down
133 changes: 4 additions & 129 deletions pywincffi/wintypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,132 +6,7 @@
used across the exposed APIs.
"""


from pywincffi.core import typesbase
from pywincffi.core import dist


# pylint: disable=protected-access
def wintype_to_cdata(wintype):
"""
Returns the underlying CFFI cdata object or ffi.NULL if wintype is None.
Used internally in API wrappers to "convert" pywincffi's Python types to
the required CFFI cdata objects when calling CFFI functions. Example:
>>> from pywincffi.core import dist
>>> from pywincffi.kernel32 import CreateEvent
>>> from pywincffi.wintypes import wintype_to_cdata
>>> ffi, lib = dist.load()
>>> # Get an event HANDLE, using the wrapper: it's a Python HANDLE object.
>>> hEvent = CreateEvent(False, False)
>>> # Call ResetEvent directly without going through the wrapper:
>>> hEvent_cdata = wintype_to_cdata(hEvent)
>>> result = lib.ResetEvent(hEvent_cdata)
:param wintype:
A type derived from :class:`pywincffi.core.typesbase.CFFICDataWrapper`
:return:
The underlying CFFI <cdata> object, or ffi.NULL if wintype is None.
"""
ffi, _ = dist.load()
if wintype is None:
return ffi.NULL
elif isinstance(wintype, HANDLE):
return wintype._cdata[0]
else:
return wintype._cdata


# pylint: disable=too-few-public-methods
class HANDLE(typesbase.CFFICDataWrapper):
"""
.. seealso::
https://msdn.microsoft.com/en-us/library/aa383751
"""
def __init__(self, data=None):
ffi, _ = dist.load()
super(HANDLE, self).__init__("HANDLE[1]", ffi)
# Initialize from a <cdata handle> object as returned by some
# Windows API library calls: Python AND FFI types must be equal.
if isinstance(data, type(self._cdata[0])):
if ffi.typeof(data) == ffi.typeof(self._cdata[0]):
self._cdata[0] = data

def __repr__(self):
ffi, _ = dist.load()
return "<HANDLE 0x%x at 0x%x>" % (
int(ffi.cast("intptr_t", self._cdata[0])),
id(self)
)

def __eq__(self, other):
if not isinstance(other, HANDLE):
raise TypeError("%r must be a HANDLE" % other)
return self._cdata[0] == other._cdata[0]


# pylint: disable=invalid-name
class SECURITY_ATTRIBUTES(typesbase.CFFICDataWrapper):
"""
.. seealso::
https://msdn.microsoft.com/en-us/library/aa379560
"""
def __init__(self):
ffi, _ = dist.load()
super(SECURITY_ATTRIBUTES, self).__init__(
"SECURITY_ATTRIBUTES*",
ffi,
)
self._cdata.nLength = ffi.sizeof(self._cdata)
self.lpSecurityDescriptor = ffi.NULL

# pylint: disable=missing-docstring
@property
def nLength(self):
return self._cdata.nLength

# pylint: disable=missing-docstring,no-self-use
@nLength.setter
def nLength(self, _):
# Can't raise AttributeError.
# CFFICDataWrapper would fall back to setting self._cdata.nLength .
raise TypeError("SECURITY_ATTRIBUTES.nLength is read-only")


# pylint: disable=too-few-public-methods
class OVERLAPPED(typesbase.CFFICDataWrapper):
"""
.. seealso::
https://msdn.microsoft.com/en-us/library/ms684342
"""
def __init__(self):
ffi, _ = dist.load()
super(OVERLAPPED, self).__init__("OVERLAPPED*", ffi)

# pylint: disable=missing-docstring
@property
def hEvent(self):
return HANDLE(self._cdata.hEvent)

# pylint: disable=missing-docstring
@hEvent.setter
def hEvent(self, handle):
if not isinstance(handle, HANDLE):
raise TypeError("%r must be a HANDLE" % handle)
self._cdata.hEvent = handle._cdata[0]


# pylint: disable=too-few-public-methods
class FILETIME(typesbase.CFFICDataWrapper):
"""
.. seealso::
https://msdn.microsoft.com/en-us/library/ms724284
"""
def __init__(self):
ffi, _ = dist.load()
super(FILETIME, self).__init__("FILETIME*", ffi)
from pywincffi.wintypes.functions import wintype_to_cdata, handle_from_file
from pywincffi.wintypes.objects import HANDLE
from pywincffi.wintypes.structures import (
SECURITY_ATTRIBUTES, OVERLAPPED, FILETIME)
76 changes: 76 additions & 0 deletions pywincffi/wintypes/functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""
Functions
---------
This module provides various functions for converting and using Windows
types.
"""

from pywincffi.core import dist
from pywincffi.exceptions import InputError
from pywincffi.wintypes.objects import HANDLE


# pylint: disable=protected-access
def wintype_to_cdata(wintype):
"""
Returns the underlying CFFI cdata object or ffi.NULL if wintype is None.
Used internally in API wrappers to "convert" pywincffi's Python types to
the required CFFI cdata objects when calling CFFI functions. Example:
>>> from pywincffi.core import dist
>>> from pywincffi.kernel32 import CreateEvent
>>> from pywincffi.wintypes import wintype_to_cdata
>>> ffi, lib = dist.load()
>>> # Get an event HANDLE, using the wrapper: it's a Python HANDLE object.
>>> hEvent = CreateEvent(False, False)
>>> # Call ResetEvent directly without going through the wrapper:
>>> hEvent_cdata = wintype_to_cdata(hEvent)
>>> result = lib.ResetEvent(hEvent_cdata)
:param wintype:
A type derived from :class:`pywincffi.core.typesbase.CFFICDataWrapper`
:return:
The underlying CFFI <cdata> object, or ffi.NULL if wintype is None.
"""
ffi, _ = dist.load()
if wintype is None:
return ffi.NULL
elif isinstance(wintype, HANDLE):
return wintype._cdata[0]
else:
return wintype._cdata


def handle_from_file(file_):
"""
Converts a standard Python file object into a :class:`HANDLE` object.
.. warning::
This function is mainly intended for internal use. Passing in a file
object with an invalid file descriptor may crash your interpreter.
:param file file_:
The Python file object to convert to a :class:`HANDLE` object.
:raises InputError:
Raised if ``file_`` does not appear to be a file object or is currently
closed.
:rtype: :class:`HANDLE`
"""
try:
fileno = file_.fileno()
except AttributeError:
raise InputError(
"file_", file_, expected_types=None,
message="Expected a file like object for `file_`")
except ValueError:
raise InputError(
"file_", file_, expected_types=None,
message="Expected an open file like object for `file_`")
else:
_, library = dist.load()
return HANDLE(library.handle_from_fd(fileno))
48 changes: 48 additions & 0 deletions pywincffi/wintypes/objects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""
Objects
-------
Provides wrappers around core Windows objects such as file handles, sockets,
etc.
"""

# NOTE: This module should *not* import other modules from wintypes.
from pywincffi.core import dist
from pywincffi.core.typesbase import CFFICDataWrapper


class ObjectMixin(object): # pylint: disable=too-few-public-methods
"""A mixin which is used by object classes to share common code."""
def __repr__(self):
ffi, _ = dist.load()
return "<%s 0x%x at 0x%x>" % (
self.__class__.__name__,
int(ffi.cast("intptr_t", self._cdata[0])),
id(self)
)

def __eq__(self, other):
if not isinstance(other, self.__class__):
raise TypeError(
"%r must be a %s object" % (other, self.__class__.__name__))

# pylint: disable=protected-access
return self._cdata[0] == other._cdata[0]


# pylint: disable=too-few-public-methods,protected-access
class HANDLE(CFFICDataWrapper, ObjectMixin):
"""
.. seealso::
https://msdn.microsoft.com/en-us/library/aa383751
"""
def __init__(self, data=None):
ffi, _ = dist.load()
super(HANDLE, self).__init__("HANDLE[1]", ffi)

# Initialize from a <cdata handle> object as returned by some
# Windows API library calls: Python AND FFI types must be equal.
if isinstance(data, type(self._cdata[0])):
if ffi.typeof(data) == ffi.typeof(self._cdata[0]):
self._cdata[0] = data
76 changes: 76 additions & 0 deletions pywincffi/wintypes/structures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""
Structures
----------
This module provides wrappers for structures produced or required by the
Windows APIs.
"""

from pywincffi.core import dist
from pywincffi.core.typesbase import CFFICDataWrapper
from pywincffi.wintypes.objects import HANDLE


# pylint: disable=too-few-public-methods,invalid-name
class SECURITY_ATTRIBUTES(CFFICDataWrapper):
"""
.. seealso::
https://msdn.microsoft.com/en-us/library/aa379560
"""
def __init__(self):
ffi, _ = dist.load()
super(SECURITY_ATTRIBUTES, self).__init__(
"SECURITY_ATTRIBUTES*",
ffi,
)
self._cdata.nLength = ffi.sizeof(self._cdata)
self.lpSecurityDescriptor = ffi.NULL

# pylint: disable=missing-docstring
@property
def nLength(self):
return self._cdata.nLength

# pylint: disable=missing-docstring,no-self-use
@nLength.setter
def nLength(self, _):
# Can't raise AttributeError.
# CFFICDataWrapper would fall back to setting self._cdata.nLength .
raise TypeError("SECURITY_ATTRIBUTES.nLength is read-only")


# pylint: disable=too-few-public-methods,protected-access
class OVERLAPPED(CFFICDataWrapper):
"""
.. seealso::
https://msdn.microsoft.com/en-us/library/ms684342
"""
def __init__(self):
ffi, _ = dist.load()
super(OVERLAPPED, self).__init__("OVERLAPPED*", ffi)

# pylint: disable=missing-docstring
@property
def hEvent(self):
return HANDLE(self._cdata.hEvent)

# pylint: disable=missing-docstring
@hEvent.setter
def hEvent(self, handle):
if not isinstance(handle, HANDLE):
raise TypeError("%r must be a HANDLE object" % handle)
self._cdata.hEvent = handle._cdata[0]


# pylint: disable=too-few-public-methods
class FILETIME(CFFICDataWrapper):
"""
.. seealso::
https://msdn.microsoft.com/en-us/library/ms724284
"""
def __init__(self):
ffi, _ = dist.load()
super(FILETIME, self).__init__("FILETIME*", ffi)
Loading

0 comments on commit 5163e08

Please sign in to comment.