e 内存_申请内存(pid,(int)) 内存_申请文本内存 (pid, “xxx”) 进程_取函数入口 (pid, “xxx.dll”, “xxx”)
e
【相关推荐】
(C/C++ 代码在 Windows VS 环境编写)
// 下列 ifdef 块是创建使从 DLL 导出更简单的宏的标准方法。
// 在预处理器中定义了 MYDLL_EXPORTS 符号,而调用方不包含此符号。
// 源文件中包含此文件的任何其他项目都会将 MYDLL_API 视为是从 DLL 导入的,
// 而此 DLL 则将用此宏定义的符号视为是被导出的。
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
//ctypes需要提供c接口,主要是目前cpp还没有统一的abi
extern "C"
{
//导出一个全局变量
extern MYDLL_API int my_number;
//函数
MYDLL_API int my_func(int a, int b);
MYDLL_API double my_func2(double a, double b);
MYDLL_API int * my_func3(char *a, double *b, const char *str);
//指针
extern MYDLL_API char *char_ptr;
extern MYDLL_API int *int_ptr;
extern MYDLL_API int *null_ptr;
//打印dll中的变量
MYDLL_API void print_var();
//结构体
struct MYDLL_API MyStruct
{
int a;
double b;
};
MYDLL_API MyStruct my_func4(const MyStruct &arg);
MYDLL_API MyStruct * my_func5(MyStruct *arg);
}
// MSVC模板默认带pch,设置为不使用预编译头
// #include "pch.h"
#include "mydll.h"
#include <iostream>
MYDLL_API int my_number = 1992;
MYDLL_API int my_func(int a, int b)
{
return a + b;
}
MYDLL_API double my_func2(double a, double b)
{
return a + b;
}
MYDLL_API int * my_func3(char * a, double * b, const char *str)
{
std::cout << "dll myfunc3:" << str << std::endl;
my_number = *a + int(*b);
return &my_number;
}
MYDLL_API char *char_ptr = new char(65);
MYDLL_API int *int_ptr = new int(250);
MYDLL_API int *null_ptr = nullptr;
MYDLL_API void print_var()
{
std::cout << "dll print var:"
<< "\n\tmy number:" << my_number
<< "\n\tchar ptr:" << *char_ptr
<< "\n\tint ptr:" << *int_ptr << std::endl;
}
MYDLL_API MyStruct my_func4(const MyStruct & arg)
{
MyStruct ret{ 12,34.5 };
std::cout << "dll myfunc4:"
<< "in:" << arg.a << " " << arg.b
<< "ret:" << ret.a << " " << ret.b << std::endl;
return ret;
}
MYDLL_API MyStruct * my_func5(MyStruct * arg)
{
if (arg) {
arg->a = 67;
arg->b = 89.5;
}
return arg;
}
import ctypes
#dll = ctypes.cdll.LoadLibrary("msvcrt.dll")
#dll.printf(b"hello ctypes\n")
dll = ctypes.cdll.LoadLibrary(
"D:/TestSpace/TestCpp_20210617_mydll/x64/Release/mydll.dll")
#访问变量
print(dll.my_number) # 打印<_FuncPtr object at 0x0000022537F1B450>,默认应该是当作函数访问的
print(ctypes.c_int.in_dll(dll, 'my_number').value)
#访问函数
print(dll.my_func)
print(dll.my_func(12, 34))
#ctypes 默认假定函数返回 int 类型,可以设置函数对象的 restype 属性来指定具体类型。
#对于参数类型也可以通过设置函数对象的 argtypes 来指定具体类型,防止不合理的参数传递。
my_func2 = dll.my_func2
my_func2.argtypes = [ctypes.c_double, ctypes.c_double]
my_func2.restype = ctypes.c_double
print(my_func2(12, 34.5))
my_func3 = dll.my_func3
my_func3.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_double)]
my_func3.restype = ctypes.POINTER(ctypes.c_int)
arg1 = ctypes.c_char(12)
arg2 = ctypes.c_double(1000)
#byref相当于取引用,c字符串传字节数组
ret = my_func3(ctypes.byref(arg1), ctypes.byref(arg2), b'hello ctypes.')
print(ret.contents.value)
dll.print_var()
#指针变量
#ptr = ctypes.POINTER(ctypes.c_int)
# char(65)->print(b'A'),可能会把后面挨着的字节内容也打印
print(ctypes.c_char_p.in_dll(dll, 'char_ptr').value)
print(ctypes.POINTER(ctypes.c_int).in_dll(dll, 'int_ptr').contents.value)
ctypes.POINTER(ctypes.c_int).in_dll(dll, 'int_ptr').contents.value = 520
#空指针bool值为false
print(bool(ctypes.POINTER(ctypes.c_int).in_dll(dll, 'null_ptr')))
dll.print_var()
#struct或union必须派生ctypes给的基类Structure和Union
#每个子类都必须定义一个_fields_属性,_fields_必须是一个2-tuples列表,包含一个字段名和一个字段类型。
class MyStruct(ctypes.Structure):
_fields_ = [
("a", ctypes.c_int),
("b", ctypes.c_double)
]
my_func4 = dll.my_func4
my_func4.restype = MyStruct
arg = MyStruct()
arg.a = 10
arg.b = 11
#print(ctypes.sizeof(MyStruct))
ret = my_func4(arg)
print('my_func4 ret:', ret.a, ' ', ret.b)
my_func5 = dll.my_func5
my_func5.restype = ctypes.POINTER(MyStruct)
ret = my_func5(ctypes.byref(arg)).contents
print('my_func5 ret:', ret.a, ' ', ret.b)