[编程进阶]ctypes在Python编程中的奇光异彩

一、What is ctypes?

ctypes 是 Python 的外部函数库。它提供了与 C 兼容的数据类型,并允许调用 DLL 或共享库中的函数。可使用该模块以纯 Python 形式对这些库进行封装……

相信你可能会觉得这又是一篇从“入门到精通”类的文章。当然不是的nei~我就是记一下我觉得有价值的东东,你一定也会用得到,而且关注我的小伙伴们自然猜到我们为什么要用ctypes,嘻嘻

详细的介绍可见:https://docs.python.org/zh-cn/3.7/library/ctypes.html

二、进阶之路,就在脚下

1.载入动态连接库

ctypes 导出了 cdll 对象,在 Windows 系统中还导出了 windlloledll 对象用于载入动态连接库。

  • cdll 载入按标准的 cdecl 调用协议导出的函数
  • windll 导入的库按 stdcall 调用协议调用其中的函数
  •  oledll 也按 stdcall 调用协议调用其中的函数,并假定该函数返回的是 Windows HRESULT 错误代码,并当函数调用失败时,自动根据该代码甩出一个 OSError 异常。

因为一些后续工程的原因,我只在Windows下进行了试验:

Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> print(ctypes.windll.kernel32)

>>> print(ctypes.cdll.msvcrt)

2.调用函数

(1)ctypes.windll.kernel32.VirtualAlloc函数。

VirtualAlloc是Windows提供的API,通常用来分配大块的内存。例如如果想在进程A和进程B之间通过共享内存的方式实现通信,可以使用该函数。不要用该函数实现通常情况的内存分配。该函数的一个重要特性是可以预定指定地址和大小的虚拟内存空间。例如,希望在进程的地址空间中第50MB的地方分配内存,那么将参数 50*1024*`1024 = 52428800 传递给pvAddress,将需要的内存大小传递给dwSize。如果系统有足够大的闲置区域能满足请求,则系统会将该块区域预订下来并返回预订内存的基地址,否则返回NULL。

格式:

LPVOID VirtualAlloc{ 
    LPVOID lpAddress, // 要分配的内存区域的地址 
    DWORD dwSize, // 分配的大小 
    DWORD flAllocationType, // 分配的类型 
    DWORD flProtect // 该内存的初始保护属性 
}; 

ctypes 定义了一些和C兼容的基本数据类型:

ctypes 类型

C 类型

Python 类型

c_bool

_Bool

bool (1)

c_char

char

单字符字节对象

c_wchar

wchar_t

单字符字符串

c_byte

char

整型

c_ubyte

unsigned char

整型

c_short

short

整型

c_ushort

unsigned short

整型

c_int

int

整型

c_uint

unsigned int

整型

c_long

long

整型

c_ulong

unsigned long

整型

c_longlong

__int64long long

整型

c_ulonglong

unsigned __int64unsigned long long

整型

c_size_t

size_t

整型

c_ssize_t

ssize_tPy_ssize_t

整型

c_float

float

浮点数

c_double

double

浮点数

c_longdouble

long double

浮点数

c_char_p

char * (以 NUL 结尾)

字节串对象或 None

c_wchar_p

wchar_t * (以 NUL 结尾)

字符串或 None

c_void_p

void *

int 或 None

 

(2)RtlMoveMemory从指定内存中复制内存至另一内存里 ,语法如下:

VOID RtlMoveMemory(
    VOID UNALIGNED *Destination,
    const VOID UNALIGNED *Source,
    SIZE_T Length
);

Destination :指向移动目的地址的指针。

Source :指向要复制的内存地址的指针。

Length :指定要复制的字节数。

 

(3)CreateProcess

调用时,系统将创建一个进程和一个主线程。CreateThread将在主线程的基础上创建一个新线程,大致做如下步骤:

  1. 在内核对象中分配一个线程标识/句柄,可供管理,由CreateThread返回
  2. 把线程退出码置为STILL_ACTIVE,把线程挂起计数置1
  3. 分配context结构
  4. 分配两页的物理存储以准备栈,保护页设置为PAGE_READWRITE,第2页设为PAGE_GUARD
  5. lpStartAddr和lpvThread值被放在栈顶,使它们成为传送给StartOfThread的参数
  6. 把context结构的栈指针指向栈顶(第5步)指令指针指向startOfThread函数

语法:

hThread = CreateThread(&security_attributes, dwStackSize, ThreadProc,pParam, dwFlags, &idThread) ;

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,      // pointer to security attributes
  DWORD dwStackSize,                  // initial thread stack size
  LPTHREAD_START_ROUTINE lpStartAddress,       // pointer to thread function
  LPVOID lpParameter,                   // argument for new thread
  DWORD dwCreationFlags,                // creation flags
  LPDWORD lpThreadId                  // pointer to receive thread ID
);

第一个参数是指向SECURITY_ATTRIBUTES型态的结构的指针。在Windows 98中忽略该参数。在Windows NT中,它被设为NULL。
第二个参数是用于新线程的初始堆栈大小,默认值为0。在任何情况下,Windows根据需要动态延长堆栈的大小。
第三个参数是指向线程函数的指标。函数名称没有限制,但是必须以下列形式声明:DWORD WINAPI ThreadProc (PVOID pParam) ;
第四个参数为传递给ThreadProc的参数。这样主线程和从属线程就可以共享数据。
第五个参数通常为0,但当建立的线程不马上执行时为旗标CREATE_SUSPENDED。线程将暂停直到呼叫ResumeThread来恢复线程的执行为止。
第六个参数是一个指标,指向接受执行绪ID值的变量。

 

你可能感兴趣的:(剑在手,天下走)