Неверный дескриптор при вызове Windows API из Python 3 - PullRequest
1 голос
/ 17 марта 2019

Следующий код хорошо работает в Python 2:

import ctypes

def test():
    OpenSCManager      = ctypes.windll.advapi32.OpenSCManagerA
    CloseServiceHandle = ctypes.windll.advapi32.CloseServiceHandle

    handle = OpenSCManager(None, None, 0)
    print(hex(handle))
    assert handle, ctypes.GetLastError()
    assert CloseServiceHandle(handle), ctypes.GetLastError()

test()

Это не работает в Python 3:

0x40d88f90
Traceback (most recent call last):
  File ".\test1.py", line 12, in <module>
    test()
  File ".\test1.py", line 10, in test
    assert CloseServiceHandle(handle), ctypes.GetLastError()
AssertionError: 6

6 означает недопустимый дескриптор.

Кажется, что кроме того, дескрипторы, полученные в Python 2, имеют меньшие числа, например 0x100ffc0. Это не что-то конкретное с CloseServiceHandle. Этот дескриптор не может использоваться ни с какой сервисной функцией.

Обе версии Python являются 64-битными Windows Python.

1 Ответ

3 голосов
/ 18 марта 2019

Вы должны использовать argtypes и restype, иначе все аргументы по умолчанию имеют значение int и усекаются в 64-битном формате.Также вы не должны вызывать GetLastError напрямую, а использовать ctypes.get_last_error(), который кэширует последний код ошибки (возможно, были интерфейсы Windows API, вызванные интерпретатором после выполнения вызова, вы не можете быть уверены).

Вот рабочий пример:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import ctypes


def test():
    advapi32 = ctypes.WinDLL("advapi32", use_last_error=True)
    OpenSCManager = advapi32.OpenSCManagerA
    OpenSCManager.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong]
    OpenSCManager.restype = ctypes.c_void_p

    CloseServiceHandle = advapi32.CloseServiceHandle
    CloseServiceHandle.argtypes = [ctypes.c_void_p]
    CloseServiceHandle.restype = ctypes.c_long

    handle = OpenSCManager(None, None, 0)
    if not handle:
        raise ctypes.WinError(ctypes.get_last_error())
    print(f"handle: {handle:#x}")

    result = CloseServiceHandle(handle)
    if result == 0:
        raise ctypes.WinError(ctypes.get_last_error())

def main():
    test()


if __name__ == "__main__":
    sys.exit(main())
...