reish
reish

Reputation: 841

Invalid handle when calling Windows API from Python 3

The following code works well in 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()

It does not work in 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 means invalid handle.

It seems that in addition, the handles retrieved in Python 2 are smaller numbers, such as 0x100ffc0. It isn't something specific with CloseServiceHandle. This handle cannot be used with any service function.

Both Python versions are 64 bit native Windows Python.

Upvotes: 1

Views: 670

Answers (2)

0xVodka
0xVodka

Reputation: 1

Try using ctypes.windll.Advapi32 instead of ctypes.windll.advapi32

Upvotes: 0

Neitsa
Neitsa

Reputation: 8166

You should use argtypes and restype otherwise all argument default to int and are truncated in 64-bit. Also you shouldn't call GetLastError directly but use ctypes.get_last_error()which cache the last error code (there might have been windows APIs called by the interpreter after you perform a call, you can't be sure).

Here's a working example:

#!/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())

Upvotes: 4

Related Questions