# Source code for windows.winobject.handle

    import os
    import ctypes

    import windows
    from windows import winproxy
    from windows.generated_def import windef
    import windows.generated_def as gdef

    current_process_pid = os.getpid()

    class BaseSystemHandle(object):
        """A handle of the system"""
        @windows.utils.fixedpropety
        def process(self):
            """The process possessing the handle

            :type: :class:`WinProcess <windows.winobject.process.WinProcess>`"""
            # "TODO: something smart ? :D"
            # return [p for p in windows.system.processes if p.pid == self.dwProcessId][0]
            return windows.WinProcess(pid=self.dwProcessId)

        @property
        def pid(self):
            return self.dwProcessId

        @property
        def value(self):
            return self.wValue

        @windows.utils.fixedpropety
        def name(self):
            """The name of the handle

            :type: :class:`str`"""
            return self._get_object_name()

        @windows.utils.fixedpropety
        def type(self):
            """The type of the handle

            :type: :class:`str`"""
            return self._get_object_type()

        @property
        def infos(self):
            """TODO: DOC"""
            return self._get_object_basic_infos()

        def _get_object_name(self):
            lh = self.local_handle
            size_needed = gdef.DWORD()
            yyy = ctypes.c_buffer(0x1000)
            winproxy.NtQueryObject(lh, gdef.ObjectNameInformation, ctypes.byref(yyy), ctypes.sizeof(yyy), ctypes.byref(size_needed))
            return gdef.LSA_UNICODE_STRING.from_buffer_copy(yyy[:size_needed.value]).str

        def _get_object_type(self):
            lh = self.local_handle
            xxx = gdef.PUBLIC_OBJECT_TYPE_INFORMATION()
            size_needed = gdef.DWORD()
            try:
                winproxy.NtQueryObject(lh, gdef.ObjectTypeInformation, ctypes.byref(xxx), ctypes.sizeof(xxx), ctypes.byref(size_needed))
            except WindowsError as e:
                if e.code != gdef.STATUS_INFO_LENGTH_MISMATCH:
                    raise
                size = size_needed.value
                buffer = ctypes.c_buffer(size)
                winproxy.NtQueryObject(lh, gdef.ObjectTypeInformation, buffer, size, ctypes.byref(size_needed))
                xxx = gdef.PUBLIC_OBJECT_TYPE_INFORMATION.from_buffer_copy(buffer)
            return xxx.TypeName.str

        def _get_object_basic_infos(self):
            pass
            lh = self.local_handle
            size_needed = gdef.DWORD()
            basic_infos = gdef.PUBLIC_OBJECT_BASIC_INFORMATION()
            winproxy.NtQueryObject(lh, gdef.ObjectBasicInformation, ctypes.byref(basic_infos), ctypes.sizeof(basic_infos), ctypes.byref(size_needed))
            return basic_infos

        @windows.utils.fixedpropety
        def local_handle(self):
            """A local copy of the handle, acquired with ``DuplicateHandle``

            :type: :class:`int`"""
            if self.dwProcessId == windows.current_process.pid:
                return self.wValue
            res = gdef.HANDLE()
            winproxy.DuplicateHandle(self.process.handle, self.wValue, windows.current_process.handle, ctypes.byref(res), dwOptions=gdef.DUPLICATE_SAME_ACCESS)
            return res.value

        def description(self):
            stype = self.type
            descr_func = getattr(self, "description_" + stype, None)
            if descr_func is None:
                return None
            return descr_func()

        def description_Process(self):
            proc = windows.WinProcess(handle=self.wValue)
            res = str(proc)
            del proc._handle
            return res

        def description_Thread(self):
            thread = windows.WinThread(handle=self.wValue)
            res = str(thread)
            del thread._handle
            return res

        def __repr__(self):
            return "<{0} value=<0x{1:x}> in process pid={2}>".format(type(self).__name__, self.wValue, self.dwProcessId)

        def __del__(self):
            if self.dwProcessId == current_process_pid:
                return
            if hasattr(self, "_local_handle"):
                return winproxy.CloseHandle(self._local_handle)

    class Handle(gdef.SYSTEM_HANDLE, BaseSystemHandle):
        pass

    class HandleWow64(gdef.SYSTEM_HANDLE64, BaseSystemHandle):
        pass # For wow64 process

    def enumerate_handles():
        if windows.current_process.is_wow_64:
            return enumerate_handles_syswow64()
        size_needed = gdef.ULONG()
        # Should at least be sizeof(gdef.SYSTEM_HANDLE_INFORMATION)
        tmp_buffer = windows.utils.BUFFER(gdef.SYSTEM_HANDLE_INFORMATION)()
        try:
            winproxy.NtQuerySystemInformation(gdef.SystemHandleInformation, tmp_buffer, tmp_buffer.real_size, ReturnLength=ctypes.byref(size_needed))
        except WindowsError as e:
            pass
        size = size_needed.value + 0x1000 # In case we have some more handle created
        buf = windows.utils.BUFFER(gdef.SYSTEM_HANDLE_INFORMATION)(size=size)
        size_needed.value = 0
        winproxy.NtQuerySystemInformation(gdef.SystemHandleInformation, buf, buf.real_size, ReturnLength=ctypes.byref(size_needed))
        handle_array = windows.utils.resized_array(buf[0].Handles, buf[0].HandleCount, Handle)
        return list(handle_array)

    def enumerate_handles_syswow64():
        size_needed = gdef.ULONG()
        # Should at least be sizeof(gdef.SYSTEM_HANDLE_INFORMATION)
        tmp_buffer = windows.utils.BUFFER(gdef.SYSTEM_HANDLE_INFORMATION64)()
        try:
            windows.syswow64.NtQuerySystemInformation_32_to_64(gdef.SystemHandleInformation, tmp_buffer, tmp_buffer.real_size, ReturnLength=ctypes.byref(size_needed))
        except WindowsError as e:
            pass
        size = size_needed.value + 0x1000 # In case we have some more handle created
        buf = windows.utils.BUFFER(gdef.SYSTEM_HANDLE_INFORMATION64)(size=size)
        size_needed.value = 0
        windows.syswow64.NtQuerySystemInformation_32_to_64(gdef.SystemHandleInformation, buf, buf.real_size, ReturnLength=ctypes.byref(size_needed))
        handle_array = windows.utils.resized_array(buf[0].Handles, buf[0].HandleCount, HandleWow64)
        return list(handle_array)

    def enumerate_type():
            "WIP: DO NOT USE"
            size_needed = DWORD()
            fsize = 8
            fbuffer = ctypes.c_buffer(fsize)
            try:
                winproxy.NtQueryObject(None, gdef.ObjectTypesInformation, fbuffer, fsize, ctypes.byref(size_needed))
            except WindowsError as e:
                if e.code != STATUS_INFO_LENGTH_MISMATCH:
                    raise
            else:
                # We had enought memory ?
                return

            # Looks like the Wow64 syscall emulation is broken :D
            # It write AFTER the buffer if we are a wow64 process :D
            # So better allocate a standalone buffer (triggering a ACCESS_VIOLATION) that corrupting the heap
            # This is a worst case scenario, as we allocation more space it should not happen !
            size = size_needed.value + 0x200
            size_needed.value = 0

            with windows.current_process.allocated_memory(size, gdef.PAGE_READWRITE) as buffer_base:
                winproxy.NtQueryObject(None, gdef.ObjectTypesInformation, buffer_base, size, ctypes.byref(size_needed))
                # Cache some exceptions ?
                # Parse the buffer data in-place as string are addr-dependant
                types_info = gdef.OBJECT_TYPES_INFORMATION.from_address(buffer_base)
                offset = ctypes.sizeof(gdef.PVOID) # Looks like the size of the struct is PTR aligned as the struct is follower by other stuff
                for i in range(types_info.NumberOfTypes):
                    info = gdef.PUBLIC_OBJECT_TYPE_INFORMATION.from_address(buffer_base + offset)
                    yield info
                    offset += ctypes.sizeof(gdef.PUBLIC_OBJECT_TYPE_INFORMATION) + info.TypeName.MaximumLength
                    if offset % ctypes.sizeof(gdef.PVOID):
                        offset += ctypes.sizeof(gdef.PVOID) - (offset % ctypes.sizeof(gdef.PVOID))
            # End-of ctx-manager
            return