# 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 * 点击上面的数字签名
 - 选择第一个签名,查看详细信息
 - 选择 
查看证书 - 选择 
安装证书 - 存储位置选择 
本地计算机,点击下一步 将所有的证书都放入下列 存储- 点击浏览 ,选择 
受信任的根证书颁发机构 - 点击 
确认 - 点击 
下一步 - 点击 
完成导入成功即可