当前位置: 首页 > 面试题库 >

在python ctypes模块中将struct用作函数参数

张积厚
2023-03-14
问题内容

因此,我尝试将使用ctypes模块将为处理Windows上的结点/符号链接/等而编写的python
C扩展移植到纯Python。不幸的是,由于我以前对ctypes的使用非常有限,所以我认为我可能在某个地方犯了一个错误,导致我的代码无法正常运行。到目前为止,这是我所拥有的:

from os import path
from ctypes import *
from ctypes.wintypes import *

# Python implementation of:
#
# typedef struct {
#       DWORD   ReparseTag;
#       DWORD   ReparseDataLength;
#       WORD    Reserved;
#       WORD    ReparseTargetLength;
#       WORD    ReparseTargetMaximumLength;
#       WORD    Reserved1;
#       WCHAR   ReparseTarget[1];
# } REPARSE_MOUNTPOINT_DATA_BUFFER, *PREPARSE_MOUNTPOINT_DATA_BUFFER;

class ReparsePoint(Structure):
    _fields_ = [
        ("ReparseTag", DWORD),
        ("ReparseDataLength", DWORD),
        ("Reserved", WORD),

        ("ReparseTargetLength", WORD),
        ("ReparseTargetMaximumLength", WORD),
        ("Reserved1", WORD),
        ("ReparseTarget", c_wchar_p),
    ]

GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000

FILE_SHARE_DELETE = 0x00000004
FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
FILE_SHARE_READ_WRITE = (FILE_SHARE_READ | FILE_SHARE_WRITE)

OPEN_EXISTING = 3

IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
REPARSE_MOUNTPOINT_HEADER_SIZE = 8

FSCTL_SET_REPARSE_POINT = 589988
FILE_FLAG_OPEN_REPARSE_POINT = 2097152
FILE_FLAG_BACKUP_SEMANTICS = 33554432
FILE_FLAG_REPARSE_BACKUP = 35651584 # FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS

INVALID_HANDLE_VALUE = -1
LPOVERLAPPED = c_void_p
LPSECURITY_ATTRIBUTES = c_void_p

NULL = 0
FALSE = BOOL(0)
TRUE = BOOL(1)

def CreateFile(filename, access, sharemode, creation, flags):
    return HANDLE(windll.kernel32.CreateFileW(
        LPWSTR(filename),
        DWORD(access),
        DWORD(sharemode),
        LPSECURITY_ATTRIBUTES(NULL),
        DWORD(creation),
        DWORD(flags),
        HANDLE(NULL)
    ))

def CreateDirectory(fpath):
    return windll.kernel32.CreateDirectoryW(LPWSTR(fpath), LPSECURITY_ATTRIBUTES(NULL)) != FALSE

def RemoveDirectory(fpath):
    return windll.kernel32.RemoveDirectoryW(LPWSTR(fpath)) != FALSE

def translate_path(fpath):
    fpath = path.abspath(fpath)
    if fpath[len(fpath)-1] == '\\' and fpath[len(fpath)-2] == ':':
        fpath = fpath[:len(fpath)-1]
    return '\\??\\%s' % fpath

def junction(source, link_name):
    """ Create a junction at link_name pointing to source directory. """
    if not path.isdir(source):
        raise Exception('Junction source does not exist or is not a directory.')

    link_name = path.abspath(link_name)
    if path.exists(link_name):
        raise Exception('Filepath for new junction already exists.')

    if not CreateDirectory(link_name):
        raise Exception('Failed to create new directory for target junction.')

    source = translate_path(source)
    hFile = CreateFile(link_name, GENERIC_WRITE, 0, OPEN_EXISTING, FILE_FLAG_REPARSE_BACKUP)
    if hFile == HANDLE(INVALID_HANDLE_VALUE):
        raise Exception('Failed to open directory for junction creation.')

    datalen = len(source) * sizeof(c_wchar)
    reparseInfo = ReparsePoint(
        IO_REPARSE_TAG_MOUNT_POINT,
        datalen + 12,
        0,
        datalen,
        datalen + sizeof(c_wchar),
        0,
        source
    )
    pReparseInfo = pointer(reparseInfo)

    print reparseInfo.ReparseTarget
    returnedLength = DWORD(0)
    result = BOOL(
        windll.kernel32.DeviceIoControl(
            hFile,
            DWORD(FSCTL_SET_REPARSE_POINT),
            pReparseInfo,
            DWORD(reparseInfo.ReparseDataLength + REPARSE_MOUNTPOINT_HEADER_SIZE),
            LPVOID(NULL),
            DWORD(0),
            byref(returnedLength),
            LPOVERLAPPED(NULL)
        )
    ) == TRUE

    #if not result:
        #RemoveDirectory(link_name)

    windll.kernel32.CloseHandle(hFile)
    return result

