如何手动将 IronPython ctypes c_char_p 指针设置为绝对地址?

How do I set an IronPython ctypes c_char_p pointer to an absolute address manually?

我需要将字符指针指向的地址设置为绝对值。

在许多 Python 实现中(CPython 2.x、CPython 3.x、PyPy & ActivePython、...)这可以做到使用:

>>> c_char_p(0xcafebabe)
c_char_p(3405691582)
>>>

铁Python:

>>> c_char_p(0xcafebabe)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: expected char pointer, got long
>>>

IronPython 不会尝试设置指针的地址,而是将参数视为内容然后 returns 类型冲突。但是,上述其他 Python 发行版的功能不适用于 IronPython.

如何在 IronPython 中将 c_char_p 设置为绝对地址?

我的问题背景:

我开发了一个用Delphi编写的DLL。 DLL 的目的是为 Delphi 应用程序提供一个外部接口。 我可以通过 C 和 C++ 中的 DLL 成功控制应用程序。 客户要求更方便的解决方案 -> 他们想用 Python 控制应用程序。 我开发了一个 Python 包,实际上更容易使用。 所有 DLL 函数都必须使用指向表示设备的相同类型结构的指针来调用。 第一个调用的函数是 DLL 的 Init 函数,它使用默认值初始化结构。 不幸的是结构的设计缺少一个重要的项目,那就是RS232参数的配置, 因为在 DLL 的第一个版本中没有计划支持 RS232 设备。 为了仍然提供 RS232 支持,DLL 已被修改为使用设备结构中现有 char* 的绝对地址作为信号。 如果此 char* 的绝对地址为 0xCAFEBABE,则 DLL 会解析已放入该结构的另一个 char* 中的配置字符串。 这个丑陋的解决方案非常有效,并且不必更改结构的属性。 使用 CPython 2.x、CPython 3.x、PyPy 和 ActivePython 控制 DLL/application 时一切正常。 不幸的是,IronPython 在尝试将指针设置为绝对地址时报告错误。

显然,IPython对地址的限制更大,必须手动转换。这可以通过 [Python 2]: ctypes.cast(obj, type).

完成

code.py:

#!/usr/bin/env python2

import sys
import ctypes


CharPtr = ctypes.POINTER(ctypes.c_char)


def main():
    pchar0 = ctypes.cast(ctypes.c_char_p("Dummy text"), CharPtr)  # Create an object that will yield a valid memory address
    buf_addr = ctypes.addressof(pchar0.contents) # Raw buffer address
    print("Raw buffer address: 0x{:016X}".format(buf_addr))

    cp0 = ctypes.cast(buf_addr, ctypes.c_char_p)
    print("cp0 ({:s}) value: {:s}\n".format(cp0.__class__.__name__, cp0.value))

    cp1 = ctypes.c_char_p(buf_addr)
    print("cp1 ({:s}) value: {:s}".format(cp1.__class__.__name__, cp1.value))


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

输出:

[cfati@CFATI-5510-0:e:\Work\Dev\Whosebug\q055118583]> "e:\Work\Dev\VEnvs\py_064_02.07.15_test0\Scripts\python.exe" code.py
Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32

Raw buffer address: 0x00000000036D0690
cp0 (c_char_p) value: Dummy text

cp1 (c_char_p) value: Dummy text

[cfati@CFATI-5510-0:e:\Work\Dev\Whosebug\q055118583]> "c:\Install\IronLanguages\IronPython.07.09\net45\ipy.exe" code.py
Python 2.7.9 (IronPython 2.7.9 (2.7.9.0) on .NET 4.0.30319.42000 (64-bit)) on cli

Raw buffer address: 0x00000209BFF2E860
cp0 (c_char_p) value: Dummy text

Traceback (most recent call last):
  File "code.py", line 24, in <module>
  File "code.py", line 18, in main
TypeError: expected char pointer, got long

备注:

  • pchar0的目的只是得到一个有效的内存地址(buf_addr) 指向 char*(因为 0xCafeBabe 在我的 Python 过程中没有意义)
  • cp1 (以相反的顺序获取它们)是问题陈述:试图从内存地址创建 ctypes.c_char_p (根据最新的问题编辑:那个由.dll中的某些例程填充char*(必须在当前进程中加载​​))
    • 这在 CPython 中有效(根据问题),但在 中引发了 TypeError ]IPython
  • cp0 是问题的解决方案:尝试从 相同的 内存地址创建一个 ctypes.c_char_p
    • 适用于 CPython IPython