当前位置:   article > 正文

Windows下QT使用WinRing0控制主板的蜂鸣器响_winring0x64.dll必须以管理员模式运行吗

winring0x64.dll必须以管理员模式运行吗

一、前言

最近在windows10下用QT做项目,需要在用户进行某项操作时进行声音提示,扬声器的话一来增加成本,二来也受系统提示音困扰。搜索网上有两种解决办法,一个是WinIO的方式,这种处理起来比较麻烦,量产时费人费力还容易造成系统不稳定。另外一种就是WinRing0了,也就是这篇博客讲的。

二、使用WinRing0的几种方式

1.静态编译方式

使用这种方式对使用者的素养要求比较高,由于本人属于嵌入式开发范畴,不会将源代码编译成lib文件。这种方式需要使用者用与QT版本相同的编译器去编译,否则QT项目会在编译阶段报错。

2.动态编译方式

使用动态编译也需要自己编译WinRing0的源码,生成DLL文件及相关库文件。

3.使用QLibrary类动态调用方式

我目前使用的就是这种方法,手头上有个DLL文件以及sys驱动,因为水平有限,不会自己编译库。使用此种方式的原理就是QLibrary类的resolve方法会根据你传的函数名返回DLL中对应的函数指针。你再去执行此函数即可。

三、WinRing0驱动主板的蜂鸣器代码

1.定义一个beep类:

#include <QObject>
#include <QLibrary>

class WioBeep : public QObject{
     Q_OBJECT;
public:
    WioBeep();
    ~WioBeep();
    void beep(uint16_t ms);

private:
    QLibrary mylib;   //声明所用到的dll文件

};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

2.定义需要用到的函数指针:

#include <windows.h>
//初始化函数
typedef bool(__stdcall *InitializeWinIoType)();
typedef void(__stdcall *DeinitializeWinIoType)();

typedef DWORD(__stdcall *GetDllStatusType)();
//读取端口的数值
typedef BYTE(__stdcall *GetPortValType)(unsigned short PortAddr);
//写入端口的数值
typedef void(__stdcall *SetPortValType)(unsigned short PortAddr, unsigned long PortVal);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.编写函数构造函数:

WioBeep::WioBeep(){
    mylib.setFileName("WinRing0x64.dll");
    if (mylib.load())
            qDebug( "WinRing0x64.dll load succuse!\n");
        else
            qDebug( "WinRing0x64.dll load failed!\n");
    InitializeWinIoType pFunc = (InitializeWinIoType)mylib.resolve("InitializeOls");
    GetDllStatusType GetDllStatus = (GetDllStatusType)mylib.resolve("GetDllStatus");
    if (pFunc != NULL)
    {
       bool Result = pFunc();
       if (!Result)
       {
           DWORD str =  GetDllStatus();//获取失败原因代码
           qDebug( "Error In InitializeWinIo %d!\n",str);
       }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

4.编写析构函数

WioBeep::~WioBeep(){
    DeinitializeWinIoType pFunc = (DeinitializeWinIoType)mylib.resolve("DeinitializeOls");
    if (pFunc != NULL)
    {
        pFunc();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

5.编写beep函数(有一部分是ChatGPT写的,我具体也不是很清楚):

void WioBeep::beep(uint16_t ms){
    if (!mylib.isLoaded()){
        qDebug( "WinRing0x64.dll not load!\n");
        return;
    }

    GetPortValType ReadIoPortByte = (GetPortValType)mylib.resolve("ReadIoPortByte");
    SetPortValType WriteIoPortByte = (SetPortValType)mylib.resolve("WriteIoPortByte");

    if (ReadIoPortByte == NULL || WriteIoPortByte == NULL)
    {
        qDebug( "WinRing0x64.dll function load faild!\n");
        return;
    }

    // 设置蜂鸣器频率
    unsigned int frequency = 2000;  // 设置频率为400Hz
    unsigned short count = static_cast<unsigned short>(1193180 / frequency);  // 计算计数器的值
    unsigned char lowByte = static_cast<unsigned char>(count & 0xFF);  // 取计数器的低字节
    unsigned char highByte = static_cast<unsigned char>((count >> 8) & 0xFF);  // 取计数器的高字节

    // 控制蜂鸣器
    WriteIoPortByte(0x43, 0xB6);  // 向IO端口写入字节,设置蜂鸣器工作方式
    WriteIoPortByte(0x42, lowByte);  // 向IO端口写入字节,设置蜂鸣器计数器的低字节
    WriteIoPortByte(0x42, highByte);  // 向IO端口写入字节,设置蜂鸣器计数器的高字节

	//开启蜂鸣器
    DWORD data = ReadIoPortByte(0x61);
    data |= 0x03;
    WriteIoPortByte(0x61, data);
    Sleep(ms);

    //关闭蜂鸣器
    data = ReadIoPortByte(0x61);
    data &= 0xFC;
    WriteIoPortByte(0x61, data);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

6.主函数调用,会听见主板上的哔的一声:

WioBeep *beep = new WioBeep();
beep->beep(200);
  • 1
  • 2

四、常见问题

1.使用过程中初始化失败

确保WinRing0x64.dll和WinRing0x64.sys和你的.exe文件在同一目录下。

程序需要以管理员权限运行,QT的pro文件需要添加如下内容:

RC_FILE=main.rc
  • 1

main.rc文件放在与.pro文件同目录下,文件内容如下:

// 图标
IDI_ICON1       ICON      "/icon/main.ico"
1 24 uac.manifest
  • 1
  • 2
  • 3

uac.manifest文件放在与main.rc文件同目录下,文件内容如下:

<?xml version='1.0' encoding='UTF-8' standalone='yes'?> 
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> 
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> 
<security> 
<requestedPrivileges> 
<requestedExecutionLevel level='requireAdministrator' uiAccess='false' /> 
</requestedPrivileges> 
</security> 
</trustInfo> 
</assembly>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

如果你使用的是32位的编译器,请将相关代码及文件替换成WinRing0.dll和WinRing0.sys。

五、文件下载

工程源代码因为是公司项目,无法发出来,之后会发相关的DLL及sys文件。
百度云网盘链接
提取码:euf3

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/197481
推荐阅读
相关标签
  

闽ICP备14008679号