如何使用 ctypes 在 Python 中实现 NetUserGetInfo 函数

How to implement NetUserGetInfo function in Python using ctypes

我正在尝试使用 ctypes 在 python 中使用 NetUserGetInfo。

根据 documentation,该函数如下所示:

NET_API_STATUS NET_API_FUNCTION NetUserGetInfo(
  LPCWSTR servername,
  LPCWSTR username,
  DWORD   level,
  LPBYTE  *bufptr
);

我发现调用类型为 LPBYTE *bufptr

的函数的第四个参数有困难

我的代码如下所示:

import ctypes
from ctypes.wintypes import LPWSTR
netap = ctypes.WinDLL("Netapi32.dll")

servername = None
username = ctypes.c_wchar_p("myuser")

bufptr = ctypes.POINTER(ctypes.c_byte)

class USER_INFO_0(ctypes.Structure):
    _fields_ = [
        ("usri0_name", LPWSTR)
    ]
usrio_name = username.bytes.decode()
level = USER_INFO_0()

response = netap.NetUserGetInfo(ctypes.byref(servername),ctypes.byref(username),level,ctypes.byref(bufptr))
print(response)

出现以下错误:

Traceback (most recent call last):
  File ".\netusertest.py", line 17, in <module>
    response = netap.NetUserGetInfo(ctypes.byref(servername),ctypes.byref(username),level,ctypes.byref(bufptr))
TypeError: byref() argument must be a ctypes instance, not '_ctypes.PyCPointerType'

多多指教,初学者不用说!

这一行:

bufptr = ctypes.POINTER(ctypes.c_byte)

是一个类型声明,而不是一个实例,正如你的错误所指出的那样,所以它不能被引用。调用类型创建实例 (ctypes.POINTER(ctypes.c_byte))()) 但我建议使用适当的 wintypes 代替。

我注意到您正在尝试初始化一个 USER_INFO_0 实例。这是由 API 分配和 return 编辑的,并且也必须被释放。 level 表示将 returned 的类型,因为它可以变化。

服务器名用户名参数可以直接作为Unicode字符串传递。

它也有助于定义 .argtypes.restype 以告知 ctypes 参数类型和 return 类型。不要 ctypes 猜测。如果定义正确ctypes 如果你传递一个不能转换为定义的类型将报错

这是在 32 位和 64 位 Python 上使用适当的 server/user 测试的代码:

import ctypes as ct
from ctypes import wintypes as w

# from lm.h headers.
NET_API_STATUS = w.DWORD
NERR_Success = 0

class USER_INFO_0(ct.Structure):
    _fields_ = [('usri0_name', w.LPWSTR)]

# WinDLL is appropriate as NET_API_FUNCTION is defined as __stdcall.
# This matters if the code runs under 32-bit Python.
netap = ct.WinDLL('netapi32')
netap.NetUserGetInfo.argtypes = w.LPCWSTR, w.LPCWSTR, w.DWORD, ct.POINTER(w.LPBYTE)
netap.NetUserGetInfo.restype = NET_API_STATUS
netap.NetApiBufferFree.argtypes = w.LPVOID,
netap.NetApiBufferFree.restype = NET_API_STATUS

bufptr = w.LPBYTE() # make an LPBYTE instance to hold the output parameter.

level = 0
response = netap.NetUserGetInfo('server', 'account', level, ct.byref(bufptr))
if response == NERR_Success:
    data = ct.cast(bufptr,ct.POINTER(USER_INFO_0)) # cast as indicated by level
    print(data.contents.usri0_name) # dereference pointer and access member
    netap.NetApiBufferFree(bufptr)  # free the pointer

print(response)