# WinIO 头文件
#ifndef WINIO_H | |
#define WINIO_H | |
//#include "..\drv\winio_nt.h" | |
#include "winio_nt.h" | |
#ifndef WINIO_DLL | |
#define WINIO_API _declspec(dllimport) | |
#else | |
#define WINIO_API | |
#endif | |
extern "C" | |
{ | |
//// 初始化 WinIO 函数库 | |
WINIO_API bool _stdcall InitializeWinIo(); | |
// 关闭 WinIO 函数库 | |
WINIO_API void _stdcall ShutdownWinIo(); | |
// 将物理内存映射到一个 32 位应用程序的线性地址空间 | |
WINIO_API PBYTE _stdcall MapPhysToLin(tagPhysStruct &PhysStruct); | |
// 物理映射线性:使用此函数解除原先使用 MapPhysToLin 函数映射的一段物理内存区域,该区域被映射到 | |
// 所属的线性地址空间 | |
WINIO_API bool _stdcall UnmapPhysicalMemory(tagPhysStruct &PhysStruct); | |
// 从指定的物理地址读取一个双字数据 | |
WINIO_API bool _stdcall GetPhysLong(PBYTE pbPhysAddr, PDWORD pdwPhysVal); | |
// 将一个双字型数据写入指定的物理地址 | |
WINIO_API bool _stdcall SetPhysLong(PBYTE pbPhysAddr, DWORD dwPhysVal); | |
// 从一个输入或输出端口读取一个字节 / 字 / 双字数据 | |
WINIO_API bool _stdcall GetPortVal(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize); | |
// 写一个字节 / 字 / 双字的数据写入输入或输出接口 | |
WINIO_API bool _stdcall SetPortVal(WORD wPortAddr, DWORD dwPortVal, BYTE bSize); | |
// 安装 WinIODriver | |
WINIO_API bool _stdcall InstallWinIoDriver(PWSTR pszWinIoDriverPath, bool IsDemandLoaded = false); | |
// 移除 WinIODriver | |
WINIO_API bool _stdcall RemoveWinIoDriver(); | |
} | |
extern HANDLE hDriver; | |
extern bool IsWinIoInitialized; | |
extern bool g_Is64BitOS; | |
bool _stdcall StartWinIoDriver(); | |
bool _stdcall StopWinIoDriver(); | |
#endif |
# 函数
# 初始化
本函数初始化
WioIO函数库
。必须在调用所有其他
函数之前
调用本函数
。
bool _stdcall InitializeWinlo(); |
# 关闭 WinIO
在内存中
清除WinIO
库,必须在中止函数之
前或者不需要WinIO库
时调用
void _stdcall ShutdownWinIo(); |
# 读
从一个
输入
或输出端口
读取一个
字节/字/双字
数据
bool _stdcall GetPortVal(WORD wPortAddr,PDWORD pwdPortVal,BYTE bSize); | |
//wPortAddr : 输入输出端口地址 | |
//pdwPortVal : 指向双字变量的指针, 接收从端口得到的数据 | |
//bSize : 需要读的字节数,可以是 1 (BYTE),2 (WORD) or 4 (DWORD) |
# 写
将
一个字节/字/双字
的数据写入输入或输出
接口
bool _stdcall SetPortVal(WORD wPortAddr, DWORD dwPortVal, BYTE bSize); | |
//wPortAddr 输入输出口地址 | |
//dwPortVal 要写入口的数据 | |
//bSize 要写的数据个数 可以是 1 (BYTE),2 (WORD) or 4 (DWORD) |
# 物理内存映射
将
物理内存映射
到一个32位应用程序
的线性地址空间
PBYTE _stdcall MapPhysToLin(PBYTE pbPhysAddr, DWORD dwPhysSize, HANDLE *pPhysicalMemoryHandle); | |
//pbPhyAddr -- 指向物理地址的指针 | |
//dwPhySize -- 需要映射的字节数 | |
//uPhysicalMemoryHandle 变量指针,如果调用成功,负责接收物理内存句柄,随后本句柄在调用 UnmapPhysicalMemory 函数时作为其第一个参数 | |
// 案例 | |
PBYTE pbLinAddr; | |
HANDLE PhysicalMemoryHandle; | |
pbLinAddr = MapPhysToLin(0xA0000, 65536, &PhysicalMemoryHandle); |
把物理地址范围
0xA0000 - 0xAFFFF
的地址空间映射
与应用的线性地址
空间。返回值为一个与物理地址 0xA0000 相关的线性地址。如出现错误
,则返回值NULL
# 物理映射线性
使用本函数解除原先使用
MapPhysToLin
函数映射的一段物理内存区域
,该区域被映射到应用程序所属的线性地址空间
bool _stdcall UnmapPhysicalMemory(HANDLE PhysicalMemoryHandle,PBYTE pbLinAddr); |
PhysicalMemoryHandle
–物理
内存区域的句柄
,此参数由 MapPhysToLin 函数的调用返回pbLinAddr
–MapPhysToLin
– 函数调用返回的线性地址
。
# 读双字数据
从指定的
物理地址
读取一个双字数据
bool _stdcall GetPhysLong(PBYTE pbPhysAddr,PDWORD pdwPhysVal); | |
//pbPhysAddr -- 指向物理地址的指针 | |
//pdwPhysVal -- 指向一个双字变量的指针,接收从物理内存中传来的数据 | |
// 成功 返回 非零值 | |
// 失败 返回 零值 |
# 双字型写入物理地址
将一个
双字型
数据写入
指定的物理地址
bool _stdcall SetPhysLong(PBYTE pbPhysAddr,DWORD dwphysVal); | |
//pbPhysAddr -- 指向物理地址的指针 | |
//pdwPhysVal -- 指向待写入物理内存地址的双字型数据 |
# GetProcAddress 函数
用于
获取DLL
中导出函数的地址
(显式链接使用)
GetProcAddress
将 DLL 模块处理 (由LoadLibrary
, 或GetModuleHandle
返回的参数
),并采用要调用的函数的名称
或函数的导出序号
因为通过
指针
调用DLL函数
,并且没有编译时
类型检查,所以确保
参数正确
,以便不会
超过在堆栈上
分配的内存
以及导致访问冲突
。帮助提供类型安全的一种方法时查看导出函数
的函数原型
,并为函数指针创建匹配的typedef
。
# 官方 demo
#include "windows.h" | |
typedef HRESULT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT*); | |
HRESULT LoadAndCallSomeFunction(DWORD dwParam1, UINT * puParam2) | |
{ | |
HINSTANCE hDLL; // Handle to DLL | |
LPFNDLLFUNC1 lpfnDllFunc1; // Function pointer | |
HRESULT hrReturnVal; | |
hDLL = LoadLibrary("MyDLL"); | |
if (NULL != hDLL) | |
{ | |
lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "DLLFunc1"); | |
if (NULL != lpfnDllFunc1) | |
{ | |
// call the function | |
hrReturnVal = lpfnDllFunc1(dwParam1, puParam2); | |
} | |
else | |
{ | |
// report the error | |
hrReturnVal = ERROR_DELAY_LOAD_FAILED; | |
} | |
FreeLibrary(hDLL); | |
} | |
else | |
{ | |
hrReturnVal = ERROR_DELAY_LOAD_FAILED; | |
} | |
return hrReturnVal; | |
} |
如何指定
调用GetProcAddress时
所需的函数取决于DLL的
生成方式。仅当要
链接到DLL
使用模块定义 (.def
) 文件生成,并且序号随函数在DLL.def
文件的EXPORTS节
中列出时,才能获取导出序号
。如果DLL
具有许多导出函数,则与使用函数名称相比,使用导出
需要调用GetProcAddress
会稍微快一些,
因为导出序号充当 DLL 导出表中的索引。使用导出序号,GetProcAddress
可以直接查找函数
,而不是将指定名称与 DLL 导出表中的函数名进行比较。但是当仅当可控制将序号分配给.def文件
中的导出函数时,才应使用导出序号
调用GetProcAddress
# Qt 环境搭建
# pro 文件
DEFINES += WINIO_DLL | |
unix|win32: LIBS += -L$$PWD/./ -lWinIo64 | |
RESOURCES += \ | |
source.qrc |
# 头文件存储函数指针
typedef bool( _stdcall* LS_GetPhysLong)(PBYTE pbPhysAddr, PDWORD pdwPhysVal); | |
typedef bool( _stdcall* LS_SetPhysLong)(PBYTE pbPhysAddr, DWORD dwPhysVal); | |
typedef bool( _stdcall* LS_InitializeWinIo)(); | |
typedef bool( _stdcall* LS_ShutdownWinIo)(); | |
typedef bool( _stdcall* LS_GetPortVal)(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize); | |
typedef bool( _stdcall* LS_SetPortVal)(WORD wPortAddr, DWORD dwPortVal, BYTE bSize); | |
// 对函数指针进行重定义。 | |
LS_GetPhysLong Lib_GetPhysLong; | |
LS_SetPhysLong Lib_SetPhysLong; | |
LS_InitializeWinIo Lib_InitializeWinIo; | |
LS_ShutdownWinIo Lib_ShutdownWinIo; | |
LS_SetPortVal Lib_SetPortVal; | |
LS_GetPortVal Lib_GetPortVal; | |
HMODULE m_hDllFile; // 初始化 WinIO 文件 |
# 函数初始化
放到函数的头文件中
// 加载动态链接库,并通过 GetProcAddress 方法调用取函数空间地址 | |
// @ 传入所需的动态链接库 | |
// 返回 m_hDllFile 将作为 GetProcAddress 去调用 WinIO 的函数地址使用 | |
m_hDllFile = LoadLibrary(L"WinIo64"); | |
if(m_hDllFile == NULL) | |
{ | |
Bugart("加载WinIo64失败"); | |
} | |
// 对函数指针初始化 Lib_InitializeWinIo -> InitializeWinIo | |
Lib_InitializeWinIo=(LP_InitializeWinIo)::GetProcAddress(m_hDllFile,"InitializeWinIo"); | |
if(NULL == Lib_InitializeWinIo) | |
{ | |
Bugart("load error Lib_InitializeWinIo "); | |
} | |
//qDebug ()<< "后:"<< Lib_InitializeWinIo; | |
// 函数指针初始化 Lib_ShutdownWinIo -> ShutdownWinIo | |
Lib_ShutdownWinIo=(LP_ShutdownWinIo)::GetProcAddress(m_hDllFile,"ShutdownWinIo"); | |
if(NULL == Lib_ShutdownWinIo) | |
{ | |
Bugart("load error Lib_ShutdownWinIo "); | |
} | |
// 函数指针初始化 Lib_GetPhysLong -> GetPhysLong | |
Lib_GetPhysLong=(LP_GetPhysLong)::GetProcAddress(m_hDllFile,"GetPhysLong"); | |
if(NULL == Lib_GetPhysLong) | |
{ | |
Bugart("load error Lib_GetPhysLong "); | |
} | |
// 函数 Lib_SetPhysLong -> SetPhysLong | |
Lib_SetPhysLong=(LP_SetPhysLong)::GetProcAddress(m_hDllFile,"SetPhysLong"); | |
if(NULL == Lib_SetPhysLong) | |
{ | |
Bugart("load error Lib_SetPhysLong "); | |
} | |
Lib_SetPortVal=(LP_SetPortVal)::GetProcAddress(m_hDllFile,"SetPortVal"); | |
if(NULL==Lib_SetPortVal) | |
{ | |
Bugart("load error Lib_SetPortVal "); | |
} | |
// 初始化操作 | |
Lib_GetPortVal=(LP_GetPortVal)::GetProcAddress(m_hDllFile,"GetPortVal"); | |
if(NULL==Lib_GetPortVal) | |
{ | |
Bugart("load error Lib_GetPortVal "); | |
} |
# Qt WinIO 调用
确保自己 系统处于
测试模式
\n以管理员权限运行
CMD
\n在输入框输入 \n
bcdedit /set testsigning on # 并执行 重启即可进入测试模 |
- 确保使用
管理员权限
打开软件 \n - 确保
使用的版本
与设备型号
一致 \n
- 确保
- 确保将
软件
目录的WinIo64.sys
文件的签名
安装到本地
。
- 确保将
- 右键点击
WinIo64.sys
- 点击属性 \n * 点击上面的数字签名
- 选择第一个签名,查看详细信息
- 选择
查看证书
- 选择
安装证书
- 存储位置选择
本地计算机
,点击下一步
将所有的证书都放入下列 存储
- 点击浏览 ,选择
受信任
的根证书颁发机构 - 点击
确认
- 点击
下一步
- 点击
完成
导入成功即可