print junction('G:\\cpp.workspace\\tools', 'test')
"""
Just putting this here for the moment so I know how to call the function.

BOOL WINAPI DeviceIoControl(
  __in         HANDLE hDevice,
  __in         DWORD dwIoControlCode,
  __in_opt     LPVOID lpInBuffer,
  __in         DWORD nInBufferSize,
  __out_opt    LPVOID lpOutBuffer,
  __in         DWORD nOutBufferSize,
  __out_opt    LPDWORD lpBytesReturned,
  __inout_opt  LPOVERLAPPED lpOverlapped
);
"""

当前,在运行时,该代码为目标联结创建一个文件夹。(在这种情况下,请进行测试)甚至似乎正在应用reparse标签向系统发出信号,表明该文件夹是联结。但是,结点不是指向“
G:\ cpp.workspace \ tools”(或者指向\ ?? \ G:\ cpp.workspace \ tools),而是指向:㢨\獬

现在,显然这是reparseInfo.ReparseTarget的问题,但是我一直无法弄清楚我做错了什么。


问题答案:

这是WCHAR的数组,而不是指针:

#       WCHAR   ReparseTarget[1];

[1]具有误导性,API期望在结构的末尾使用以null终止的字符串。



 类似资料:
  • 函数可以作为其它函数的参数进行传递,然后在其它函数内调用执行,一般称之为回调。下面是一个将函数作为参数的简单例子(function_parameter.go): package main import ( "fmt" ) func main() { callback(1, Add) } func Add(a, b int) { fmt.Printf("The sum

  • 问题内容: 我想使用数组作为参数调用一个函数: 有路过的内容的一种更好的方式进入? 问题答案: const args = [‘p0’, ‘p1’, ‘p2’]; call_me.apply(this, args); 请参阅MDN文档。 如果环境支持ECMAScript6,则可以改用传播参数:

  • 我目前有一个,但是为了灵活性,我希望能够分配一个lambda表达式,将作为映射中的值返回。 所以我创建了这个模板类: 并像这样使用它: IntelliSense提供了更多信息: 多个操作符“=”匹配这些操作数:function“valueorfunction::operator=(const std::function&other)[with T=std::wstring]”function“va

  • 问题内容: 在Java中,如何将一个函数作为另一个函数的参数传递? 问题答案: Java 8及以上 如果你的类或接口只有一个抽象方法(有时称为SAM type),则使用Java 8+ lambda表达式,例如: 然后可以在使用MyInterface的任何地方替换lambda表达式: 例如,你可以非常快速地创建一个新线程: 并使用方法引用语法使其更加清晰: 如果没有 lambda表达式,则最后两个示

  • 考虑以下数据frame: 为什么我能够将列作为输入传递给查询中的,而不是从API传递?是否有一种方法可以使用spark DataFrame函数复制这种行为?

  • 本文向大家介绍Python struct模块解析,包括了Python struct模块解析的使用技巧和注意事项,需要的朋友参考一下 python提供了一个struct模块来提供转换。下面就介绍这个模块中的几个方法。     struct.pack(): struct.pack用于将Python的值根据格式符,转换为字符串(因为Python中没有字节(Byte)类型,可以把这里的字符串理解为字节流,