依赖
-) 操作系统
-) 操作系统的文件系统
本身
-) python解释器
-) python文件系统
项目一
实现功能
1.按键,将按键消息发送到其他窗口
功能分析
1.监视指定窗口按键
2.发送按键消息
实现思路
1.建包 ; 建立一个容器
2.建模块 ; 实现功能
3.# -*- coding: utf-8 -*-
4.依赖模块 ; ctypes
5.六种数据类型、函数、类、扩展
6.监视指定窗口按键; 需要一个C的DLL,DLL里执行python流程 ; python为面向对象,C为面向过程
1).python中设置上钩子 ; SetWindowsHookExA(消息类型, dll的回调函数地址, dll句柄, 窗口线程)
2).python中传递dll回调函数地址;
3)."dll"中准备回调函数
4)."dll"的回调函数调用python功能
5).python中准备功能
7.根据按键做发送消息的操作
项目问题总结
ctypes问题
1.当'调用'动态链接库的函数,加上()
2.当'传递'动态链接库的函数,去掉()
3.当'传递'python的函数给动态链接库,需转换;WINFUNCTYPE(python函数参数集合<逗号隔开>)(python函数名)
结构问题
附带:ctypes用法简介
一段示例:
from ctypes import *
user32 = windll.LoadLibrary('user32.dll')
user32.MessageBoxA(0,'ctypes is cool','Ctypes',0)
模块的思路
1.使用哪个函数
2.函数所在dll
3.调用约定
4.创建参数
使用ctypes的方法
1.加载动态链接库 ; 首先要做的是导入ctypes模块包,导入成功后调用ctypes为其提供的三个调用约定对象,三个对象为其封装好的dll对象可以直接调用,反之调用构造dll对象器
-) 三个对象: cdll(cdecl)、windll(stdcall)、oledll(stdcall)
-) 构造器: windll.LoadLibrary('dllName')
from ctypes import *
windll.user32.MessageBoxA(0,0,0,0)
#或者
windll.LoadLibrary('user32.dll').MessageBoxA(0,0,0,0)
2.调用动态链接库的函数 ,并简单使用python的数据类型传递; 主要是参数的处理
-) dll对象.函数()
-) python的字符串(Asic和Unicode)、整数、None可直接用于char*、wchar*、NULL类型
from ctypes import *
windll.LoadLibrary('user32.dll').MessageBoxW(None,None,u'hello',None)
3.构造简单的参数
-) ctypes提供了19种数据类型类,用于对应c的数据类型{c_bool:_Bool, 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 short, c_long:long, c_ulong:unsigned long, c_longlong:__int64 or long long, c_ulonglong:unsigned __int64 or unsigned long long, c_float:float, c_double:double, c_longdouble:long double, c_char_p:char*, c_wchar_p:wchar_t*, c_void_p:void*}
-) ctypes提供了申请缓冲区的函数: create_string_buffer(3),可用于动态修改,比如字符串
4.指名函数对象的参数类型 ; 指定格式可以防止不兼容的参数类型,并尝试转换为有效类型
printf.argtypes = [c_char_p, c_char_p, c_int, c_double]
printf("String '%s', Int %d,Double%f\n","hi", 10, 2, 2.2)
5.创建C的结构体 ; 类名取之C结构的名,类继承自ctypes模块的Struct基类;只定义一个属性_fields_(一个2元组的列表类型)
class POINT(Structure):
_fields_ = [('x', c_int), ('y', c_int)]
#以类名作为类型传递
6.处理回调函数 ; 首先定义python的函数对象,接着将函数对象转换为C的回调函数
#定义
def CallBack(code, wParam, lParam):
pass
#调用工厂函数创建回调类(WINFUNCTYPE 或 CFUNCTYPE),注意最后一个参数是该回调函数的返回值
BACKCLASS = WINFUNCTYPE(c_int, c_int, c_int)
#用回调类创建一个C的回调函数
backObj = BACKCLASS(CallBack)
#将最终的对象传递给win API即可
windll.user32.SetWindowsHookExA(3,obj, None, threadId)
附带:minGW写dll
思路
1.建项目 ; 容器
2.建源文件
3.添加依赖 ; #include <windows.h>
4.编译器导出 ; extern "C" _declspec(dllexport)
5.写函数
6.生成dll ; g++/gcc -share test.cpp -o test.dll
附带:C++调用python
思路
1.建项目
2.建源文件
3.导入依赖;#include <python.h>
4.定义过程 ;
5.初始化解释器; Py_Initialize();
6.单句运行python ; PyRun_SimpleString("python代码");
7.Python提供的对象 ; PyObject
8.转换过程的字符串为python对象 ; PyString_FromString("字符串")
9.导入脚本模块 ; PyImport_Import(python对象)
附带:gcc简单使用
1.GUN公社
2.GCC项目(GUN项目)
3.GCC for win32 -- mingw
4.GCC命令
-) 预编译过程; gcc -E test.c -o test.i ;
-) 编译过程; gcc -S test.i -o test.s
-) 汇编过程; gcc -c test.s -o test.o
-) 连接过程; gcc test.o -o test
-) 四大过程合并;gcc -o test
-) 三大过程合并:gcc -c test.c(或 gcc -c test.c -o)
-) 四大过程合并且维护多个源文件:gcc -o test first.c second.c third.c
附带:一段C功能代码
LRESULT CALLBACK HookerCallBack(int nCode,WPARAM wParam, LPARAM lParam)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
PMSG pMsg = (PMSG)lParam;
if(pMsg->message == WM_KEYUP)
{
if(pMsg->wParam == VK_HOME)
{
if(theDlg == NULL)
{
hGameWnd = pMsg->hwnd;
theDlg = new CWgDlg();
theDlg->Create(IDD_DIALOG_WG);
theDlg->ShowWindow(TRUE);
}
else
{
if(theDlg->IsWindowVisible())
theDlg->ShowWindow(FALSE);
else
theDlg->ShowWindow(TRUE);
}
}
}
return CallNextHookEx(0,nCode,wParam,lParam);
}
void StartHook()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());//Afx =全局,Static = 静态,Module = 模块,State = 状态;
HWND hGameWnd = FindWindow(NULL, "");
if (hGameWnd == NULL)
{
AfxMessageBox("未找到窗口");
return;
}
DWORD dwThreadId=::GetWindowThreadProcessId(hGameWnd, NULL);
::SetWindowsHookEx(WH_GETMESSAGE,HookerCallBack,::GetModuleHandle("fun.dll"),dwThreadId);
}