I am trying to use NetUserGetInfo in python using ctypes.
The function looks like the following as per documentation:
NET_API_STATUS NET_API_FUNCTION NetUserGetInfo(
LPCWSTR servername,
LPCWSTR username,
DWORD level,
LPBYTE *bufptr
);
I'm finding difficulty in calling the 4th argument to the function which is of type LPBYTE *bufptr
my code looks like following:
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)
Getting the following error:
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'
Any pointers are appreciated, I'm a beginner needless to say!
1 Answer 1
This line:
bufptr = ctypes.POINTER(ctypes.c_byte)
is a type declaration, not an instance, as your error points out, so it can't be taken by reference. Call the type to create an instance (ctypes.POINTER(ctypes.c_byte))()) but I recommend using appropriate wintypes instead.
I noticed you are trying to initialize a USER_INFO_0 instance. This is allocated and returned by the API and must be freed as well. level represent the type that will be returned as it can vary.
servername and username parameters can be passed as Unicode strings directly.
It also helps to define .argtypes and .restype to inform ctypes of the argument types and return type. Don't make ctypes guess. If defined correctly ctypes will report errors if you pass a type that can't be converted to the definition.
Here is code tested on 32- and 64-bit Python with an appropriate 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)