简体   繁体   English

在 Python 中如何在转换为 ctypes c_wchar_p 时引用 function 字符串参数的值

[英]In Python how to reference the value of a function string parameter when converting to ctypes c_wchar_p

Context语境

I have used Python very occasionally in the past and am not familiar with its type system.我过去偶尔使用过 Python 并且不熟悉它的类型系统。 This is the first time I am consuming the win32 API with Python ctypes.这是我第一次使用带有 Python ctypes 的 win32 API。

Issue问题

With this code authentication succeeds and the process is started使用此代码身份验证成功并启动该过程

def run_as_user(command):
  lpUsername            = ctypes.c_wchar_p("hardcoded username")
  lpDomain              = ctypes.c_wchar_p("hardcoded domain")
  lpPassword            = ctypes.c_wchar_p("hardcoded password")

  ... 

  ctypes.windll.advapi32.CreateProcessWithLogonW(
    lpUsername,
    lpDomain, 
    lpPassword, 
    ...
  )

However with this code authentication fails.但是,使用此代码身份验证失败。

def run_as_user(username, domain, password, command):
  lpUsername            = ctypes.c_wchar_p(username)
  lpDomain              = ctypes.c_wchar_p(domain)
  lpPassword            = ctypes.c_wchar_p(password)

  ... 

  ctypes.windll.advapi32.CreateProcessWithLogonW(
    lpUsername,
    lpDomain, 
    lpPassword, 
    ...
  )

Questions问题

How can I fix the second code so that the conversion to ctypes c_wchar_p is performed on the values of the strings passed as function arguments instead of on their reference?如何修复第二个代码,以便对作为 function arguments 传递的字符串的值执行到 ctypes c_wchar_p 的转换,而不是在它们的引用上执行?

Where can I find resources about how strings are passed in Python function calls and ctypes casts?我在哪里可以找到有关如何在 Python function 调用和 ctypes 转换中传递字符串的资源?

A simple method, you only need to call the .value attribute of ctypes.c_wchar_p , you can get a Python native object, so as to call the function correctly.一个简单的方法,只需要调用ctypes.c_wchar_p.value属性,就可以得到一个 Python 原生 object,从而正确调用 ZC1C425268E683854F1AB5074C17

def run_as_user(username, domain, password, command):
  lpUsername            = ctypes.c_wchar_p(username)
  lpDomain              = ctypes.c_wchar_p(domain)
  lpPassword            = ctypes.c_wchar_p(password)

  ... 

  ctypes.windll.advapi32.CreateProcessWithLogonW(
    lpUsername.value,
    lpDomain.value, 
    lpPassword.value, 
    ...
  )

More reference: casting into a Python string from a char[] returned by a DLL更多参考: 从 DLL 返回的 char[] 转换为 Python 字符串

Dude, seriously, your two examples as shown are doing the same thing.伙计,说真的,您所显示的两个示例正在做同样的事情。 I don't know why your authentication fails (the function actually takes 11 parameters) and I'm not debugging it without the asked for reproducible example, but your handling of the parameters is identical.我不知道为什么您的身份验证会失败(function 实际上需要 11 个参数)并且在没有要求可重现示例的情况下我不会对其进行调试,但是您对参数的处理是相同的。 See this answer for a correct ctypes declaration.请参阅此答案以获取正确的 ctypes 声明。

Here's an actual minimal reproducible example showing handling of a wchar_t* parameter in various ways:这是一个实际的最小可重现示例,显示了以各种方式处理wchar_t*参数:

test.c (A function taking a wchar_t*, printing and returning it): test.c(A function 获取 wchar_t*,打印并返回它):

#include <stdio.h>

#define API __declspec(dllexport)

API wchar_t* demo(wchar_t* input) {
    printf("In demo: %S\n", input);
    return input;
}

test.py测试.py

from ctypes import *

dll = CDLL('./test')

def demo1():
    pdata = c_wchar_p("hard coded")   # Your "hard coded" example
    dll.demo(pdata)

def demo2(data):
        pdata = c_wchar_p(data)       # Your "not hard coded" example
        dll.demo(pdata)
        
demo1()                  # works
demo2("soft coded")      # also works

data = "example"

 # Other "accepted" answer is just extracting the original value from the wrapper
print(c_wchar_p(data).value == data)  # returns True

dll.demo('also no wrapper')  # no need for a wrapper at all actually
                             # ctypes "knows" to marshal `str` as `wchar_t*`
try:
    dll.demo(123)            # but no error checking without setting .argtypes
except Exception as e:       # as recommended crashes the C code
    print(e)

dll.demo.argtypes = c_wchar_p,   # but setting .argtypes as recommended
try:                             # gives a better error message
    dll.demo(123)
except Exception as e:
    print(e)

result = dll.demo('restype test')  # not setting .restype as recommended
print('no restype =',result)       # returns garbage

dll.demo.restype = c_wchar_p       # setting the restype as recommended
result = dll.demo('restype test')  # returns the right value
print('with restype =',result)

Output: Output:

In demo: hard coded
In demo: soft coded
True
In demo: no wrapper
In demo: also no wrapper
exception: access violation reading 0x000000000000007B    # .argtypes not set
argument 1: <class 'TypeError'>: wrong type
no restype = 1373086064                                   # .restype not set
with restype = restype test
In demo: In demo: restype test
In demo: restype test

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM