Repository: peng-zhihui/TrafficMonitor Branch: master Commit: 5ac1625134bf Files: 205 Total size: 1.1 MB Directory structure: gitextract_vr76zmf_/ ├── .github/ │ └── workflows/ │ └── main.yml ├── .gitignore ├── Help.md ├── Help_en-us.md ├── LICENSE ├── LICENSE_CN ├── OpenHardwareMonitorApi/ │ ├── LibreHardwareMonitorLib.xml │ ├── OpenHardwareMonitorApi.vcxproj │ ├── OpenHardwareMonitorApi.vcxproj.filters │ ├── OpenHardwareMonitorImp.cpp │ ├── OpenHardwareMonitorImp.h │ ├── ReadMe.txt │ ├── Stdafx.cpp │ ├── Stdafx.h │ ├── UpdateVisitor.cpp │ ├── UpdateVisitor.h │ ├── app.rc │ └── resource.h ├── PluginDemo/ │ ├── CustomDrawItem.cpp │ ├── CustomDrawItem.h │ ├── DataManager.cpp │ ├── DataManager.h │ ├── OptionsDlg.cpp │ ├── OptionsDlg.h │ ├── PluginDemo.cpp │ ├── PluginDemo.h │ ├── PluginDemo.rc │ ├── PluginDemo.vcxproj │ ├── PluginDemo.vcxproj.filters │ ├── PluginSystemDate.cpp │ ├── PluginSystemDate.h │ ├── PluginSystemTime.cpp │ ├── PluginSystemTime.h │ ├── framework.h │ ├── pch.cpp │ ├── pch.h │ └── resource.h ├── README.md ├── README_en-us.md ├── TrafficMonitor/ │ ├── AboutDlg.cpp │ ├── AboutDlg.h │ ├── AdapterCommon.cpp │ ├── AdapterCommon.h │ ├── AppAlreadyRuningDlg.cpp │ ├── AppAlreadyRuningDlg.h │ ├── BaseDialog.cpp │ ├── BaseDialog.h │ ├── CAutoAdaptSettingsDlg.cpp │ ├── CAutoAdaptSettingsDlg.h │ ├── CMFCColorDialogEx.cpp │ ├── CMFCColorDialogEx.h │ ├── CPUUsage.cpp │ ├── CPUUsage.h │ ├── CSkinPreviewView.cpp │ ├── CSkinPreviewView.h │ ├── CTabCtrlEx.cpp │ ├── CTabCtrlEx.h │ ├── CVariant.cpp │ ├── CVariant.h │ ├── CalendarHelper.cpp │ ├── CalendarHelper.h │ ├── ColorSettingListCtrl.cpp │ ├── ColorSettingListCtrl.h │ ├── ColorStatic.cpp │ ├── ColorStatic.h │ ├── ComboBox2.cpp │ ├── ComboBox2.h │ ├── Common.cpp │ ├── Common.h │ ├── CommonData.cpp │ ├── CommonData.h │ ├── DisplayTextSettingDlg.cpp │ ├── DisplayTextSettingDlg.h │ ├── DonateDlg.cpp │ ├── DonateDlg.h │ ├── DrawCommon.cpp │ ├── DrawCommon.h │ ├── DrawCommonEx.cpp │ ├── DrawCommonEx.h │ ├── FilePathHelper.cpp │ ├── FilePathHelper.h │ ├── GeneralSettingsDlg.cpp │ ├── GeneralSettingsDlg.h │ ├── HighResolutionTimer.h │ ├── HistoryTrafficCalendarDlg.cpp │ ├── HistoryTrafficCalendarDlg.h │ ├── HistoryTrafficDlg.cpp │ ├── HistoryTrafficDlg.h │ ├── HistoryTrafficFile.cpp │ ├── HistoryTrafficFile.h │ ├── HistoryTrafficListCtrl.cpp │ ├── HistoryTrafficListCtrl.h │ ├── HistoryTrafficListDlg.cpp │ ├── HistoryTrafficListDlg.h │ ├── IconSelectDlg.cpp │ ├── IconSelectDlg.h │ ├── IniHelper.cpp │ ├── IniHelper.h │ ├── LinkStatic.cpp │ ├── LinkStatic.h │ ├── ListCtrlEx.cpp │ ├── ListCtrlEx.h │ ├── MainWndColorDlg.cpp │ ├── MainWndColorDlg.h │ ├── MainWndSettingsDlg.cpp │ ├── MainWndSettingsDlg.h │ ├── MessageDlg.cpp │ ├── MessageDlg.h │ ├── NetworkInfoDlg.cpp │ ├── NetworkInfoDlg.h │ ├── OptionsDlg.cpp │ ├── OptionsDlg.h │ ├── PictureStatic.cpp │ ├── PictureStatic.h │ ├── PluginInfoDlg.cpp │ ├── PluginInfoDlg.h │ ├── PluginManager.cpp │ ├── PluginManager.h │ ├── PluginManagerDlg.cpp │ ├── PluginManagerDlg.h │ ├── ReadMe.txt │ ├── SelectConnectionsDlg.cpp │ ├── SelectConnectionsDlg.h │ ├── SetItemOrderDlg.cpp │ ├── SetItemOrderDlg.h │ ├── SimpleXML.cpp │ ├── SimpleXML.h │ ├── SkinDlg.cpp │ ├── SkinDlg.h │ ├── SkinFile.cpp │ ├── SkinFile.h │ ├── SpinEdit.cpp │ ├── SpinEdit.h │ ├── StaticEx.cpp │ ├── StaticEx.h │ ├── TabDlg.cpp │ ├── TabDlg.h │ ├── TaskBarDlg.cpp │ ├── TaskBarDlg.h │ ├── TaskBarSettingsDlg.cpp │ ├── TaskBarSettingsDlg.h │ ├── TaskbarColorDlg.cpp │ ├── TaskbarColorDlg.h │ ├── TaskbarDefaultStyle.cpp │ ├── TaskbarDefaultStyle.h │ ├── TaskbarItemOrderHelper.cpp │ ├── TaskbarItemOrderHelper.h │ ├── Test.cpp │ ├── Test.h │ ├── TinyXml2Helper.cpp │ ├── TinyXml2Helper.h │ ├── TrafficMonitor.cpp │ ├── TrafficMonitor.h │ ├── TrafficMonitor.rc │ ├── TrafficMonitor.vcxproj │ ├── TrafficMonitor.vcxproj.filters │ ├── TrafficMonitorDlg.cpp │ ├── TrafficMonitorDlg.h │ ├── UpdateHelper.cpp │ ├── UpdateHelper.h │ ├── WIC.cpp │ ├── WIC.h │ ├── WinVersionHelper.cpp │ ├── WinVersionHelper.h │ ├── WindowsSettingHelper.cpp │ ├── WindowsSettingHelper.h │ ├── auto_start_helper.cpp │ ├── auto_start_helper.h │ ├── crashtool.cpp │ ├── crashtool.h │ ├── print_compile_time.bat │ ├── res/ │ │ ├── Acknowledgement.txt │ │ ├── Acknowledgement_en.txt │ │ └── TrafficMonitor.rc2 │ ├── resource.h │ ├── skins/ │ │ ├── 0默认皮肤/ │ │ │ └── skin.ini │ │ ├── xml_test/ │ │ │ └── skin.xml │ │ ├── 皮肤01/ │ │ │ └── skin.ini │ │ ├── 皮肤02/ │ │ │ └── skin.ini │ │ ├── 皮肤03/ │ │ │ └── skin.ini │ │ ├── 皮肤04/ │ │ │ └── skin.ini │ │ ├── 皮肤05/ │ │ │ └── skin.ini │ │ ├── 皮肤06/ │ │ │ └── skin.ini │ │ ├── 皮肤07/ │ │ │ └── skin.ini │ │ ├── 皮肤08/ │ │ │ └── skin.ini │ │ ├── 皮肤09/ │ │ │ └── skin.ini │ │ ├── 皮肤10/ │ │ │ └── skin.ini │ │ ├── 皮肤10(竖排)/ │ │ │ └── skin.ini │ │ ├── 皮肤11/ │ │ │ └── skin.ini │ │ └── 默认皮肤2/ │ │ └── skin.ini │ ├── stdafx.cpp │ ├── stdafx.h │ ├── targetver.h │ └── tinyxml2/ │ ├── tinyxml2.cpp │ └── tinyxml2.h ├── TrafficMonitor.sln ├── UpdateLog/ │ ├── update_log.md │ ├── update_log_en-us.md │ └── update_log_zh-tw.md ├── include/ │ ├── OpenHardwareMonitor/ │ │ ├── OpenHardwareMonitorApi.h │ │ └── OpenHardwareMonitorGlobal.h │ └── PluginInterface.h ├── version.info ├── version_utf8.info └── 皮肤制作教程.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/main.yml ================================================ name: Release CI on: push jobs: x64_build: runs-on: windows-2019 steps: - uses: actions/checkout@v2 - name: Add msbuild to PATH uses: microsoft/setup-msbuild@v1 - name: Run msbuild run: msbuild -p:configuration=release -p:platform=x64 -p:platformToolset=v142 - name: Get current time uses: 1466587594/current-time@v1 id: current-time with: format: YYYYMMDD_HHmmss utcOffset: "+08:00" - name : Upload artifact uses: actions/upload-artifact@v2 with: name: x64_${{ steps.current-time.outputs.formattedTime }}_TrafficMonitor path: | Bin/x64/Release/TrafficMonitor.exe Bin/x64/Release/*.dll - name : Upload pdb files uses: actions/upload-artifact@v2 with: name: x64_${{ steps.current-time.outputs.formattedTime }}_pdb path: Bin/x64/Release/*.pdb x86_build: runs-on: windows-2019 steps: - uses: actions/checkout@v2 - name: Add msbuild to PATH uses: microsoft/setup-msbuild@v1 - name: Run msbuild run: msbuild -p:configuration=release -p:platform=x86 -p:platformToolset=v142 - name: Get current time uses: 1466587594/current-time@v1 id: current-time with: format: YYYYMMDD_HHmmss utcOffset: "+08:00" - name : Upload artifact uses: actions/upload-artifact@v2 with: name: x86_${{ steps.current-time.outputs.formattedTime }}_TrafficMonitor path: | Bin/Release/TrafficMonitor.exe Bin/Release/*.dll - name : Upload pdb files uses: actions/upload-artifact@v2 with: name: x86_${{ steps.current-time.outputs.formattedTime }}_pdb path: Bin/Release/*.pdb # winXP_build: # runs-on: windows-latest # steps: # - uses: actions/checkout@v2 # - name: Add msbuild to PATH # uses: microsoft/setup-msbuild@v1 # - name: Run msbuild # run: | # set ExternalCompilerOptions=/DCOMPILE_FOR_WINXP # msbuild -p:configuration=release -p:platform=x86 -p:platformToolset=v140_xp # shell: cmd # - name: Get current time # uses: 1466587594/current-time@v1 # id: current-time # with: # format: YYYYMMDD_HHmmss # utcOffset: "+08:00" # - name : Upload artifact # uses: actions/upload-artifact@v1 # with: # name: winXP_${{ steps.current-time.outputs.formattedTime }}_TrafficMonitor # path: Bin/Release/TrafficMonitor.exe ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # .NET Core project.lock.json project.fragment.lock.json artifacts/ **/Properties/launchSettings.json *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # TODO: Comment the next line if you want to checkin your web deploy settings # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Typescript v1 declaration files typings/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # JetBrains Rider .idea/ *.sln.iml # CodeRush .cr/ # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs *.ini !skin.ini *.dat *.bak /TrafficMonitor/skins/test* [Dd]ebug (without temperature)/ [Rr]elease (without temperature)/ [Dd]ebug (lite)/ [Rr]elease (lite)/ /TrafficMonitor/compile_time.txt ================================================ FILE: Help.md ================================================ **简体中文 | [English](./Help_en-us.md)**
# TrafficMonitor 常见问题 这里是关于TrafficMonitor常见问题的页面,如果你想查看关于TrafficMonitor的各项功能和使用方法的详细介绍,请[点击这里](https://github.com/zhongyang219/TrafficMonitor/wiki)转到TraffinMonitor Wiki页面。 ### 1. 如何显示CPU和内存利用率? 在主窗口点击右弹出键菜单,勾选“显示更多信息”。如果需要在任务栏窗口中也显示CPU和内存利用率,则在任务栏窗口中点击右键弹出菜单,在“显示设置”子菜单下勾选“CPU和内存利用率”即可。 ### 2. 如何单独设置任务栏窗口中每个项目的颜色? 在右键菜单中选择“选项”,切换到“任务栏窗口设置”,勾选“指定每个项目的颜色”,此时再点击“文本颜色”右边的颜色块,就会弹出“任务栏窗口颜色设置”的对话框了。
如果不勾选“指定每个项目的颜色”,则只能为文本设置统一的颜色。 ### 3. 设置了开机自动运行仍然无法开机自启。 从1.80版本开始,包含温度监控的版本和不含温度监控的版本采用了不同的方式来实现开机自启动。 * 不含温度监控的版本和1.80以前的版本: 不含温度监控的版本和1.80以前的版本的开机启动功能是通过在注册表“计算机\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run”中创建“TrafficMonitor”的注册表项来实现的,如果你遇到无法开机启动的问题,请先检查该注册表项是否存在,再检查程序的路径是否正确。如果你移动了程序的位置,则会因为路径无效导致开机自启动失效,此时只需要在选项设置中取消“开机自动运行”的勾选,再将其勾选上就可以了。
注意,某些第三方安全软件可能会阻止TrafficMonitor的开机自启动,请尝试在安全软件中允许TrafficMonitor开机自启动。 如果设置了以管理员身份运行也会出现开机无法自启动的问题,请尝试去掉以管理员身份运行。
* 包含温度监控的版本: 包含温度监控的版本是通过创建任务计划来实现开机自启动的。可以通过`控制面板\系统和安全\管理工具`来打开任务计划程序。 如下图所示: 如果你遇到无法开机自启动的情况,请到“任务计划程序”中检查TrafficMonitor的计划任务是否正常创建,exe文件的路径是否正确。 开机无法自启动的一个常见原因是你可能移动了TrafficMonitor主程序的位置。如果你为TrafficMonitor设置好了开机自动运行,但是你将TrafficMonitor移动到了其他位置,那么开机自启动肯定就失效了。你需要打开TrafficMonitor的“选项设置”——“常规设置”,如果“开机时自动运行”处于勾选状态,先去掉勾选,然后再次打开“选项设置”——“常规设置”,重新勾选“开机时自动运行”即可。 需要注意的是,如果你使用不含温度监控的版本在注册表中创建了开机自启动项,然后再使用包含温度监控的版本开启开机自启动功能,它会自动将注册表中的开机自启动项删除,再在任务计划中创建开机自启动项。反之亦然。 ### 4. 程序弹出“无法保存设置”的对话框。 如果遇到这种情况,说明程序没有向其所在目录下写入数据的权限,导致设置数据无法保存。尝试将程序移动到其他有写入权限的文件夹中可以解决这个问题。
你也可以通过以下步骤将配置文件的保存路径改为C:\Users\\<用户名\>\AppData\Roaming\TrafficMonitor目录。
* 退出TrafficMonitor,以管理员身份重新启动TrafficMonitor。 * 在右键菜单中选择“选项”,切换到“常规设置”选项卡,在“数据和配置文件”中选择“保存到Appdata目录”。
如果此时仍然提示“无法保存设置”,请打开应用程序所在目录,打开`global_cfg.ini`文件,如果不存在请新建一个,在里面添加如下内容: ``` [config] portable_mode = true ``` 如果无法新建,可以在其他位置(比如桌面)新建该文件,然后移动到程序所在目录。 如果`global_cfg.ini`文件已存在,就把`portable_mode `的值改成`true`,保存后重新启动TrafficMonitor。 如果`global_cfg.ini`没有写入权限,可以尝试把该文件复制到桌面,改好后复制回原来的路径将原文件覆盖。 执行以上步骤后理论上应该不会出现这种问题了。如果这个问题仍然出现,请尝试把C:\Users\\<用户名\>\AppData\Roaming\TrafficMonitor\config.ini删除,该文件会在删除后重新生成。 在1.79以后的版本中,如果程序所在目录无法写入数据,会自动将配置和数据文件保存到C:\Users\\<用户名\>\AppData\Roaming\TrafficMonitor目录,此时,“选项”——“常规设置”——“数据和配置文件”中“保存到程序所在目录”将不可用。 ### 5. 多显示器时悬浮窗只能在主显示器中显示。 默认情况下做了让悬浮窗无法超出屏幕边界的处理,如果需要将悬浮窗移动到其他显示器,请在悬浮窗中点击右键弹出菜单,选择“其他功能”,勾选“允许超出屏幕边界”,此时悬浮窗不再限制在屏幕内,也能移动到任意显示器中了。
如果移除额外的显示器,那么悬浮窗可能会出现在屏幕区域外导致不可见,此时只需要在通知区域图标上点击鼠标右键,选择“其他功能”,去掉“允许超出屏幕边界”的勾选,悬浮窗就会重新出现屏幕范围内了。 ### 6. 网速数值显示不全。 由于不同字体每个字符的宽度并不一样,在某些情况下,确实会出现网速数值显示不全的问题。如果出现了这样的问题,请打开“选项”——“任务栏窗口设置”,在“数据位数”下拉列表中选择一个更大的值。 ### 7. 设置了鼠标穿透后如何取消? 在通知区的TrafficMonitor的图标上点击鼠标右键,去掉“鼠标穿透”的勾选即可。
设置了鼠标穿透后,悬浮窗将无法响应任何鼠标消息,也无法弹出右键菜单,但是可以通过通知区图标来弹出右键菜单。主窗口的右键菜单和通知区图标的右键是完全一样的。
另外,即使你之前设置了隐藏通知区图标,开启鼠标穿透后,通知区图标也会自动显示出来,防止无法弹出右键菜单。
说明:以下几种情况下通知区图标会自动显示出来:
* 开启鼠标穿透后; * 不显示任务栏窗口的情况下隐藏主窗口后; * 隐藏主窗口的情况下关闭任务栏窗口后; * 开启鼠标穿透的情况下关闭任务栏窗口后。 ### 8. Windows 10 白色任务栏主题时任务栏窗口颜色的问题 在使用白色任务栏主题时,你可以在在“任务栏窗口设置”点击“预设方案”按钮,选择“浅色模式”,可以一键设置浅色模式任务栏颜色。如图所示: 同时,你还可能勾选“自动适应Windows10深色/浅色主题”,程序会在Windows10深色/浅色主题更换时自动切换颜色方案。你可以点击“自动适应设置”按钮来配置在深色和浅色主题时分别使用哪个颜色预设。 ### 9. 在Windows7/Windows8/8.1下任务栏窗口有个背景色,无法完全透明 这个问题确实存在,但是在Win10下是正常的。这个问题暂时无法解决。 在1.79以后的版本中,Windows8/8.1下可以在“选项”——“任务栏窗口设置”中勾选“背景色透明”,再勾选“根据任务栏颜色自动设置背景色”即可获得较好的显示效果。 ### 10. 任务栏窗口有时会显示不全,比如单位被覆盖了 这确实是一个BUG,但是我目前还没有找到一个好的解决方法,这个问题通常出现在任务栏右侧通知区域宽度变化的时候,主要在在切换输入法的时候,如果出现了这个问题,可以将通知区任意一个图标向上拖动将其隐藏,再将其拖下来即可恢复正常。
出现这个问题原因在于,由于系统任务栏通知区的图标数量可能会发生变化,导致通知区的宽度也会时常变化,当通知区的宽度发生变化时,TrafficMonitor的任务栏窗口需要实时调整其位置。但是由于我无法知道通知区的宽度在什么时候变化,因此只能每隔一段时间判断是否需要调整位置,如果任务栏通知区域的宽度变化得太快,就会导致TrafficMonitor的任务栏无法及时调整其位置,从而导致了这个BUG。
#### 以下步骤或许可以解决这个问题:
* 打开“设置” * 点击“时间和语言”——“区域和语言” * 点击右侧“高级键盘设置” * 勾选“使用桌面语言栏” * 右键点击任务栏,选择“任务栏设置” * 点击“打开或关闭系统图标”,关闭“输入指示”
方法来自知乎 [win10的任务栏为何一点击就乱动?](https://www.zhihu.com/question/312032145/answer/627965084)
### 11. Windows10中开启HDR后任务栏窗口无法显示 部分用户反馈,在Windows10中开始HDR功能会导致任务栏窗口无法显示。如果遇到这个问题,可以尝试在[“选项设置”——“任务栏窗口设置”](https://github.com/zhongyang219/TrafficMonitor/wiki/选项设置#任务栏窗口设置)中关闭“背景透明”选项的勾选。 ### 12. CPU利用率显示和任务管理器不一致 在Windows10及以上操作系统中,如果你需要让TrafficMonitor显示的CPU利用率和任务管理器一致,请到[“选项设置”——“常规设置”——“高级”](https://github.com/zhongyang219/TrafficMonitor/wiki/选项设置#高级)——“CPU使用率获取方式”中选择“使用性能计数器”。 由于Windows10以上操作系统中任务管理器获取CPU利用率的方式发生了改变,因此选择“基于CPU使用时间”的方式获取到的CPU利用率会和任务管理器中显示的不一致。 ### 13. 关于TrafficMonitor温度监控的问题 由于温度监控功能在某些电脑中存在一些问题,因此温度监控功能默认是关闭的,如果你要使用TrafficMonitor的温度监控功能,请到[“选项设置”-“常规设置”-“硬件监控”](https://github.com/zhongyang219/TrafficMonitor/wiki/选项设置#硬件监控)中开启。开启后,任务栏右键菜单中的“显示设置”子菜单下才会出现温度相关的项目。 TrafficMonitor的温度监控功能依赖第三方开源库[LibreHardwareMonitor](https://github.com/LibreHardwareMonitor/LibreHardwareMonitor)。如果你遇到硬件温度无法显示,或者显示的温度异常的问题,请先下载LibreHardwareMonitor,并查看LibreHardwareMonitor是否能正常显示对应的温度。 如果LibreHardwareMonitor也无法显示对应硬件的温度,那么我也无法解决这个问题,你可以向LibreHardwareMonitor作者反馈你的问题。 如果LibreHardwareMonitor可以正常显示对应硬件的温度,请向我反馈这个问题,同时提供LibreHardwareMonitor的截图,以便我调查你的问题。 **注意:硬件监控功能(包括温度监控和显卡使用率监控)可能存在一些问题,它可能会占用更多的CPU和内存。据部分用户反馈,开启温度功能后会导致程序崩溃和系统死机等问题,请在知晓以上风险后再决定开启硬件监控功能。否则,请不要使用硬件监控功能。** ## 14. 程序启动时提示找不到“MSVC\*.dll”或“mfc\*.dll” 点击以下链接下载并安装Microsoft Visual C++ 运行环境。 [最新支持的 Visual C++ 可再发行程序包下载 | Microsoft Docs](https://docs.microsoft.com/zh-CN/cpp/windows/latest-supported-vc-redist?view=msvc-170)
>如果还遇到其他问题,请点击“关于”对话框中的“联系作者”,或者直接[点击此处](mailto:zhongyang219@hotmail.com)向我发送电子邮件。但我由于作者的能力有限,我并不能保证可以解决所有问题,但是你的反馈也许可以帮助我更好的改进这个软件。
请在邮件中尽可能详细地描述你遇到的问题,出现了什么错误提示,你尝试过哪些操作等,最好能够附上截图和配置文件(“选项”——“常规设置”——“打开配置文件所在路径”)。
注意,发送前请先确认一下你发送时使用的电子邮件地址,如果你的邮件地址是形如“outlook_随机字符串@outlook.com”的格式,那么这样的邮箱地址是无法回复的。 这可能是由于你使用了第三方邮箱地址作为Microsoft账号登录Windows导致的。如果有这样的情况,请务必在邮件中附上正确的电子邮件地址。 ================================================ FILE: Help_en-us.md ================================================ **[简体中文](./Help.md) | English**
# TrafficMonitor Frequently Asked Questions This is the page about the Frequently Asked Questions of TrafficMonitor. If you want to view the detailed introduction of the functions and usage of TrafficMonitor, please [click here](https://github.com/zhongyang219/TrafficMonitor/wiki) to go the the TraffinMonitor Wiki page (Only Chinese Available). ### 1. How to show the CPU and memory usage? Right click the main window and check "Show More Info". If you also need to display the CPU and memory usage in the taskbar window, right click the taskbar window and check "CPU and Memory Usage" in the "Display Settings" sub menu. ### 2. How do I set the color of each item in the taskbar window individually? Select "Options" In the right-click menu, switch to "Taskbar Window Settings" tab, check "Specify colors for each item", and then click the color block on the right side of "Text Color " to pop up the dialog box for taskbar window color settings.
If you do not check "Specify colors for each item", you can only set the uniform color for the text. ### 3. "Auto run when Windows start" dose not work Starting from version 1.80, the version with temperature monitoring and the version without temperature monitoring have adopted different methods to realize "auto run when Windows start". * Versions without temperature monitoring and versions before 1.80: The auto run function of the versions without temperature monitoring and versions before 1.80 is achieved by creating the "TrafficMonitor" key in the registry path of "Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run". If you encounter the problem of auto run dose not work, please check that the registry exists, and then check the program path is correct. If you move the location of the program, the auto run will be invalid because of the program location being invalid. In this case, you only need to uncheck "Auto run when Windows start" in the option settings, and then check it on.
Note that some third-party security software may prevent TrafficMonitor from booting up automatically. Please try to allow TrafficMonitor to boot up automatically in the security software. If you set the program to run as an administrator, the auto run function will also not work. Please try to remove running as an administrator.
* Version with temperature monitoring: The version that includes temperature monitoring implements auto run function by creating a task plan. The task scheduler can be opened through `Control Panel\System and Security\Administrative Tools`. As shown below: If you encounter that situation that the program cannot be started automatically after booting, please go to "Task Scheduler" to check whether the scheduled task of TrafficMonitor is created normally and the path of the exe file is correct. A common reason why the "Auto run when Windows start" dose not work is that you may have moved the location of the TrafficMonitor main program. If you have set up TrafficMonitor to run automatically at startup, but you move TrafficMonitor to another location, then the auto run at startup will definitely fail. You need to open "Option Settings"-"General Settings" of TrafficMonitor, if "Auto run when Windows start" is checked, remove the check, then open "Option Settings"-"General Settings" again, and check again "Auto run when Windows start" will be fine. It should be noted that if you use the version without temperature monitoring to create a auto-start item in the registry, and then use the version that with temperature monitoring to turn on the "Auto run when Windows start" function, it will automatically delete the auto-start item in the registry, and then create a auto-start item in the task plan. vice versa. ### 4. The program pops up the "Unable to Save Settings" message box. If you encountered this problem, that means the program does not have permission to write data to its directory, causing the settings data cannot be saved. Try to move the program to another folder that has write permissions will save this problem.
You can also change the save path of the configuration and data file to the C:\Users\\\AppData\Roaming\TrafficMonitor directory by the following steps.
* Exit TrafficMonitor and restart TrafficMonitor as an administrator. * Select "Options" in the right-click menu, switch to the "General Settings" tab, and select "Save to Appdata Directory" in "Configuration and data files". If it still pops up the "Unable to Save Settings" message box, open the directory where the application is located, open the `global_cfg.ini` file. If it doesn't exist, create a new one, adding the following: ``` [config] portable_mode = true ``` If the file cannot be created, you can create the file in a different location, such as the desktop, and then move to the directory where the program is located. If the `global_cfg.ini` file already exists, change the value of `portable_mode` to `true` and save, then restart TrafficMonitor. If `global_cfg.ini` does not have write permission, you can try copying the file to the desktop, and then copying it back to the original path to overwrite the original file after modified. After these steps, this problem should not theoretically occur. If this problem still occurs, try to delete the file C:\Users\\\AppData\Roaming\TrafficMonitor\config.ini. This file will be regenerated after it is deleted. In version 1.79 and later, if the directory where the program located is not writable, the configuration and data files will be automatically saved to the "C:\Users\\\AppData\Roaming\TrafficMonitor" directory. At this time, "Options" -“General Settings”-“Save to the program directory” in “Configuration and data files” will not be available. ### 5. The suspension window can only be displayed on the main monitor when multiple monitors are present. By default, the suspension window cannot be moved out of the screen boundaries. If you need to move the suspension window to other monitors, please right click the suspension window, select "Other Functions", check "Allow Out of Screen Boundaries". At this time the suspension window is no longer limited to the screen, it can be also move to any monitors.
If you remove the extra monitor, then the suspension window may appear outside the screen area to cause the invisible. At this time, you only need to right click the the icon in the notification area, select "Other function", uncheck "Allow Out of Screen Boundaries", the suspension window will appear in the screen area again. ### 6. The net speed value is not fully displayed. Because the width of each character in different fonts is not the same, in some cases, it does appear the problem of the net speed value is not fully displayed. If this problem occurs, open "Options"-"Taskbar Window Settings", and select a larger value in the "Number of digits" drop down list. ### 7. How to cancel after setting the mouse penetrate? Right click the TrafficMonitor icon in the notification area, uncheck the "Mouse Penetrate".
After the mouse penetrate is set, the suspension window will not be able to respond to any mouse messages, or pop-up right-click menu. But the menu can be poped up by right click the icon in notification area. The right-click menu of the main window and which of the notification area icon is exactly the same.
In addition, even if you have previously set the hidden notify icon, when the "mouse penetrate" is set, the notify icon will also automatically appear to prevent the right-click menu cannot be displayed.
Note: The notification area icon will be automatically displayed in the following situations:
* After the "Mouse Penetrate" is set; * Hide the main window without displaying the taskbar window; * Close the taskbar window when the main window is hidden; * Close the taskbar window when the "Mouse Penetrate" is set. ### 8. Problems with the taskbar window color in Windows 10 white taskbar theme When using the white taskbar theme, you can click the "Preset" button in the "Taskbar Window Settings" and select "Light Mode" to set the taskbar color in light mode. As the picture shows: At the same time, you may also check "Auto adapt to Windows 10 dark/light theme", the program will automatically switch the color preset when Windows 10 dark/light theme is changed. You can click the "Auto Adapt settings" button to configure which color preset to use for dark and light themes. ### 9. The taskbar windows cannot be displayed when the HDR is turned on in Windows 10 Some users have reported that turning on the HDR function in Windows 10 will cause the taskbar window to fail to display. If you encounter this problem, you can try turning off the "Background Transparent" option in ["Option Settings" - "Taskbar Window Settings"](https://github.com/zhongyang219/TrafficMonitor/wiki/选项设置#任务栏窗口设置). ### 13. About the temperature monitoring of TrafficMonitor Due to some problems occurred in some computers caused by the temperature monitoring function, the temperature monitoring function is turned off by default. If you want to use the temperature monitoring function of TrafficMonitor, please go to ["Option Settings"-"General Settings"-"Hardware Monitoring"](https://github.com/zhongyang219/TrafficMonitor/wiki/选项设置#硬件监控) to enable it. After it is turned on, temperature-related items will appear under the "Display Settings" submenu in the taskbar right-click menu. The temperature monitoring function of TrafficMonitor relies on a third-party open source library [LibreHardwareMonitor](https://github.com/LibreHardwareMonitor/LibreHardwareMonitor). If you encounter the problem that the hardware temperature cannot be displayed, or the displayed temperature is incorrect, then please download LibreHardwareMonitor first, and check whether LibreHardwareMonitor can display the corresponding temperature normally. If LibreHardwareMonitor cannot display the temperature of the corresponding hardware, then I cannot solve this problem. You can report your problem to the author of LibreHardwareMonitor. If LibreHardwareMonitor can display the temperature of the corresponding hardware normally, please report this problem to me, and provide a screenshot of LibreHardwareMonitor so that I can investigate your problem. **Note: The hardware monitoring function (including temperature monitoring and GPU usage monitoring) may have some problems, which may cause more CPU and memory usage. According to feedback from some users, turning on the temperature function will cause problems such as program crashes and system crashes. Please decide to turn on the hardware monitoring function after you are aware of the above risks. Otherwise, please do not use the hardware monitoring function.** ## 14. The program prompts that "MSVC\*.dll" or "mfc\*.dll" cannot be found when the program starts Click the link below to download and install the Microsoft Visual C++ runtime environment. [Latest supported Visual C++ Redistributable downloads | Microsoft Docs](https://docs.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170)

>If you have encountered any other problems, please click "Contact Author" in the "About" dialog box, or directly [click here](mailto:zhongyang219@hotmail.com) to send me an email.
Please describe the problems you have encountered in detail, the error prompts, what operations you have tried, it is better to attach the screenshots and configuration files ("Options"-"General Settings"-"Open configuration file path").
Note: Please confirm the email address that you used before sending the email. If your email address is form like "Outlook_\@outlook.com", then such email address is unable to reply. This may be due to the fact that you are using a third-party e-mail address as the Microsoft account to log on to Windows. If this is the case, be sure to enclose the correct email address in the message. ================================================ FILE: LICENSE ================================================ Copyright (c) <2019> "Anti 996" License Version 1.0 (Draft) Permission is hereby granted to any individual or legal entity obtaining a copy of this licensed work (including the source code, documentation and/or related items, hereinafter collectively referred to as the "licensed work"), free of charge, to deal with the licensed work for any purpose, including without limitation, the rights to use, reproduce, modify, prepare derivative works of, distribute, publish and sublicense the licensed work, subject to the following conditions: 1. The individual or the legal entity must conspicuously display, without modification, this License and the notice on each redistributed or derivative copy of the Licensed Work. 2. The individual or the legal entity must strictly comply with all applicable laws, regulations, rules and standards of the jurisdiction relating to labor and employment where the individual is physically located or where the individual was born or naturalized; or where the legal entity is registered or is operating (whichever is stricter). In case that the jurisdiction has no such laws, regulations, rules and standards or its laws, regulations, rules and standards are unenforceable, the individual or the legal entity are required to comply with Core International Labor Standards. 3. The individual or the legal entity shall not induce, suggest or force its employee(s), whether full-time or part-time, or its independent contractor(s), in any methods, to agree in oral or written form, to directly or indirectly restrict, weaken or relinquish his or her rights or remedies under such laws, regulations, rules and standards relating to labor and employment as mentioned above, no matter whether such written or oral agreements are enforceable under the laws of the said jurisdiction, nor shall such individual or the legal entity limit, in any methods, the rights of its employee(s) or independent contractor(s) from reporting or complaining to the copyright holder or relevant authorities monitoring the compliance of the license about its violation(s) of the said license. THE LICENSED WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ANY WAY CONNECTION WITH THE LICENSED WORK OR THE USE OR OTHER DEALINGS IN THE LICENSED WORK. ================================================ FILE: LICENSE_CN ================================================ 版权所有(c)<2019> 反996许可证版本1.0 在符合下列条件的情况下,特此免费向任何得到本授权作品的副本(包括源代码、文件和/或相关内容,以 下统称为“授权作品”)的个人和法人实体授权:被授权个人或法人实体有权以任何目的处置授权作品,包括 但不限于使用、复制,修改,衍生利用、散布,发布和再许可: 1. 个人或法人实体必须在许可作品的每个再散布或衍生副本上包含以上版权声明和本许可证,不得自行修 改。 2. 个人或法人实体必须严格遵守与个人实际所在地或个人出生地或归化地、或法人实体注册地或经营地( 以较严格者为准)的司法管辖区所有适用的与劳动和就业相关法律、法规、规则和标准。如果该司法管辖区 没有此类法律、法规、规章和标准或其法律、法规、规章和标准不可执行,则个人或法人实体必须遵守国际 劳工标准的核心公约。 3. 个人或法人不得以任何方式诱导、暗示或强迫其全职或兼职员工或其独立承包人以口头或书面形式同意 直接或间接限制、削弱或放弃其所拥有的,受相关与劳动和就业有关的法律、法规、规则和标准保护的权利 或补救措施,无论该等书面或口头协议是否被该司法管辖区的法律所承认,该等个人或法人实体也不得以任 何方法限制其雇员或独立承包人向版权持有人或监督许可证合规情况的有关当局报告或投诉上述违反许可证 的行为的权利。 该授权作品是"按原样"提供,不做任何明示或暗示的保证,包括但不限于对适销性、特定用途适用性和非侵 权性的保证。在任何情况下,无论是在合同诉讼、侵权诉讼或其他诉讼中,版权持有人均不承担因本软件或 本软件的使用或其他交易而产生、引起或与之相关的任何索赔、损害或其他责任。 ================================================ FILE: OpenHardwareMonitorApi/LibreHardwareMonitorLib.xml ================================================ LibreHardwareMonitorLib Stores all hardware groups and decides which devices should be enabled and updated. Creates a new instance with basic initial . Creates a new instance with additional . Computer settings that will be transferred to each . Contains computer information table read in accordance with System Management BIOS (SMBIOS) Reference Specification. Triggers the method for the given observer. Observer who call to devices. Triggers the method with the given visitor for each device in each group. Observer who call to devices. If hasn't been opened before, opens , , and triggers the private method depending on which categories are enabled. If opened before, removes all and triggers , and . If opened before, removes all and recreates it. specific additional settings passed to its . Support for the Kraken X3 devices from NZXT Initializes a new instance of the class. The group. The thread. The affinity. Gets the specified . The group. The thread. . Gets the CPUID. Gets the CPU index. Sets the default fan speed. Gets the OverdriveN temperature. The type. The sensor. The minimum temperature. The scale. If set to true, resets the sensor value to null. Gets a PMLog sensor value. The data. Type of the sensor. The sensor. The factor. Gets the Overdrive6 power. The type. The sensor. This structure describes a group-specific affinity. Initializes a new instance of the struct. The group. The mask. Gets a single group affinity. The group. The index. . Gets the group. Gets the mask. Determines whether the specified is equal to this instance. The to compare with this instance. true if the specified is equal to this instance; otherwise, false. Returns a hash code for this instance. A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. Implements the == operator. The a1. The a2. The result of the operator. Implements the != operator. The a1. The a2. The result of the operator. Object representing a component of the computer. Individual information can be read from the . Creates a new instance based on the data provided. Component name. Identifier that will be assigned to the device. Based on Additional settings passed by the . Event triggered when is closing. Collection of identifiers representing the purpose of the hardware. Handler that will trigger the actions assigned to it when the event occurs. Component returned to the assigned action(s). Basic abstract with methods for the class which can store all hardware and decides which devices are to be checked and updated. Gets or sets a value indicating whether collecting information about devices should be enabled and updated. if a given category of devices is already enabled. Gets or sets a value indicating whether collecting information about: devices should be enabled and updated. if a given category of devices is already enabled. Gets or sets a value indicating whether collecting information about or devices should be enabled and updated. if a given category of devices is already enabled. Gets or sets a value indicating whether collecting information about devices should be enabled and updated. if a given category of devices is already enabled. Gets or sets a value indicating whether collecting information about devices should be enabled and updated. if a given category of devices is already enabled. Gets or sets a value indicating whether collecting information about devices should be enabled and updated. if a given category of devices is already enabled. Gets or sets a value indicating whether collecting information about devices should be enabled and updated. if a given category of devices is already enabled. Gets or sets a value indicating whether collecting information about devices should be enabled and updated. if a given category of devices is already enabled. Gets a list of all known . Can be updated by . List of all enabled devices. Triggered when a new is registered. Triggered when a is removed. Generates full LibreHardwareMonitor report for devices that have been enabled. A formatted text string with library, OS and hardware information. Represents a unique / identifier in text format with a / separator. Creates a new identifier instance based on the base and additional elements. Base identifier being the beginning of the new one. Additional parts by which the base will be extended. Abstract parent with logic for the abstract class that stores data. Accepts the observer for this instance. Computer observer making the calls. Call the method for all child instances (called only from visitors). Computer observer making the calls. A group of devices from one category in one list. Gets a list that stores information about in a given group. Report containing most of the known information about all in this . A formatted text string with hardware information. Stop updating this group in the future. Handler that will trigger the actions assigned to it when the event occurs. Component returned to the assigned action(s). Abstract object that stores information about a device. All sensors are available as an array of . Can contain . Type specified in . Gets a unique hardware ID that represents its location. Gets or sets device name. Gets the device that is the parent of the current hardware. For example, the motherboard is the parent of SuperIO. Gets an array of all sensors such as , , etc. Gets child devices, e.g. of the . Report containing most of the known information about the current device. A formatted text string with hardware information. Refreshes the information stored in array. An that will be triggered when a new sensor appears. An that will be triggered when one of the sensors is removed. Gets rarely changed hardware properties that can't be represented as sensors. Abstract object that represents additional parameters included in . Gets a parameter default value defined by library. Gets a parameter description defined by library. Gets a unique parameter ID that represents its location. Gets or sets information whether the given is the default for . Gets a parameter name defined by library. Gets the sensor that is the data container for the given parameter. Gets or sets the current value. Category of what type the selected sensor is. Stores the readed value and the time in which it was recorded. of the sensor. The time code during which the was recorded. Gets the value of the sensor Gets the time code during which the was recorded. Stores information about the readed values and the time in which they were collected. Gets the unique identifier of this sensor for a given . Gets a maximum value recorded for the given sensor. Gets a minimum value recorded for the given sensor. Gets or sets a sensor name. By default determined by the library. Gets the last recorded value for the given sensor. Gets a list of recorded values for the given sensor. Resets a value stored in . Resets a value stored in . Abstract object that stores information about the limits of . Upper limit of value. Lower limit of value. Abstract object that stores information about the critical limits of . Critical upper limit of value. Critical lower limit of value. Abstract object that stores settings passed to , and . Returns information whether the given collection of settings contains a value assigned to the given key. Key to which the setting value is assigned. Assigns a setting option to a given key. Key to which the setting value is assigned. Text setting value. Gets a setting option assigned to the given key. Key to which the setting value is assigned. Default value. Removes a setting with the specified key from the settings collection. Key to which the setting value is assigned. Base interface for creating observers who call to devices. Refreshes the values of all in all on selected . Instance of the computer to be revisited. Refreshes the values of all on selected . Instance of the hardware to be revisited. Refreshes the values on selected . Instance of the sensor to be revisited. Refreshes the values on selected . Instance of the parameter to be revisited. An unsafe but universal implementation for the ACPI Embedded Controller IO interface for Windows It is unsafe because of possible race condition between this application and the PC firmware when writing to the EC registers. For a safe approach ACPI/WMI methods have to be used, but those are different for each motherboard model. Represents the motherboard of a computer with its and as . Creates motherboard instance by retrieving information from and creates a new based on data from and . table containing motherboard data. Additional settings passed by . Gets the name obtained from . Always Gets the information. Motherboard itself cannot be updated. Update instead. Closes using . Composite class containing information about the selected . Creates a new instance and assigns values. Name of the selected component. Description of the selected component. Default value of the selected component. Gets a name of the parent . Gets a description of the parent . Gets a default value of the parent . Observer making calls to selected component 's. Creates a new observer instance. Instance of the that triggers events during visiting the . Goes through all the components of the specified with its . Computer class instance that is derived from the interface. Goes through all the components of the specified with its . Hardware class instance that is derived from the interface. Goes through all the components of the specified using . Sensor class instance that is derived from the interface. Goes through all the components of the specified . Parameter class instance that is derived from the interface. Chassis security status based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.4.3. Chassis state based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.4.2. Chassis type based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.4.1. Processor family based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.5.2. Processor type based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.5.1. Processor socket based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.5.5. System wake-up type based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.2.2. Cache associativity based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.8.5. Processor cache level. Initializes a new instance of the class. The data. The strings. Gets the byte. The offset. . Gets the word. The offset. . Gets the string. The offset. . Motherboard BIOS information obtained from the SMBIOS table. Gets the BIOS release date. Gets the size of the physical device containing the BIOS. Gets the string number of the BIOS Vendor’s Name. Gets the string number of the BIOS Version. This value is a free-form string that may contain Core and OEM version information. Gets the size. . Gets the date. The bios date. . System information obtained from the SMBIOS table. Gets the family associated with system. This text string identifies the family to which a particular computer belongs. A family refers to a set of computers that are similar but not identical from a hardware or software point of view. Typically, a family is composed of different computer models, which have different configurations and pricing points. Computers in the same family often have similar branding and cosmetic features. Gets the manufacturer name associated with system. Gets the product name associated with system. Gets the serial number string associated with system. Gets the version string associated with system. Gets Chassis information obtained from the SMBIOS table. Gets the asset tag associated with the enclosure or chassis. Gets Gets Gets or sets the chassis lock. Chassis lock is present if . Otherwise, either a lock is not present or it is unknown if the enclosure has a lock. Gets the string describing the chassis or enclosure manufacturer name. Gets the number of power cords associated with the enclosure or chassis. Gets the state of the enclosure’s power supply (or supplies) when last booted. Gets the height of the enclosure, in 'U's. A U is a standard unit of measure for the height of a rack or rack-mountable component and is equal to 1.75 inches or 4.445 cm. A value of 0 indicates that the enclosure height is unspecified. Gets the physical security status of the enclosure when last booted. Gets the string describing the chassis or enclosure serial number. Gets the string describing the chassis or enclosure SKU number. Gets the thermal state of the enclosure when last booted. Gets the number of null-terminated string representing the chassis or enclosure version. Motherboard information obtained from the SMBIOS table. Gets the value that represents the manufacturer's name. Gets the value that represents the motherboard's name. Gets the value that represents the motherboard's serial number. Gets the value that represents the motherboard's revision number. Processor information obtained from the SMBIOS table. Gets the value that represents the number of cores per processor socket. Gets the value that represents the number of enabled cores per processor socket. Gets the value that represents the current processor speed (in MHz). Gets the external Clock Frequency, in MHz. If the value is unknown, the field is set to 0. Gets Gets the string number of Processor Manufacturer. Gets the value that represents the maximum processor speed (in MHz) supported by the system for this processor socket. Gets Gets the value that represents the string number for the serial number of this processor. This value is set by the manufacturer and normally not changeable. Gets Gets the string number for Reference Designation. Gets the value that represents the number of threads per processor socket. Gets the value that represents the string number describing the Processor. Processor cache information obtained from the SMBIOS table. Gets Gets Gets the value that represents the installed cache size. Gets the cache designation. . Memory information obtained from the SMBIOS table. Gets the string number of the string that identifies the physically labeled bank where the memory device is located. Gets the string number of the string that identifies the physically-labeled socket or board position where the memory device is located. Gets the string number for the manufacturer of this memory device. Gets the string number for the part number of this memory device. Gets the string number for the serial number of this memory device. Gets the size of the memory device. If the value is 0, no memory device is installed in the socket. Gets the the value that identifies the maximum capable speed of the device, in mega transfers per second (MT/s). Reads and processes information encoded in an SMBIOS table. Gets Gets Gets Gets Gets Gets Gets Report containing most of the information that could be read from the SMBIOS table. A formatted text string with computer information and the entire SMBIOS table. Helper to calculate the disk performance with base timestamps https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-perfrawdata Gets the SMART data. Gets the SMART attributes. Gets the SMART data. Initializes a new instance of the class. The SMART id of the attribute. The name of the attribute. Initializes a new instance of the class. The SMART id of the attribute. The name of the attribute. A delegate for converting the raw byte array into a value (or null to use the attribute value). Initializes a new instance of the class. The SMART id of the attribute. The name of the attribute. A delegate for converting the raw byte array into a value (or null to use the attribute value). Type of the sensor or null if no sensor is to be created. If there exists more than one attribute with the same sensor channel and type, then a sensor is created only for the first attribute. The name to be used for the sensor, or null if no sensor is created. True to hide the sensor initially. Description for the parameters of the sensor (or null). Gets the SMART identifier. Localization class for SMART attribute names. Reads Smart health status of the drive True, if drive is healthy; False, if unhealthy; Null, if it cannot be read Initializes static members of the class. Gets the processor group count. Returns true if the is valid. The affinity. true if the specified affinity is valid; otherwise, false. Sets the processor group affinity for the current thread. The processor group affinity. The previous processor group affinity. All OK, but need to wait. All OK, but need restart. All OK but need mode change. All OK, but with warning. ADL function completed successfully. Generic Error. Most likely one or more of the Escape calls to the driver failed! ADL not initialized. One of the parameter passed is invalid. One of the parameter size is invalid. Invalid ADL index passed. Invalid controller index passed. Invalid display index passed. Function not supported by the driver. Null Pointer error. Call can't be made due to disabled adapter. Invalid Callback. Display Resource conflict. Failed to update some of the values. Can be returned by set request that include multiple values if not all values were successfully committed. There's no Linux XDisplay in Linux Console environment. If set to 1, then the available spare space has fallen below the threshold. If set to 1, then a temperature is above an over temperature threshold or below an under temperature threshold. If set to 1, then the device reliability has been degraded due to significant media related errors or any internal error that degrades device reliability. If set to 1, then the media has been placed in read only mode If set to 1, then the volatile memory backup device has failed. This field is only valid if the controller has a volatile memory backup solution. Create a instance from a struct with zero initialized memory arrays no need to init every inner array with the correct sizes type of struct that is needed SMART data requested. Identify data is requested. Read SMART data. Read SMART thresholds. obsolete Autosave SMART data. Save SMART attributes. Set SMART to offline immediately. Read SMART log. Write SMART log. Write SMART thresholds. obsolete Enable SMART. Disable SMART. Get SMART status. Set SMART to offline automatically. bit 0:15 Maximum Power (MP) in centiwatts bit 16:23 bit 24 Max Power Scale (MPS), bit 25 Non-Operational State (NOPS) bit 32:63 Entry Latency (ENLAT) in microseconds bit 64:95 Exit Latency (EXLAT) in microseconds bit 96:100 Relative Read Throughput (RRT) bit 104:108 Relative Read Latency (RRL) bit 112:116 Relative Write Throughput (RWT) bit 120:124 Relative Write Latency (RWL) bit 128:143 Idle Power (IDLP) bit 150:151 Idle Power Scale (IPS) bit 152:159 bit 160:175 Active Power (ACTP) bit 176:178 Active Power Workload (APW), bit 182:183 Active Power Scale (APS) bit 184:255. byte 0:1 M - PCI Vendor ID (VID) byte 2:3 M - PCI Subsystem Vendor ID (SSVID) byte 4: 23 M - Serial Number (SN) byte 24:63 M - Model Number (MN) byte 64:71 M - Firmware Revision (FR) byte 72 M - Recommended Arbitration Burst (RAB) byte 73:75 M - IEEE OUI Identifier (IEEE). Controller Vendor code. byte 76 O - Controller Multi-Path I/O and Namespace Sharing Capabilities (CMIC) byte 77 M - Maximum Data Transfer Size (MDTS) byte 78:79 M - Controller ID (CNTLID) byte 80:83 M - Version (VER) byte 84:87 M - RTD3 Resume Latency (RTD3R) byte 88:91 M - RTD3 Entry Latency (RTD3E) byte 92:95 M - Optional Asynchronous Events Supported (OAES) byte 96:239. byte 240:255. Refer to the NVMe Management Interface Specification for definition. byte 256:257 M - Optional Admin Command Support (OACS) byte 258 M - Abort Command Limit (ACL) byte 259 M - Asynchronous Event Request Limit (AERL) byte 260 M - Firmware Updates (FRMW) byte 261 M - Log Page Attributes (LPA) byte 262 M - Error Log Page Entries (ELPE) byte 263 M - Number of Power States Support (NPSS) byte 264 M - Admin Vendor Specific Command Configuration (AVSCC) byte 265 O - Autonomous Power State Transition Attributes (APSTA) byte 266:267 M - Warning Composite Temperature Threshold (WCTEMP) byte 268:269 M - Critical Composite Temperature Threshold (CCTEMP) byte 270:271 O - Maximum Time for Firmware Activation (MTFA) byte 272:275 O - Host Memory Buffer Preferred Size (HMPRE) byte 276:279 O - Host Memory Buffer Minimum Size (HMMIN) byte 280:295 O - Total NVM Capacity (TNVMCAP) byte 296:311 O - Unallocated NVM Capacity (UNVMCAP) byte 312:315 O - Replay Protected Memory Block Support (RPMBS) byte 316:511 byte 512 M - Submission Queue Entry Size (SQES) byte 513 M - Completion Queue Entry Size (CQES) byte 514:515 byte 516:519 M - Number of Namespaces (NN) byte 520:521 M - Optional NVM Command Support (ONCS) byte 522:523 M - Fused Operation Support (FUSES) byte 524 M - Format NVM Attributes (FNA) byte 525 M - Volatile Write Cache (VWC) byte 526:527 M - Atomic Write Unit Normal (AWUN) byte 528:529 M - Atomic Write Unit Power Fail (AWUPF) byte 530 M - NVM Vendor Specific Command Configuration (NVSCC) byte 531 byte 534:535 byte 536:539 O - SGL Support (SGLS) byte 540:703 byte 704:2047 byte 2048:3071 Power State Descriptors byte 3072:4095 Vendor Specific This field indicates critical warnings for the state of the controller. Each bit corresponds to a critical warning type; multiple bits may be set. Composite Temperature: Contains the temperature of the overall device (controller and NVM included) in units of Kelvin. Available Spare: Contains a normalized percentage (0 to 100%) of the remaining spare capacity available Available Spare Threshold: When the Available Spare falls below the threshold indicated in this field, an asynchronous event completion may occur. The value is indicated as a normalized percentage (0 to 100%). Percentage Used: Contains a vendor specific estimate of the percentage of NVM subsystem life used based on the actual usage and the manufacturer’s prediction of NVM life. A value of 100 indicates that the estimated endurance of the NVM in the NVM subsystem has been consumed, but may not indicate an NVM subsystem failure. The value is allowed to exceed 100. Data Units Read: Contains the number of 512 byte data units the host has read from the controller; this value does not include metadata. This value is reported in thousands (i.e., a value of 1 corresponds to 1000 units of 512 bytes read) and is rounded up. Data Units Written: Contains the number of 512 byte data units the host has written to the controller; this value does not include metadata. This value is reported in thousands (i.e., a value of 1 corresponds to 1000 units of 512 bytes written) and is rounded up. Host Read Commands: Contains the number of read commands completed by the controller. For the NVM command set, this is the number of Compare and Read commands. Host Write Commands: Contains the number of write commands completed by the controller. For the NVM command set, this is the number of Write commands. Controller Busy Time: Contains the amount of time the controller is busy with I/O commands. Power Cycles: Contains the number of power cycles. Power On Hours: Contains the number of power-on hours. This does not include time that the controller was powered and in a low power state condition. Unsafe Shutdowns: Contains the number of unsafe shutdowns. This count is incremented when a shutdown notification is not received prior to loss of power. Media Errors: Contains the number of occurrences where the controller detected an unrecoverable data integrity error. Errors such as uncorrectable ECC, CRC checksum failure, or LBA tag mismatch are included in this field. Number of Error Information Log Entries: Contains the number of Error Information log entries over the life of the controller Warning Composite Temperature Time: Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater than or equal to the Warning Composite Temperature Threshold. Critical Composite Temperature Time: Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater than the Critical Composite Temperature Threshold. Contains the current temperature reported by temperature sensor 1-8. Gets the resulting IO control code. Initializes a new instance of the struct. Type of the device. The function. The access. Initializes a new instance of the struct. Type of the device. The function. The method. The access. The operation was successful NvidiaML was not first initialized with nvmlInit() A supplied argument is invalid The requested operation is not available on target device The current user does not have permission for operation A query to find an object was unsuccessful An input argument is not large enough A device's external power cables are not properly attached NVIDIA driver is not loaded User provided timeout passed NVIDIA Kernel detected an interrupt issue with a GPU NvidiaML Shared Library couldn't be found or loaded Local version of NvidiaML doesn't implement this function infoROM is corrupted The GPU has fallen off the bus or has otherwise become inaccessible The GPU requires a reset before it can be used again The GPU control device has been blocked by the operating system/cgroups RM detects a driver/library version mismatch An operation cannot be performed because the GPU is currently in use An public driver error occurred Driver with access at kernel level. Contains Win32 definitions for Windows NT. Describes a local identifier for an adapter. Represents a 64-bit signed integer value. Contains basic information about the operating system. Statically checks if the current system and . Gets information about whether the current system is 64 bit. Gets information about whether the current system is Unix based. ================================================ FILE: OpenHardwareMonitorApi/OpenHardwareMonitorApi.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26} v4.5.2 ManagedCProj OpenHardwareMonitorApi 10.0 DynamicLibrary true v142 true Unicode DynamicLibrary false v142 true Unicode DynamicLibrary true v142 true Unicode DynamicLibrary false v142 true Unicode true $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)Bin\$(Configuration)\ true $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)Bin\$(Platform)\$(Configuration)\ false $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)Bin\$(Configuration)\ false $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)Bin\$(Platform)\$(Configuration)\ Level3 Disabled WIN32;_DEBUG;%(PreprocessorDefinitions);OPENHARDWAREMONITOR_EXPORTS Use Level3 Disabled _DEBUG;%(PreprocessorDefinitions);OPENHARDWAREMONITOR_EXPORTS Use Level3 WIN32;NDEBUG;%(PreprocessorDefinitions);OPENHARDWAREMONITOR_EXPORTS Use Level3 NDEBUG;%(PreprocessorDefinitions);OPENHARDWAREMONITOR_EXPORTS Use LibreHardwareMonitorLib.dll Create Create Create Create ================================================ FILE: OpenHardwareMonitorApi/OpenHardwareMonitorApi.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 头文件 头文件 头文件 头文件 头文件 头文件 源文件 源文件 源文件 资源文件 ================================================ FILE: OpenHardwareMonitorApi/OpenHardwareMonitorImp.cpp ================================================ // 这是主 DLL 文件。 #include "stdafx.h" #include "OpenHardwareMonitorImp.h" #include namespace OpenHardwareMonitorApi { static std::wstring error_message; //将CRL的String类型转换成C++的std::wstring类型 static std::wstring ClrStringToStdWstring(System::String^ str) { if (str == nullptr) { return std::wstring(); } else { const wchar_t* chars = (const wchar_t*)(Runtime::InteropServices::Marshal::StringToHGlobalUni(str)).ToPointer(); std::wstring os = chars; Runtime::InteropServices::Marshal::FreeHGlobal(IntPtr((void*)chars)); return os; } } std::shared_ptr CreateInstance() { std::shared_ptr pMonitor; try { MonitorGlobal::Instance()->Init(); pMonitor = std::make_shared(); } catch (System::Exception^ e) { error_message = ClrStringToStdWstring(e->Message); } return pMonitor; } std::wstring GetErrorMessage() { return error_message; } float COpenHardwareMonitor::CpuTemperature() { return m_cpu_temperature; } float COpenHardwareMonitor::GpuTemperature() { if (m_gpu_nvidia_temperature >= 0) return m_gpu_nvidia_temperature; else return m_gpu_ati_temperature; } float COpenHardwareMonitor::HDDTemperature() { return m_hdd_temperature; } float COpenHardwareMonitor::MainboardTemperature() { return m_main_board_temperature; } float COpenHardwareMonitor::GpuUsage() { if (m_gpu_nvidia_usage >= 0) return m_gpu_nvidia_usage; else return m_gpu_ati_usage; } float COpenHardwareMonitor::CpuFreq() { return m_cpu_freq; } const std::map& COpenHardwareMonitor::AllHDDTemperature() { return m_all_hdd_temperature; } const std::map& COpenHardwareMonitor::AllCpuTemperature() { return m_all_cpu_temperature; } const std::map& COpenHardwareMonitor::AllHDDUsage() { return m_all_hdd_usage; } void COpenHardwareMonitor::SetCpuEnable(bool enable) { MonitorGlobal::Instance()->computer->IsCpuEnabled = enable; } void COpenHardwareMonitor::SetGpuEnable(bool enable) { MonitorGlobal::Instance()->computer->IsGpuEnabled = enable; } void COpenHardwareMonitor::SetHddEnable(bool enable) { MonitorGlobal::Instance()->computer->IsStorageEnabled = enable; } void COpenHardwareMonitor::SetMainboardEnable(bool enable) { MonitorGlobal::Instance()->computer->IsMotherboardEnabled = enable; } bool COpenHardwareMonitor::GetCPUFreq(IHardware^ hardware, float& freq) { for (int i = 0; i < hardware->Sensors->Length; i++) { if (hardware->Sensors[i]->SensorType == SensorType::Clock) { String^ name = hardware->Sensors[i]->Name; if (name != L"Bus Speed") m_all_cpu_clock[ClrStringToStdWstring(name)] = Convert::ToDouble(hardware->Sensors[i]->Value); } } float sum{}; for (auto i : m_all_cpu_clock) sum += i.second; freq = sum / m_all_cpu_clock.size() / 1000.0; return true; } bool COpenHardwareMonitor::GetHardwareTemperature(IHardware^ hardware, float& temperature) { temperature = -1; std::vector all_temperature; float core_temperature{ -1 }; System::String^ temperature_name; switch (hardware->HardwareType) { case HardwareType::Cpu: temperature_name = L"Core Average"; break; case HardwareType::GpuNvidia: case HardwareType::GpuAmd: temperature_name = L"GPU Core"; break; default: break; } for (int i = 0; i < hardware->Sensors->Length; i++) { //找到温度传感器 if (hardware->Sensors[i]->SensorType == SensorType::Temperature) { float cur_temperture = Convert::ToDouble(hardware->Sensors[i]->Value); all_temperature.push_back(cur_temperture); if (hardware->Sensors[i]->Name == temperature_name) //如果找到了名称为temperature_name的温度传感器,则将温度保存到core_temperature里 core_temperature = cur_temperture; } } if (core_temperature >= 0) { temperature = core_temperature; return true; } if (!all_temperature.empty()) { //如果有多个温度传感器,则取平均值 float sum{}; for (auto i : all_temperature) sum += i; temperature = sum / all_temperature.size(); return true; } //如果没有找到温度传感器,则在SubHardware中寻找 for (int i = 0; i < hardware->SubHardware->Length; i++) { if (GetHardwareTemperature(hardware->SubHardware[i], temperature)) return true; } return false; } bool COpenHardwareMonitor::GetCpuTemperature(IHardware^ hardware, float& temperature) { temperature = -1; m_all_cpu_temperature.clear(); for (int i = 0; i < hardware->Sensors->Length; i++) { //找到温度传感器 if (hardware->Sensors[i]->SensorType == SensorType::Temperature) { String^ name = hardware->Sensors[i]->Name; //保存每个CPU传感器的温度 m_all_cpu_temperature[ClrStringToStdWstring(name)] = Convert::ToDouble(hardware->Sensors[i]->Value); } } //计算平均温度 if (!m_all_cpu_temperature.empty()) { float sum{}; for (const auto& item : m_all_cpu_temperature) sum += item.second; temperature = sum / m_all_cpu_temperature.size(); } return temperature > 0; } bool COpenHardwareMonitor::GetGpuUsage(IHardware^ hardware, float& gpu_usage) { for (int i = 0; i < hardware->Sensors->Length; i++) { //找到负载 if (hardware->Sensors[i]->SensorType == SensorType::Load) { if (hardware->Sensors[i]->Name == L"GPU Core") { gpu_usage = Convert::ToDouble(hardware->Sensors[i]->Value); return true; } } } return false; } bool COpenHardwareMonitor::GetHddUsage(IHardware^ hardware, float& hdd_usage) { for (int i = 0; i < hardware->Sensors->Length; i++) { //找到负载 if (hardware->Sensors[i]->SensorType == SensorType::Load) { if (hardware->Sensors[i]->Name == L"Total Activity") { hdd_usage = Convert::ToDouble(hardware->Sensors[i]->Value); return true; } } } return false; } COpenHardwareMonitor::COpenHardwareMonitor() { ResetAllValues(); } COpenHardwareMonitor::~COpenHardwareMonitor() { MonitorGlobal::Instance()->UnInit(); } void COpenHardwareMonitor::ResetAllValues() { m_cpu_temperature = -1; m_gpu_nvidia_temperature = -1; m_gpu_ati_temperature = -1; m_hdd_temperature = -1; m_main_board_temperature = -1; m_gpu_nvidia_usage = -1; m_gpu_ati_usage = -1; m_all_hdd_temperature.clear(); m_all_hdd_usage.clear(); } void COpenHardwareMonitor::InsertValueToMap(std::map& value_map, const std::wstring& key, float value) { auto iter = value_map.find(key); if (iter == value_map.end()) { value_map[key] = value; } else { std::wstring key_exist = iter->first; size_t index = key_exist.rfind(L'#'); //查找字符串是否含有#号 if (index != std::wstring::npos) { //取到#号后面的数字,将其加1 int num = _wtoi(key_exist.substr(index + 1).c_str()); num++; key_exist = key_exist.substr(0, index + 1); key_exist += std::to_wstring(num); } else //没有#号则在末尾添加" #1" { key_exist += L" #1"; } value_map[key_exist] = value; } } void COpenHardwareMonitor::GetHardwareInfo() { ResetAllValues(); error_message.clear(); try { auto computer = MonitorGlobal::Instance()->computer; computer->Accept(MonitorGlobal::Instance()->updateVisitor); for (int i = 0; i < computer->Hardware->Count; i++) { //查找硬件类型 switch (computer->Hardware[i]->HardwareType) { case HardwareType::Cpu: if (m_cpu_temperature < 0) GetCpuTemperature(computer->Hardware[i], m_cpu_temperature); GetCPUFreq(computer->Hardware[i], m_cpu_freq); break; case HardwareType::GpuNvidia: if (m_gpu_nvidia_temperature < 0) GetHardwareTemperature(computer->Hardware[i], m_gpu_nvidia_temperature); if (m_gpu_nvidia_usage < 0) GetGpuUsage(computer->Hardware[i], m_gpu_nvidia_usage); break; case HardwareType::GpuAmd: if (m_gpu_ati_temperature < 0) GetHardwareTemperature(computer->Hardware[i], m_gpu_ati_temperature); if (m_gpu_ati_usage < 0) GetGpuUsage(computer->Hardware[i], m_gpu_ati_usage); break; case HardwareType::Storage: { float cur_hdd_temperature = -1; GetHardwareTemperature(computer->Hardware[i], cur_hdd_temperature); //m_all_hdd_temperature[ClrStringToStdWstring(computer->Hardware[i]->Name)] = cur_hdd_temperature; InsertValueToMap(m_all_hdd_temperature, ClrStringToStdWstring(computer->Hardware[i]->Name), cur_hdd_temperature); float cur_hdd_usage = -1; GetHddUsage(computer->Hardware[i], cur_hdd_usage); //m_all_hdd_usage[ClrStringToStdWstring(computer->Hardware[i]->Name)] = cur_hdd_usage; InsertValueToMap(m_all_hdd_usage, ClrStringToStdWstring(computer->Hardware[i]->Name), cur_hdd_usage); if (m_hdd_temperature < 0) m_hdd_temperature = cur_hdd_temperature; } break; case HardwareType::Motherboard: if (m_main_board_temperature < 0) GetHardwareTemperature(computer->Hardware[i], m_main_board_temperature); break; default: break; } } } catch (System::Exception^ e) { error_message = ClrStringToStdWstring(e->Message); } } //////////////////////////////////////////////////////////////////////////////////// MonitorGlobal::MonitorGlobal() { } MonitorGlobal::~MonitorGlobal() { } void MonitorGlobal::Init() { updateVisitor = gcnew UpdateVisitor(); computer = gcnew Computer(); computer->Open(); } void MonitorGlobal::UnInit() { computer->Close(); } } ================================================ FILE: OpenHardwareMonitorApi/OpenHardwareMonitorImp.h ================================================ // OpenHardwareMonitorApi.h #pragma once #include #include "OpenHardwareMonitor/OpenHardwareMonitorApi.h" #include "UpdateVisitor.h" #include using namespace System; using namespace LibreHardwareMonitor::Hardware; namespace OpenHardwareMonitorApi { public class COpenHardwareMonitor : public IOpenHardwareMonitor { public: COpenHardwareMonitor(); virtual ~COpenHardwareMonitor(); virtual void GetHardwareInfo() override; virtual float CpuTemperature() override; virtual float GpuTemperature() override; virtual float HDDTemperature() override; virtual float MainboardTemperature() override; virtual float GpuUsage() override; virtual float CpuFreq() override; virtual const std::map& AllHDDTemperature() override; virtual const std::map& AllCpuTemperature() override; virtual const std::map& AllHDDUsage() override; virtual void SetCpuEnable(bool enable) override; virtual void SetGpuEnable(bool enable) override; virtual void SetHddEnable(bool enable) override; virtual void SetMainboardEnable(bool enable) override; private: bool GetHardwareTemperature(IHardware^ hardware, float& temperature); bool GetCpuTemperature(IHardware^ hardware, float& temperature); bool GetGpuUsage(IHardware^ hardware, float& gpu_usage); bool GetHddUsage(IHardware^ hardware, float& hdd_usage); bool GetCPUFreq(IHardware^ hardware, float& freq); void ResetAllValues(); //向map中插入一个数值,如果key已经存在,则自动对新插入的key重命名 static void InsertValueToMap(std::map& value_map, const std::wstring& key, float value); private: float m_cpu_temperature{}; float m_gpu_nvidia_temperature{}; float m_gpu_ati_temperature{}; float m_hdd_temperature{}; float m_main_board_temperature{}; float m_gpu_nvidia_usage{}; float m_gpu_ati_usage{}; float m_cpu_freq{}; std::map m_all_hdd_temperature; std::map m_all_cpu_temperature; std::map m_all_cpu_clock; std::map m_all_hdd_usage; }; //一个单实例类 //由于COpenHardwareMonitor是非托管类,不能将托管类的对象作为成员变量,此类用于保存托管类的对象 public ref class MonitorGlobal { public: MonitorGlobal(); ~MonitorGlobal(); static MonitorGlobal^ Instance() { if (m_instance == nullptr) { m_instance = gcnew MonitorGlobal(); } return m_instance; } void Init(); void UnInit(); Computer^ computer; UpdateVisitor^ updateVisitor{}; private: static MonitorGlobal^ m_instance{}; }; } ================================================ FILE: OpenHardwareMonitorApi/ReadMe.txt ================================================ ======================================================================== DYNAMIC LINK LIBRARY : OpenHardwareMonitorApi Project Overview ======================================================================== AppWizard has created this OpenHardwareMonitorApi DLL for you. This file contains a summary of what you will find in each of the files that make up your OpenHardwareMonitorApi application. OpenHardwareMonitorApi.vcxproj This is the main project file for VC++ projects generated using an Application Wizard. It contains information about the version of Visual C++ that generated the file, and information about the platforms, configurations, and project features selected with the Application Wizard. OpenHardwareMonitorApi.vcxproj.filters This is the filters file for VC++ projects generated using an Application Wizard. It contains information about the association between the files in your project and the filters. This association is used in the IDE to show grouping of files with similar extensions under a specific node (for e.g. ".cpp" files are associated with the "Source Files" filter). OpenHardwareMonitorApi.cpp This is the main DLL source file. OpenHardwareMonitorApi.h This file contains a class declaration. AssemblyInfo.cpp Contains custom attributes for modifying assembly metadata. ///////////////////////////////////////////////////////////////////////////// Other notes: AppWizard uses "TODO:" to indicate parts of the source code you should add to or customize. ///////////////////////////////////////////////////////////////////////////// ================================================ FILE: OpenHardwareMonitorApi/Stdafx.cpp ================================================ // stdafx.cpp : ֻ׼ļԴļ // OpenHardwareMonitorApi.pch ΪԤͷ // stdafx.obj ԤϢ #include "stdafx.h" ================================================ FILE: OpenHardwareMonitorApi/Stdafx.h ================================================ // stdafx.h : ׼ϵͳļİļ // Ǿʹõĵ // ضĿİļ #pragma once ================================================ FILE: OpenHardwareMonitorApi/UpdateVisitor.cpp ================================================ #include "stdafx.h" #include "UpdateVisitor.h" namespace OpenHardwareMonitorApi { void UpdateVisitor::VisitComputer(IComputer ^ computer) { computer->Traverse(this); } void UpdateVisitor::VisitHardware(IHardware ^ hardware) { hardware->Update(); for each (IHardware^ subHardware in hardware->SubHardware) { subHardware->Accept(this); } } void UpdateVisitor::VisitSensor(ISensor ^ sensor) { } void UpdateVisitor::VisitParameter(IParameter ^ parameter) { } } ================================================ FILE: OpenHardwareMonitorApi/UpdateVisitor.h ================================================ #pragma once using namespace LibreHardwareMonitor::Hardware; namespace OpenHardwareMonitorApi { public ref class UpdateVisitor : IVisitor { public: virtual void VisitComputer(IComputer^ computer); virtual void VisitHardware(IHardware^ hardware); virtual void VisitSensor(ISensor^ sensor); virtual void VisitParameter(IParameter^ parameter); }; } ================================================ FILE: OpenHardwareMonitorApi/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by app.rc ================================================ FILE: PluginDemo/CustomDrawItem.cpp ================================================ #include "pch.h" #include "CustomDrawItem.h" #include "DataManager.h" const wchar_t* CCustomDrawItem::GetItemName() const { return CDataManager::Instance().StringRes(IDS_CUSTOM_DRAW_ITEM); } const wchar_t* CCustomDrawItem::GetItemId() const { return L"b4zc373y"; } const wchar_t* CCustomDrawItem::GetItemLableText() const { return L""; } const wchar_t* CCustomDrawItem::GetItemValueText() const { return L""; } const wchar_t* CCustomDrawItem::GetItemValueSampleText() const { return L""; } bool CCustomDrawItem::IsCustomDraw() const { return true; } int CCustomDrawItem::GetItemWidth() const { return 50; } static void DrawLine(CDC* pDC, CPoint point1, CPoint point2, COLORREF color) { CPen aPen, * pOldPen; aPen.CreatePen(PS_SOLID, 1, color); pOldPen = pDC->SelectObject(&aPen); pDC->MoveTo(point1); pDC->LineTo(point2); pDC->SelectObject(pOldPen); } void CCustomDrawItem::DrawItem(void* hDC, int x, int y, int w, int h, bool dark_mode) { //绘图句柄 CDC* pDC = CDC::FromHandle((HDC)hDC); //矩形区域 CRect rect(CPoint(x, y), CSize(w, h)); //设置颜色 COLORREF color1{ dark_mode ? RGB(255, 143, 107) : RGB(227, 81, 16) }; COLORREF color2{ dark_mode ? RGB(183, 241, 96) : RGB(83, 131, 11) }; COLORREF color3{ dark_mode ? RGB(158, 218, 251) : RGB(6, 111, 168) }; //显示时、分、秒的矩形区域 CRect rect1{ rect }, rect2{ rect }, rect3{ rect }; rect1.bottom = rect.top + rect.Height() / 3; rect2 = rect1; rect2.MoveToY(rect1.bottom); rect3.top = rect2.bottom; rect1.DeflateRect(1, 1); rect2.DeflateRect(1, 1); rect3.DeflateRect(1, 1); //根据当前时间计算矩形的宽度 SYSTEMTIME& time{ CDataManager::Instance().m_system_time }; int hour_width{ static_cast((time.wHour + time.wMinute / 60.0) * w / 24) }; int min_width{ static_cast((time.wMinute + time.wSecond / 60.0) * w / 60) }; int sec_width{ time.wSecond * w / 60 }; rect1.right = rect1.left + hour_width; rect2.right = rect2.left + min_width; rect3.right = rect3.left + sec_width; //填充矩形 pDC->FillSolidRect(rect1, color1); pDC->FillSolidRect(rect2, color2); pDC->FillSolidRect(rect3, color3); //绘制刻度 COLORREF color_scale{ dark_mode ? RGB(225, 225, 225) : RGB(45, 45, 45) }; for (int i{}; i < 24; i++) { int x_pos{ i * w / 24 + rect1.left }; DrawLine(pDC, CPoint(x_pos, rect1.top), CPoint(x_pos, i % 6 == 0 ? rect1.bottom : rect1.top + rect1.Height() / 2), color_scale); } } ================================================ FILE: PluginDemo/CustomDrawItem.h ================================================ #pragma once #include "PluginInterface.h" class CCustomDrawItem : public IPluginItem { // 通过 IPluginItem 继承 virtual const wchar_t* GetItemName() const override; virtual const wchar_t* GetItemId() const override; virtual const wchar_t* GetItemLableText() const override; virtual const wchar_t* GetItemValueText() const override; virtual const wchar_t* GetItemValueSampleText() const override; virtual bool IsCustomDraw() const override; virtual int GetItemWidth() const override; virtual void DrawItem(void* hDC, int x, int y, int w, int h, bool dark_mode) override; }; ================================================ FILE: PluginDemo/DataManager.cpp ================================================ #include "pch.h" #include "DataManager.h" CDataManager CDataManager::m_instance; CDataManager::CDataManager() { } CDataManager::~CDataManager() { SaveConfig(); } CDataManager& CDataManager::Instance() { return m_instance; } void CDataManager::LoadConfig(const std::wstring& config_dir) { //获取模块的路径 HMODULE hModule = reinterpret_cast(&__ImageBase); wchar_t path[MAX_PATH]; GetModuleFileNameW(hModule, path, MAX_PATH); std::wstring module_path = path; m_config_path = module_path; if (!config_dir.empty()) { size_t index = module_path.find_last_of(L"\\/"); //模块的文件名 std::wstring module_file_name = module_path.substr(index + 1); m_config_path = config_dir + module_file_name; } m_config_path += L".ini"; m_setting_data.show_second = GetPrivateProfileInt(_T("config"), _T("show_second"), 0, m_config_path.c_str()); //m_setting_data.show_label_text = GetPrivateProfileInt(_T("config"), _T("show_label_text"), 1, config_path.c_str()); } static void WritePrivateProfileInt(const wchar_t* app_name, const wchar_t* key_name, int value, const wchar_t* file_path) { wchar_t buff[16]; swprintf_s(buff, L"%d", value); WritePrivateProfileString(app_name, key_name, buff, file_path); } void CDataManager::SaveConfig() const { WritePrivateProfileInt(_T("config"), _T("show_second"), m_setting_data.show_second, m_config_path.c_str()); //WritePrivateProfileInt(_T("config"), _T("show_label_text"), m_setting_data.show_label_text, config_path.c_str()); } const CString& CDataManager::StringRes(UINT id) { auto iter = m_string_table.find(id); if (iter != m_string_table.end()) { return iter->second; } else { AFX_MANAGE_STATE(AfxGetStaticModuleState()); m_string_table[id].LoadString(id); return m_string_table[id]; } } ================================================ FILE: PluginDemo/DataManager.h ================================================ #pragma once #include #include #define g_data CDataManager::Instance() struct SettingData { bool show_second{}; //bool show_label_text{}; }; class CDataManager { private: CDataManager(); ~CDataManager(); public: static CDataManager& Instance(); void LoadConfig(const std::wstring& config_dir); void SaveConfig() const; const CString& StringRes(UINT id); //根据资源id获取一个字符串资源 public: std::wstring m_cur_time; std::wstring m_cur_date; SYSTEMTIME m_system_time; SettingData m_setting_data; private: static CDataManager m_instance; std::wstring m_config_path; std::map m_string_table; }; ================================================ FILE: PluginDemo/OptionsDlg.cpp ================================================ // OptionsDlg.cpp: 实现文件 // #include "pch.h" #include "PluginDemo.h" #include "OptionsDlg.h" #include "afxdialogex.h" // COptionsDlg 对话框 IMPLEMENT_DYNAMIC(COptionsDlg, CDialog) COptionsDlg::COptionsDlg(CWnd* pParent /*=nullptr*/) : CDialog(IDD_OPTIONS_DIALOG, pParent) { } COptionsDlg::~COptionsDlg() { } void COptionsDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(COptionsDlg, CDialog) ON_BN_CLICKED(IDC_SHOW_SECOND_CHECK, &COptionsDlg::OnBnClickedShowSecondCheck) END_MESSAGE_MAP() // COptionsDlg 消息处理程序 BOOL COptionsDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 //初始化控件状态 CheckDlgButton(IDC_SHOW_SECOND_CHECK, m_data.show_second); //CheckDlgButton(IDC_SHOW_LABEL_CHECK, m_data.show_label_text); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void COptionsDlg::OnBnClickedShowSecondCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.show_second = (IsDlgButtonChecked(IDC_SHOW_SECOND_CHECK) != 0); } ================================================ FILE: PluginDemo/OptionsDlg.h ================================================ #pragma once #include "DataManager.h" // COptionsDlg 对话框 class COptionsDlg : public CDialog { DECLARE_DYNAMIC(COptionsDlg) public: COptionsDlg(CWnd* pParent = nullptr); // 标准构造函数 virtual ~COptionsDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_OPTIONS_DIALOG }; #endif SettingData m_data; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnBnClickedShowSecondCheck(); }; ================================================ FILE: PluginDemo/PluginDemo.cpp ================================================ #include "pch.h" #include "PluginDemo.h" #include "DataManager.h" #include "OptionsDlg.h" CPluginDemo CPluginDemo::m_instance; CPluginDemo::CPluginDemo() { } CPluginDemo& CPluginDemo::Instance() { return m_instance; } IPluginItem* CPluginDemo::GetItem(int index) { switch (index) { case 0: return &m_system_date; case 1: return &m_system_time; case 2: return &m_custom_draw_item; default: break; } return nullptr; } void CPluginDemo::DataRequired() { //获取时间和日期 SYSTEMTIME& system_time{ CDataManager::Instance().m_system_time }; GetLocalTime(&system_time); wchar_t buff[128]; swprintf_s(buff, L"%d/%.2d/%.2d", system_time.wYear, system_time.wMonth, system_time.wDay); CDataManager::Instance().m_cur_date = buff; if (CDataManager::Instance().m_setting_data.show_second) swprintf_s(buff, L"%.2d:%.2d:%.2d", system_time.wHour, system_time.wMinute, system_time.wSecond); else swprintf_s(buff, L"%.2d:%.2d", system_time.wHour, system_time.wMinute); CDataManager::Instance().m_cur_time = buff; } const wchar_t* CPluginDemo::GetInfo(PluginInfoIndex index) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); static CString str; switch (index) { case TMI_NAME: str.LoadString(IDS_PLUGIN_NAME); return str.GetString(); case TMI_DESCRIPTION: str.LoadString(IDS_PLUGIN_DESCRIPTION); return str.GetString(); case TMI_AUTHOR: return L"zhongyang219"; case TMI_COPYRIGHT: return L"Copyright (C) by Zhong Yang 2021"; case TMI_VERSION: return L"1.0"; case ITMPlugin::TMI_URL: return L"https://github.com/zhongyang219/TrafficMonitor"; break; default: break; } return L""; } ITMPlugin::OptionReturn CPluginDemo::ShowOptionsDialog(void* hParent) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); COptionsDlg dlg(CWnd::FromHandle((HWND)hParent)); dlg.m_data = CDataManager::Instance().m_setting_data; if (dlg.DoModal() == IDOK) { CDataManager::Instance().m_setting_data = dlg.m_data; return ITMPlugin::OR_OPTION_CHANGED; } return ITMPlugin::OR_OPTION_UNCHANGED; } void CPluginDemo::OnExtenedInfo(ExtendedInfoIndex index, const wchar_t* data) { switch (index) { case ITMPlugin::EI_CONFIG_DIR: //从配置文件读取配置 g_data.LoadConfig(std::wstring(data)); break; default: break; } } ITMPlugin* TMPluginGetInstance() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return &CPluginDemo::Instance(); } ================================================ FILE: PluginDemo/PluginDemo.h ================================================ #pragma once #include "PluginInterface.h" #include "PluginSystemDate.h" #include "PluginSystemTime.h" #include "CustomDrawItem.h" class CPluginDemo : public ITMPlugin { private: CPluginDemo(); public: static CPluginDemo& Instance(); // 通过 ITMPlugin 继承 virtual IPluginItem* GetItem(int index) override; virtual void DataRequired() override; virtual const wchar_t* GetInfo(PluginInfoIndex index) override; virtual OptionReturn ShowOptionsDialog(void* hParent) override; virtual void OnExtenedInfo(ExtendedInfoIndex index, const wchar_t* data) override; private: CPluginSystemDate m_system_date; CPluginSystemTime m_system_time; CCustomDrawItem m_custom_draw_item; static CPluginDemo m_instance; }; #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) ITMPlugin* TMPluginGetInstance(); #ifdef __cplusplus } #endif ================================================ FILE: PluginDemo/PluginDemo.rc ================================================ // Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // (壬й) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #pragma code_page(936) #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_OPTIONS_DIALOG DIALOGEX 0, 0, 165, 77 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ʱں" FONT 9, "΢ź", 400, 0, 0x0 BEGIN DEFPUSHBUTTON "ȷ",IDOK,50,56,50,14 PUSHBUTTON "ȡ",IDCANCEL,108,56,50,14 GROUPBOX "ʽ",IDC_STATIC,7,7,151,45 CONTROL "ʾ",IDC_SHOW_SECOND_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,21,63,10 END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN IDD_OPTIONS_DIALOG, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 158 TOPMARGIN, 7 BOTTOMMARGIN, 70 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // AFX_DIALOG_LAYOUT // IDD_OPTIONS_DIALOG AFX_DIALOG_LAYOUT BEGIN 0 END ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,1 PRODUCTVERSION 1,0,0,1 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "080404b0" BEGIN VALUE "CompanyName", "By ZhongYang" VALUE "FileDescription", "Plugin Demo for TrafficMonitor" VALUE "FileVersion", "1.0.0.1" VALUE "InternalName", "PluginDe.dll" VALUE "LegalCopyright", "Copyright (C) 2021 By ZhongYang" VALUE "OriginalFilename", "PluginDe.dll" VALUE "ProductName", "Plugin Demo for TrafficMonitor" VALUE "ProductVersion", "1.0.0.1" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x804, 1200 END END ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE BEGIN IDS_PLUGIN_NAME "TrafficMonitorʾ" IDS_PLUGIN_DESCRIPTION "TrafficMonitorʾΪ߿TrafficMonitorṩ" IDS_TIME "ʱ" IDS_DATE "" IDS_CUSTOM_DRAW_ITEM "Իʾ" END #endif // (壬й) resources ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Ӣ() resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_OPTIONS_DIALOG DIALOGEX 0, 0, 165, 74 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Time and date settings" FONT 9, "Segoe UI", 400, 0, 0x0 BEGIN DEFPUSHBUTTON "OK",IDOK,50,53,50,14 PUSHBUTTON "Cancel",IDCANCEL,108,53,50,14 GROUPBOX "Format",IDC_STATIC,7,7,151,42 CONTROL "Show seconds",IDC_SHOW_SECOND_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,21,63,10 END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN IDD_OPTIONS_DIALOG, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 158 TOPMARGIN, 7 BOTTOMMARGIN, 67 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // AFX_DIALOG_LAYOUT // IDD_OPTIONS_DIALOG AFX_DIALOG_LAYOUT BEGIN 0 END ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE BEGIN IDS_PLUGIN_NAME "A sample plug-in for TrafficMonitor." IDS_PLUGIN_DESCRIPTION "A sample plug-in for TrafficMonitor, providing an example for developers to develop TrafficMonitor plug-ins." IDS_TIME "Time" IDS_DATE "Date" IDS_CUSTOM_DRAW_ITEM "Custom draw example" END #endif // Ӣ() resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: PluginDemo/PluginDemo.vcxproj ================================================ Debug Win32 Release Win32 Debug x64 Release x64 16.0 Win32Proj {d1ca3ecc-dc32-445a-b734-c4db08d4ba34} PluginDemo 10.0 DynamicLibrary true v142 Unicode Dynamic DynamicLibrary false v142 true Unicode Dynamic DynamicLibrary true v142 Unicode Dynamic DynamicLibrary false v142 true Unicode Dynamic true $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)Bin\$(Configuration)\plugins\ false $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)Bin\$(Configuration)\plugins\ true $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)Bin\$(Platform)\$(Configuration)\plugins\ false $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)Bin\$(Platform)\$(Configuration)\plugins\ Level3 true WIN32;_DEBUG;PLUGINDEMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use pch.h Windows true false Level3 true true true WIN32;NDEBUG;PLUGINDEMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use pch.h Windows true true true false Level3 true _DEBUG;PLUGINDEMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use pch.h Windows true false Level3 true true true NDEBUG;PLUGINDEMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use pch.h Windows true true true false Create Create Create Create ================================================ FILE: PluginDemo/PluginDemo.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 头文件 头文件 头文件 头文件 头文件 头文件 头文件 头文件 头文件 头文件 源文件 源文件 源文件 源文件 源文件 源文件 源文件 资源文件 ================================================ FILE: PluginDemo/PluginSystemDate.cpp ================================================ #include "pch.h" #include #include "PluginSystemDate.h" #include "DataManager.h" CPluginSystemDate::CPluginSystemDate() { } const wchar_t* CPluginSystemDate::GetItemName() const { return CDataManager::Instance().StringRes(IDS_DATE); } const wchar_t* CPluginSystemDate::GetItemId() const { return L"o282ffc4"; } const wchar_t* CPluginSystemDate::GetItemLableText() const { return CDataManager::Instance().StringRes(IDS_DATE); } const wchar_t* CPluginSystemDate::GetItemValueText() const { return CDataManager::Instance().m_cur_date.c_str(); } const wchar_t* CPluginSystemDate::GetItemValueSampleText() const { return L"2022/08/08"; } ================================================ FILE: PluginDemo/PluginSystemDate.h ================================================ #pragma once #include "PluginInterface.h" class CPluginSystemDate : public IPluginItem { public: CPluginSystemDate(); // 通过 IPluginItem 继承 virtual const wchar_t* GetItemName() const override; virtual const wchar_t* GetItemId() const override; virtual const wchar_t* GetItemLableText() const override; virtual const wchar_t* GetItemValueText() const override; virtual const wchar_t* GetItemValueSampleText() const override; private: }; ================================================ FILE: PluginDemo/PluginSystemTime.cpp ================================================ #include "pch.h" #include #include "PluginSystemTime.h" #include "DataManager.h" CPluginSystemTime::CPluginSystemTime() { } const wchar_t* CPluginSystemTime::GetItemName() const { return CDataManager::Instance().StringRes(IDS_TIME); } const wchar_t* CPluginSystemTime::GetItemId() const { return L"ra1YX2g1"; } const wchar_t* CPluginSystemTime::GetItemLableText() const { return CDataManager::Instance().StringRes(IDS_TIME); } const wchar_t* CPluginSystemTime::GetItemValueText() const { return CDataManager::Instance().m_cur_time.c_str(); } const wchar_t* CPluginSystemTime::GetItemValueSampleText() const { if (CDataManager::Instance().m_setting_data.show_second) return L"12:00:00"; else return L"12:00"; } ================================================ FILE: PluginDemo/PluginSystemTime.h ================================================ #pragma once #include "PluginInterface.h" class CPluginSystemTime : public IPluginItem { public: CPluginSystemTime(); public: // 通过 IPluginItem 继承 virtual const wchar_t* GetItemName() const override; virtual const wchar_t* GetItemId() const override; virtual const wchar_t* GetItemLableText() const override; virtual const wchar_t* GetItemValueText() const override; virtual const wchar_t* GetItemValueSampleText() const override; private: }; ================================================ FILE: PluginDemo/framework.h ================================================ #pragma once #define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容 //// Windows 头文件 //#include #include #include // MFC 核心组件和标准组件 #include // MFC 扩展 #include // MFC 自动化类 #ifdef _UNICODE #if defined _M_IX86 #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") #elif defined _M_X64 #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") #else #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #endif #endif ================================================ FILE: PluginDemo/pch.cpp ================================================ // pch.cpp: 与预编译标头对应的源文件 #include "pch.h" // 当使用预编译的头时,需要使用此源文件,编译才能成功。 ================================================ FILE: PluginDemo/pch.h ================================================ // pch.h: 这是预编译标头文件。 // 下方列出的文件仅编译一次,提高了将来生成的生成性能。 // 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。 // 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。 // 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。 #ifndef PCH_H #define PCH_H // 添加要在此处预编译的标头 #include "framework.h" #include "resource.h" #endif //PCH_H ================================================ FILE: PluginDemo/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 PluginDemo.rc 使用 // #define IDD_DIALOG1 101 #define IDD_OPTIONS_DIALOG 101 #define IDS_PLUGIN_NAME 103 #define IDS_PLUGIN_DESCRIPTION 104 #define IDS_TIME 105 #define IDS_DATE 106 #define IDS_CUSTOM_DRAW_ITEM 107 #define IDC_SHOW_SECOND_CHECK 1001 #define IDC_SHOW_LABEL_CHECK 1002 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 104 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1003 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: README.md ================================================ **简体中文 | [English](./README_en-us.md)**
[![Badge](https://img.shields.io/badge/link-996.icu-%23FF4D5B.svg?style=flat-square)](https://996.icu/#/en_US) [![LICENSE](https://img.shields.io/badge/license-Anti%20996-blue.svg?style=flat-square)](https://github.com/996icu/996.ICU/blob/master/LICENSE) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/zhongyang219/TrafficMonitor/Release%20CI?label=Release%20CI&logo=github&style=flat-square)](https://github.com/zhongyang219/TrafficMonitor/actions?query=workflow:"Release+CI") [![GitHub release](https://img.shields.io/github/release/zhongyang219/TrafficMonitor.svg?style=flat-square)](https://github.com/zhongyang219/TrafficMonitor/releases/latest) # TrafficMonitor 简介 Traffic Monitor是一款用于Windows平台的网速监控悬浮窗软件,可以显示当前网速、CPU及内存利用率,支持嵌入到任务栏显示,支持更换皮肤、历史流量统计等功能。 # 相关链接: 请[点击此处](https://github.com/zhongyang219/TrafficMonitor/releases/latest)下载TrafficMonitor的最新版本。
备用链接:[百度网盘下载](https://pan.baidu.com/s/15PMt7s-ASpyDwtS__4cUhg) 提取码:`ou0m`
国内用户如果遇到Github下载缓慢的问题,可以[点击此处](https://gitee.com/zhongyang219/TrafficMonitor)转到此项目在Gitee上的页面。 如果遇到问题,请[点击此处](./Help.md)。
你也可以[点击此处](https://github.com/zhongyang219/TrafficMonitor/actions?query=workflow:"Release+CI")下载TrafficMonitor的预发行构建版本。 从1.80版本开始,TrafficMonitor加入了温度监控功能,如果你不需要温度监控功能,并且在使用1.80以上版本中遇到了问题,建议下载不含温度监控的版本(Lite版本)。(在Release页面找到文件名包含`Lite`的版本。) TrafficMonitor依赖于Microsoft Visual C++ 运行环境,如果程序启动时提示“找不到MSVC*.dll”,请点击以下链接下载并安装Microsoft Visual C++ 运行环境。 [最新支持的 Visual C++ 可再发行程序包下载 | Microsoft Docs](https://docs.microsoft.com/zh-CN/cpp/windows/latest-supported-vc-redist?view=msvc-170) # 版本说明 TrafficMonitor提供了普通版和Lite版两种版本可用。普通版包含了所有的功能,Lite版本则不包含温度监控、显卡利用率、硬盘利用率等硬件监控功能。普通版运行需要管理员权限,而Lite版本则不需要。 如果没有监控温度等硬件信息的需要,建议使用Lite版。 以下是两个版本功能对比。 | 功能 | 普通版 | Lite版 | | ----------------------------- | ------ | ------ | | 网速监控 | ✔ | ✔ | | CPU、内存利用率 | ✔ | ✔ | | CPU、显卡、硬盘、主板温度监控、CPU频率监控 | ✔ | ❌ | | 显卡利用率监控 | ✔ | ❌ | | 硬盘利用率监控 | ✔ | ❌ | | 网络详细信息 | ✔ | ✔ | | 插件系统 | ✔ | ✔ | | 主窗口更换皮肤 | ✔ | ✔ | | 需要管理员权限 | 是 | 否 | # 主要特性 * 显示当前实现网络传输速率、CPU和内存占用率 * 如果电脑有多个网卡,支持自动和手动选择网络连接 * 查看网络详细信息 * 支持嵌入到任务栏显示 * 支持更换皮肤和自定义皮肤 * 历史流量统计 * 硬件信息监控 * 插件系统 # 使用说明 **[点击这里](https://github.com/zhongyang219/TrafficMonitor/wiki)转到Wiki页面查看关于TrafficMonitor的详细说明文档。** # 截图 主悬浮窗:
![](./Screenshots/main1.png)
右键菜单:
![](./Screenshots/main.png)
任务栏窗口:
![](./Screenshots/taskbar.PNG)
多彩皮肤:

# 如何使用 程序启动后在会在屏幕中显示一个显示网速的悬浮窗。在悬浮窗上点击鼠标右键可以弹出右键菜单。 TrafficMonitor支持将信息显示到任务栏。但是TrafficMonitor默认只显示主窗口(悬浮窗),如果需要让它嵌入到任务栏显示,请在右键菜单中选择“显示任务栏窗口”命令。 任务栏窗口支持自定义显示项目,默认情况下只显示网速,如果需要显示CPU和内存利用率,请在任务栏右键菜单中的“显示设置”子菜单下勾选需要显示的项目,如下图所示: # 自定义皮肤
在主窗口或通知区图标右键菜单上选择“其他功能”——“更换皮肤”可以打开更换皮肤界面。[点击此处](https://github.com/zhongyang219/TrafficMonitorSkin/blob/master/皮肤下载.md)可以下载更多皮肤。用户还可以根据自己的需要编辑自己的皮肤。
皮肤文件放在程序所在目录的`skins`目录下,每个皮肤被放到单独的文件夹下,文件夹的名称就是皮肤的名称。
其中`background.bmp`和`background_l.bmp`是背景图片,`skin.ini`是皮肤的配置文件,可以通过`skin.ini`指定文本颜色、字体、皮肤作者、每个项目的大小和位置等信息。
从1.80版本开始增加了xml格式的皮肤配置文件`skin.xml`,只有xml格式的皮肤配置文件才支持温度和显卡使用率显示。 详细的皮肤制作教程请点击以下链接: [皮肤制作教程 · zhongyang219/TrafficMonitor Wiki (github.com)](https://github.com/zhongyang219/TrafficMonitor/wiki/皮肤制作教程) 推荐使用[皮肤编辑器](https://github.com/zhongyang219/TrafficMonitorSkinEditor/releases)来创建或编辑皮肤。
# 选项设置
在右键菜单选择“选项...”可以进入选项设置。在选项设置对话框中,可以单独设置主窗口和任务栏窗口的文本颜色、字体、背景颜色、网速单位、显示的文本等。
在“常规设置”选项卡中,可以设置是否在程序时自动检查更新,以及是否需要在开机是自动运行。可以设置在什么时候需要发出消息通知。
从1.72版本开始,支持每个项目文本颜色单独设置。勾选“指定每个项目的颜色”后,点击“文本颜色”右边的颜色框,会弹出详细颜色设置的对话框,可以在这里单独指定每个项目的颜色。
# 插件系统 从1.82版本开始增加了插件系统,插件dll必须放在“TrafficMonitor.exe”同级目录的“plugins”目录下。程序启动后,插件会自动加载。你可以在右键菜单“更多功能”——“插件管理”中查看并管理已加载的插件。 关于如何开发TrafficMonitor的说明,请参见[插件开发指南 · zhongyang219/TrafficMonitor Wiki (github.com)](https://github.com/zhongyang219/TrafficMonitor/wiki/插件开发指南)。 要下载TrafficMonitor插件,请[点击这里](https://github.com/zhongyang219/TrafficMonitorPlugins/blob/main/download/plugin_download.md)。 # 关于硬件监控功能 从1.80版本开始,TrafficMonitor加入了硬件监控功能(包括温度监控和显卡使用率监控、CPU频率监控),它使用了第三方开源库[LibreHardwareMonitor](https://github.com/LibreHardwareMonitor/LibreHardwareMonitor)。如果你在使用温度监控功能时遇到了问题,请[点击这里](./Help.md#13-关于trafficmonitor温度监控的问题)。 需要注意的是,温度监控功能默认是关闭的,如果你要使用TrafficMonitor的温度监控功能,请到[“选项设置”-“常规设置”-“硬件监控”](https://github.com/zhongyang219/TrafficMonitor/wiki/选项设置#硬件监控)中开启。 **注意:硬件监控功能(包括温度监控和显卡使用率监控)可能存在一些问题,它可能会占用更多的CPU和内存。据部分用户反馈,开启温度功能后会导致程序崩溃和系统死机等问题,请在知晓以上风险后再决定开启硬件监控功能。否则,请不要使用硬件监控功能。** # 更新日志 **[点击此处查看更新日志](./UpdateLog/update_log.md)** ================================================ FILE: README_en-us.md ================================================ **[简体中文](./README.md) | English**
[![Badge](https://img.shields.io/badge/link-996.icu-%23FF4D5B.svg?style=flat-square)](https://996.icu/#/en_US) [![LICENSE](https://img.shields.io/badge/license-Anti%20996-blue.svg?style=flat-square)](https://github.com/996icu/996.ICU/blob/master/LICENSE) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/zhongyang219/TrafficMonitor/Release%20CI?label=Release%20CI&logo=github&style=flat-square)](https://github.com/zhongyang219/TrafficMonitor/actions?query=workflow:"Release+CI") [![GitHub release](https://img.shields.io/github/release/zhongyang219/TrafficMonitor.svg?style=flat-square)](https://github.com/zhongyang219/TrafficMonitor/releases/latest) # TrafficMonitor Introduction TrafficMonitor is a network monitoring suspension window software on Windows platform. It can display the current network speed, usage of CPU. It also has the function of displaying in the taskbar, skin changing and historical traffic statistics. # Related Links Please [click here](https://github.com/zhongyang219/TrafficMonitor/releases/latest) to download the latest version of TrafficMonitor. Alternate link: Download from [Baidu Netdisk](https://pan.baidu.com/s/15PMt7s-ASpyDwtS__4cUhg). Access code: `ou0m` If you encounter any problems, please [click here](./Help_en-us.md). You can also [click here](https://github.com/zhongyang219/TrafficMonitor/actions?query=workflow:"Release+CI") to download the pre-release build version of TrafficMonitor. Starting from version 1.80, the temperature monitoring function has been added. If you do not need the temperature monitoring function and encounter problems with version 1.80 or higher, it is recommended to download the version which is without temperature monitoring (Lite version). (Find the version that contains `Lite` in the file name on Release page.) TrafficMonitor relies on the Microsoft Visual C++ runtime environment. If the program prompts "Cannot find MSVC*.dll" when the program starts, please click the link below to download and install the Microsoft Visual C++ runtime environment. [Latest supported Visual C++ Redistributable downloads | Microsoft Docs](https://docs.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170) # Version description TrafficMonitor provides two versions, the standard version and the Lite version. The standard version includes all the functions, while the Lite version does not include hardware monitoring functions such as temperature monitoring, GPU usage, and hard disk usage. The standard version requires administrator to run, while the Lite version does not. If there is no need to monitor the temperature and other hardware information, it is recommended to use the Lite version. The functions comparison of the two versions is as the following. | Functions | Standard Version | Lite Version | | ------------------------------------------------------ | ---------------- | ------------ | | Net speed monitoring | ✔ | ✔ | | CPU and memory usage monitoring | ✔ | ✔ | | CPU, GPU, hard disk, main board temperature, CPU frequency monitoring | ✔ | ❌ | | GPU usage monitoring | ✔ | ❌ | | Hard disk usage monitoring | ✔ | ❌ | | Network connection details | ✔ | ✔ | | Plug-in system | ✔ | ✔ | | Change the skin of the main window | ✔ | ✔ | | Administrator rights required | Yes | No | # Main Features * Displays the current network transfer speed, usage of CPU and memory. * Support automatic or manual selection of network connections if there are multiple network adapters. * Display the network connection details. * Support the window displayed in the taskbar. * Support for changing skin and customizing skin. * Historical traffic statistics. * Hardware information monitoring * Plug-in system # Instructions for use **[Click here](https://github.com/zhongyang219/TrafficMonitor/wiki) to go to the Wiki page to view detailed documentation on TrafficMonitor (Only Chinese Available).** # Screen Shots Main Suspension Window: ![](./Screenshots/en_us/main1.png) Right-Click Menu: ![](./Screenshots/en_us/main.png) Taskbar Window ![](./Screenshots/en_us/taskbar.png) Colorful Skins: ![](./Screenshots/skins.PNG) Change Skins: ![](./Screenshots/en_us/selecte_skin.png) Options: # How to Use After the program started, a floating window showing the network speed will be displayed on the screen. Click the right mouse button on the floating window to pop up the right-click menu. TrafficMonitor supports displaying information on the taskbar. But TrafficMonitor only displays the main window (floating window) by default. If you want to embed it into the taskbar, please select the "Show taskbar window" command in the right-click menu. Taskbar window supports customization of display items. By default, only the network speed is displayed. If you need to display the CPU and memory usage, please check the items that need to be displayed under the "Display Settings" submenu in the taskbar right-click menu, as shown in the figure below: # Plug-in system The plug-in system has been added since version 1.82. The plug-in dll must be placed in the "plugins" directory of the same level directory of "TrafficMonitor.exe". After the program is started, the plug-in will be loaded automatically. You can view and manage the loaded plugins in the context menu "More Functions"-"Plugin Management". For instructions on how to develop the plugin-in of TrafficMonitor, please see [Plugin Development Guide · zhongyang219/TrafficMonitor Wiki (github.com)](https://github.com/zhongyang219/TrafficMonitor/wiki/Plugin-Development-Guide). To download the TrafficMonitor plug-in, please [click here](https://github.com/zhongyang219/TrafficMonitorPlugins/blob/main/download/plugin_download.md). # About the hardware monitoring function Starting from version 1.80, the hardware monitoring functions (including temperature monitoring, CPU frequency and graphics card usage monitoring) has been added in TrafficMonitor. It relies on the open source library [LibreHardwareMonitor](https://github.com/LibreHardwareMonitor/LibreHardwareMonitor). If you encounter problems during using the temperature monitoring function, please [click here](./Help_en-us.md#13-about-the-temperature-monitoring-of-trafficmonitor). It should be noted that the temperature monitoring function is turned off by default. If you want to use the temperature monitoring function of TrafficMonitor, please go to ["Option Settings"-"General Settings"-"Hardware Monitoring"](https://github.com/zhongyang219/TrafficMonitor/wiki/选项设置#硬件监控) to enable it. **Note: The hardware monitoring function (including temperature monitoring and GPU usage monitoring) may have some problems, which may cause more CPU and memory usage. According to feedback from some users, turning on the temperature function will cause problems such as program crashes and system crashes. Please decide to turn on the hardware monitoring function after you are aware of the above risks. Otherwise, please do not use the hardware monitoring function.** # Update log **[Click here to view the update log.](./UpdateLog/update_log_en-us.md)** ================================================ FILE: TrafficMonitor/AboutDlg.cpp ================================================ #include "stdafx.h" #include "TrafficMonitor.h" #include "AboutDlg.h" #include "MessageDlg.h" #include "DrawCommon.h" BEGIN_MESSAGE_MAP(CAboutDlg, CBaseDialog) //ON_STN_CLICKED(IDC_STATIC_DONATE, &CAboutDlg::OnStnClickedStaticDonate) ON_MESSAGE(WM_LINK_CLICKED, &CAboutDlg::OnLinkClicked) ON_WM_PAINT() ON_WM_ERASEBKGND() ON_WM_CTLCOLOR() END_MESSAGE_MAP() CAboutDlg::CAboutDlg() : CBaseDialog(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_STATIC_MAIL, m_mail); DDX_Control(pDX, IDC_STATIC_ACKNOWLEDGEMENT, m_acknowledgement); DDX_Control(pDX, IDC_STATIC_GITHUB, m_github); DDX_Control(pDX, IDC_STATIC_DONATE, m_donate); DDX_Control(pDX, IDC_TRANSLATOR_STATIC, m_translaotr_static); DDX_Control(pDX, IDC_STATIC_LICENSE, m_license); DDX_Control(pDX, IDC_OPENHARDWAREMONITOR_LINK, m_openhardwaremonitor_link); DDX_Control(pDX, IDC_TINYXML2_LINK, m_tinyxml2_link); DDX_Control(pDX, IDC_MUSICPLAYER2_LINK, m_musicplayer2_link); DDX_Control(pDX, IDC_SIMPLENOTEPAD_LINK, m_simplenotepad_link); DDX_Control(pDX, IDC_STATIC_GITEE, m_gitee); } CString CAboutDlg::GetDonateList() { return CCommon::GetTextResource(IDR_ACKNOWLEDGEMENT_TEXT, 2); } CString CAboutDlg::GetDialogName() const { return _T("AboutDlg"); } BOOL CAboutDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetWindowText(CCommon::LoadText(IDS_TITLE_ABOUT)); m_mail.SetURL(_T("mailto:zhongyang219@hotmail.com")); //设置超链接 //m_check_update.SetURL(_T("http://pan.baidu.com/s/1c1LkPQ4")); m_github.SetURL(_T("https://github.com/zhongyang219/TrafficMonitor")); m_gitee.SetURL(_T("https://gitee.com/zhongyang219/TrafficMonitor")); m_donate.SetLinkIsURL(false); m_acknowledgement.SetLinkIsURL(false); m_license.SetLinkIsURL(false); m_openhardwaremonitor_link.SetURL(_T("https://github.com/LibreHardwareMonitor/LibreHardwareMonitor")); m_tinyxml2_link.SetURL(_T("https://github.com/leethomason/tinyxml2")); m_musicplayer2_link.SetURL(_T("https://github.com/zhongyang219/MusicPlayer2")); m_simplenotepad_link.SetURL(_T("https://github.com/zhongyang219/SimpleNotePad")); m_openhardwaremonitor_link.SetBackgroundColor(GetSysColor(COLOR_WINDOW)); m_tinyxml2_link.SetBackgroundColor(GetSysColor(COLOR_WINDOW)); m_musicplayer2_link.SetBackgroundColor(GetSysColor(COLOR_WINDOW)); m_simplenotepad_link.SetBackgroundColor(GetSysColor(COLOR_WINDOW)); //设置版本信息 CString version_info; GetDlgItemText(IDC_STATIC_VERSION, version_info); CString str_lite; #ifdef WITHOUT_TEMPERATURE str_lite = CCommon::LoadText(_T(" ("), IDS_WITHOUT_TEMPERATURE, _T(")")); #endif version_info = CCommon::StringFormat(version_info, { str_lite, VERSION }); #ifdef COMPILE_FOR_WINXP version_info += _T(" (For WinXP)"); #endif // COMPILE_FOR_WINXP #ifdef _M_X64 version_info += _T(" (x64)"); #endif #ifdef _DEBUG version_info += _T(" (Debug)"); #endif SetDlgItemText(IDC_STATIC_VERSION, version_info); //设置最后编译日期 CString temp_str; GetDlgItemText(IDC_STATIC_COPYRIGHT, temp_str); CString str_compile_time = CCommon::GetLastCompileTime(); temp_str.Replace(_T(""), str_compile_time); SetDlgItemText(IDC_STATIC_COPYRIGHT, temp_str); m_tool_tip.Create(this, TTS_ALWAYSTIP | TTS_NOPREFIX); m_tool_tip.AddTool(&m_mail, CCommon::LoadText(IDS_SEND_EMAIL_TO_ATHOUR, _T("\r\nmailto:zhongyang219@hotmail.com"))); //m_tool_tip.AddTool(&m_check_update, _T("到百度网盘链接查看是否有更新\r\nhttp://pan.baidu.com/s/1c1LkPQ4")); m_tool_tip.AddTool(&m_github, CCommon::LoadText(IDS_GOTO_GITHUB, _T("\r\nhttps://github.com/zhongyang219/TrafficMonitor"))); m_tool_tip.AddTool(&m_gitee, CCommon::LoadText(IDS_GOTO_GITEE, _T("\r\nhttps://gitee.com/zhongyang219/TrafficMonitor"))); m_tool_tip.AddTool(&m_donate, CCommon::LoadText(IDS_DONATE_ATHOUR)); m_tool_tip.AddTool(&m_openhardwaremonitor_link, m_openhardwaremonitor_link.GetURL()); m_tool_tip.AddTool(&m_tinyxml2_link, m_tinyxml2_link.GetURL()); m_tool_tip.AddTool(&m_musicplayer2_link, CCommon::LoadText(IDS_MUSICPLAYER2_DESCRIPTION) + _T("\r\n") + m_musicplayer2_link.GetURL()); m_tool_tip.AddTool(&m_simplenotepad_link, CCommon::LoadText(IDS_SIMPLENOTEPAD_DESCRIPTION) + _T("\r\n") + m_simplenotepad_link.GetURL()); m_tool_tip.SetDelayTime(300); //设置延迟 m_tool_tip.SetMaxTipWidth(800); //设置翻译者信息 int language_code; language_code = _ttoi(CCommon::LoadText(IDS_LANGUAGE_CODE)); if (language_code == 1 || language_code == 2) //语言是简体中文和英文时不显示翻译者信息 m_translaotr_static.ShowWindow(SW_HIDE); if (language_code == 3) //显示繁体中文翻译者的信息 { m_translaotr_static.SetURL(_T("http://mkvq.blogspot.com/")); m_tool_tip.AddTool(&m_translaotr_static, CCommon::LoadText(IDS_CONTACT_TRANSLATOR, _T("\r\nhttp://mkvq.blogspot.com/"))); } m_translaotr_static.SetBackgroundColor(GetSysColor(COLOR_WINDOW)); //设置图片的位置 CRect rect; GetClientRect(rect); m_rc_pic = rect; ::GetWindowRect(GetDlgItem(IDC_STATIC_VERSION)->GetSafeHwnd(), rect); ScreenToClient(rect); m_rc_pic.bottom = rect.top - theApp.DPI(6); if (m_rc_pic.Height() <= 0) m_rc_pic.bottom = m_rc_pic.top + theApp.DPI(50); //加载图片 m_about_pic.LoadBitmap(IDB_ABOUT_BACKGROUND_HD); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } BOOL CAboutDlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 if (pMsg->message == WM_MOUSEMOVE) m_tool_tip.RelayEvent(pMsg); return CBaseDialog::PreTranslateMessage(pMsg); } //void CAboutDlg::OnStnClickedStaticDonate() //{ // CDonateDlg donateDlg; // donateDlg.DoModal(); //} afx_msg LRESULT CAboutDlg::OnLinkClicked(WPARAM wParam, LPARAM lParam) { CWnd* pCtrl = (CWnd*)wParam; if (pCtrl == &m_donate) { CDonateDlg donateDlg; donateDlg.DoModal(); } else if (pCtrl == &m_acknowledgement) { CString strContent = GetDonateList(); //strContent += _T("\r\n"); //strContent += CCommon::LoadText(IDS_ACKNOWLEDGEMENT_EXPLAIN); CMessageDlg dlg; dlg.SetWindowTitle(CCommon::LoadText(IDS_TITLE_ACKNOWLEDGEMENT)); //dlg.SetInfoText(CCommon::LoadText(IDS_THANKS_DONORS)); dlg.SetMessageText(strContent); dlg.DoModal(); } else if (pCtrl == &m_license) { CMessageDlg dlg; dlg.SetWindowTitle(CCommon::LoadText(IDS_LICENSE)); dlg.SetInfoText(CCommon::LoadText(IDS_LICENSE_EXPLAIN)); dlg.SetMessageText(CCommon::GetTextResource(IDR_LICENSE, 1)); dlg.DoModal(); } return 0; } void CAboutDlg::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CBaseDialog::OnPaint() CDrawCommon draw; draw.Create(&dc, this); draw.GetDC()->FillSolidRect(m_rc_pic, RGB(161, 200, 255)); draw.DrawBitmap(m_about_pic, m_rc_pic.TopLeft(), m_rc_pic.Size(), CDrawCommon::StretchMode::FIT); } BOOL CAboutDlg::OnEraseBkgnd(CDC* pDC) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CRect draw_rect; GetClientRect(draw_rect); pDC->FillSolidRect(draw_rect, GetSysColor(COLOR_WINDOW)); //绘制白色背景 int white_height; //白色区域的高度 CRect rc_copyright{}; ::GetWindowRect(GetDlgItem(IDOK)->GetSafeHwnd(), rc_copyright); ScreenToClient(rc_copyright); white_height = rc_copyright.top - theApp.DPI(6); //绘制“确定”按钮上方的分割线 CRect rc_line{ draw_rect }; rc_line.top = white_height; rc_line.bottom = white_height + theApp.DPI(1); pDC->FillSolidRect(rc_line, RGB(210, 210, 210)); //绘制灰色背景 CRect rc_gray{ rc_line }; rc_gray.top = rc_line.bottom; rc_gray.bottom = draw_rect.bottom; pDC->FillSolidRect(rc_gray, GetSysColor(COLOR_BTNFACE)); return TRUE; //return CBaseDialog::OnEraseBkgnd(pDC); } HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CBaseDialog::OnCtlColor(pDC, pWnd, nCtlColor); // TODO: 在此更改 DC 的任何特性 //去掉static控件的灰色灰色背景 UINT ctrl_id = pWnd->GetDlgCtrlID(); if (ctrl_id == IDC_STATIC_VERSION || ctrl_id == IDC_STATIC_COPYRIGHT || ctrl_id == IDC_STATIC) { static HBRUSH hBackBrush{}; if (hBackBrush == NULL) hBackBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); pDC->SetBkColor(GetSysColor(COLOR_WINDOW)); return hBackBrush; } // TODO: 如果默认的不是所需画笔,则返回另一个画笔 return hbr; } ================================================ FILE: TrafficMonitor/AboutDlg.h ================================================ #pragma once #include "DonateDlg.h" #include "LinkStatic.h" #include "BaseDialog.h" // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CBaseDialog { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: CLinkStatic m_mail; //“联系作者”超链接 CLinkStatic m_acknowledgement; //“鸣谢”超链接 CLinkStatic m_github; //“GitHub”超链接 CLinkStatic m_gitee; //“Gitee”超链接 CLinkStatic m_donate; //“捐助”超链接 CLinkStatic m_license; //“开源协议”超链接 CToolTipCtrl m_tool_tip; //鼠标指向时的工具提示 CLinkStatic m_translaotr_static; CLinkStatic m_openhardwaremonitor_link; CLinkStatic m_tinyxml2_link; CLinkStatic m_musicplayer2_link; CLinkStatic m_simplenotepad_link; CRect m_rc_pic; //图片的位置 CBitmap m_about_pic; virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 CString GetDonateList(); //从资源文件加载捐赠人员名单 virtual CString GetDialogName() const override; // 实现 protected: DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); virtual BOOL PreTranslateMessage(MSG* pMsg); // afx_msg void OnStnClickedStaticDonate(); protected: afx_msg LRESULT OnLinkClicked(WPARAM wParam, LPARAM lParam); public: afx_msg void OnPaint(); afx_msg BOOL OnEraseBkgnd(CDC* pDC); afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); }; ================================================ FILE: TrafficMonitor/AdapterCommon.cpp ================================================ #include "stdafx.h" #include "AdapterCommon.h" CAdapterCommon::CAdapterCommon() { } CAdapterCommon::~CAdapterCommon() { } void CAdapterCommon::GetAdapterInfo(vector& adapters) { adapters.clear(); PIP_ADAPTER_INFO pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[sizeof(IP_ADAPTER_INFO)]; //PIP_ADAPTER_INFOṹָ洢Ϣ unsigned long stSize = sizeof(IP_ADAPTER_INFO); //õṹС,GetAdaptersInfo int nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize); //GetAdaptersInfo,pIpAdapterInfoָ;stSizeһҲһ if (ERROR_BUFFER_OVERFLOW == nRel) { //صERROR_BUFFER_OVERFLOW //˵GetAdaptersInfoݵڴռ䲻,ͬʱ䴫stSize,ʾҪĿռС //Ҳ˵ΪʲôstSizeһҲһ delete[] (BYTE*)pIpAdapterInfo; //ͷԭڴռ pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize]; //ڴռ洢Ϣ nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize); //ٴεGetAdaptersInfo,pIpAdapterInfoָ } PIP_ADAPTER_INFO pIpAdapterInfoHead = pIpAdapterInfo; //pIpAdapterInfoеһԪصĵַ if (ERROR_SUCCESS == nRel) { while (pIpAdapterInfo) { NetWorkConection connection; connection.description = pIpAdapterInfo->Description; connection.ip_address = CCommon::StrToUnicode(pIpAdapterInfo->IpAddressList.IpAddress.String); connection.subnet_mask = CCommon::StrToUnicode(pIpAdapterInfo->IpAddressList.IpMask.String); connection.default_gateway = CCommon::StrToUnicode(pIpAdapterInfo->GatewayList.IpAddress.String); adapters.push_back(connection); pIpAdapterInfo = pIpAdapterInfo->Next; } } //ͷڴռ if (pIpAdapterInfoHead) { delete[] (BYTE*)pIpAdapterInfoHead; } if (adapters.empty()) { NetWorkConection connection{}; connection.description = CCommon::UnicodeToStr(CCommon::LoadText(L"<", IDS_NO_CONNECTION, L">")); adapters.push_back(connection); } } void CAdapterCommon::RefreshIpAddress(vector& adapters) { vector adapters_tmp; GetAdapterInfo(adapters_tmp); for (const auto& adapter_tmp : adapters_tmp) { for (auto& adapter : adapters) { if (adapter_tmp.description == adapter.description) { adapter.ip_address = adapter_tmp.ip_address; adapter.subnet_mask = adapter_tmp.subnet_mask; adapter.default_gateway = adapter_tmp.default_gateway; } } } } void CAdapterCommon::GetIfTableInfo(vector& adapters, MIB_IFTABLE* pIfTable) { //IfTableÿ for (size_t i{}; i < adapters.size(); i++) { if (adapters[i].description.empty()) continue; int index; index = FindConnectionInIfTable(adapters[i].description, pIfTable); if (index == -1) //ʹþȷƥķʽûҵģƥķʽٲһ index = FindConnectionInIfTableFuzzy(adapters[i].description, pIfTable); //if (index != -1) //{ adapters[i].index = index; adapters[i].in_bytes = pIfTable->table[index].dwInOctets; adapters[i].out_bytes = pIfTable->table[index].dwOutOctets; adapters[i].description_2 = (const char*)pIfTable->table[index].bDescr; //} } } void CAdapterCommon::GetAllIfTableInfo(vector& adapters, MIB_IFTABLE * pIfTable) { vector adapters_tmp; GetAdapterInfo(adapters_tmp); //ȡIPַ adapters.clear(); for (size_t i{}; i < pIfTable->dwNumEntries; i++) { NetWorkConection connection; connection.description = connection.description_2 = (const char*)pIfTable->table[i].bDescr; connection.index = i; connection.in_bytes = pIfTable->table[i].dwInOctets; connection.out_bytes = pIfTable->table[i].dwOutOctets; for (size_t j{}; j < adapters_tmp.size(); j++) { if (connection.description.find(adapters_tmp[j].description) != string::npos) { connection.ip_address = adapters_tmp[j].ip_address; connection.subnet_mask = adapters_tmp[j].subnet_mask; connection.default_gateway = adapters_tmp[j].default_gateway; break; } } adapters.push_back(connection); } } int CAdapterCommon::FindConnectionInIfTable(string connection, MIB_IFTABLE* pIfTable) { for (size_t i{}; i < pIfTable->dwNumEntries; i++) { string descr = (const char*)pIfTable->table[i].bDescr; if (descr == connection) return i; } return -1; } int CAdapterCommon::FindConnectionInIfTableFuzzy(string connection, MIB_IFTABLE* pIfTable) { for (size_t i{}; i < pIfTable->dwNumEntries; i++) { string descr = (const char*)pIfTable->table[i].bDescr; size_t index; //ڽϳַҽ϶̵ַ if (descr.size() >= connection.size()) index = descr.find(connection); else index = connection.find(descr); if (index != wstring::npos) return i; } //ûҵʹַƥ㷨 double max_degree{}; int best_index{}; for (size_t i{}; i < pIfTable->dwNumEntries; i++) { string descr = (const char*)pIfTable->table[i].bDescr; double degree = CCommon::StringSimilarDegree_LD(descr, connection); if (degree > max_degree) { max_degree = degree; best_index = i; } } return best_index; } ================================================ FILE: TrafficMonitor/AdapterCommon.h ================================================ #pragma once #include "Common.h" //һϢ struct NetWorkConection { int index{}; //MIB_IFTABLEе string description; //ȡGetAdapterInfo string description_2; //ȡGetIfTable unsigned int in_bytes; //ʼʱѽֽ unsigned int out_bytes; //ʼʱѷֽ wstring ip_address{ L"-.-.-.-" }; //IPַ wstring subnet_mask{ L"-.-.-.-" }; // wstring default_gateway{ L"-.-.-.-" }; //Ĭ }; class CAdapterCommon { public: CAdapterCommon(); ~CAdapterCommon(); //ȡбIPַ롢ĬϢ static void GetAdapterInfo(vector& adapters); //ˢбеIPַ롢ĬϢ static void RefreshIpAddress(vector& adapters); //ȡбÿӵMIB_IFTABLEеʼʱѽ/ֽϢ static void GetIfTableInfo(vector& adapters, MIB_IFTABLE* pIfTable); //ֱӽMIB_IFTABLEеӵadapters static void GetAllIfTableInfo(vector& adapters, MIB_IFTABLE* pIfTable); private: //һжǷIfTableбҲ򷵻-1 static int FindConnectionInIfTable(string connection, MIB_IFTABLE* pIfTable); //һжǷIfTableбҲ򷵻-1ֻҪƥ static int FindConnectionInIfTableFuzzy(string connection, MIB_IFTABLE* pIfTable); }; ================================================ FILE: TrafficMonitor/AppAlreadyRuningDlg.cpp ================================================ // AppAlreadyRuningDlg.cpp: 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "AppAlreadyRuningDlg.h" #include "afxdialogex.h" // CAppAlreadyRuningDlg 对话框 IMPLEMENT_DYNAMIC(CAppAlreadyRuningDlg, CDialog) CAppAlreadyRuningDlg::CAppAlreadyRuningDlg(HWND handel, CWnd* pParent /*=nullptr*/) : CDialog(IDD_APP_ALREAD_RUNING_DIALOG, pParent), m_handle(handel) { } CAppAlreadyRuningDlg::~CAppAlreadyRuningDlg() { } void CAppAlreadyRuningDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAppAlreadyRuningDlg, CDialog) ON_BN_CLICKED(IDC_EXIT_INST_BUTTON, &CAppAlreadyRuningDlg::OnBnClickedExitInstButton) ON_BN_CLICKED(IDC_OPEN_SETTINGS_BUTTON, &CAppAlreadyRuningDlg::OnBnClickedOpenSettingsButton) ON_BN_CLICKED(IDC_SHOW_HIDE_MAIN_WINDOW_BUTTON, &CAppAlreadyRuningDlg::OnBnClickedShowHideMainWindowButton) ON_BN_CLICKED(IDC_SHOW_HIDE_TASKBAR_WINDOW_BUTTON, &CAppAlreadyRuningDlg::OnBnClickedShowHideTaskbarWindowButton) END_MESSAGE_MAP() // CAppAlreadyRuningDlg 消息处理程序 BOOL CAppAlreadyRuningDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetIcon(AfxGetApp()->LoadIcon(IDR_MAINFRAME), FALSE); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CAppAlreadyRuningDlg::OnBnClickedExitInstButton() { ::PostMessage(m_handle, WM_COMMAND, ID_APP_EXIT, 0); } void CAppAlreadyRuningDlg::OnBnClickedOpenSettingsButton() { ::PostMessage(m_handle, WM_COMMAND, ID_OPTIONS, 0); } void CAppAlreadyRuningDlg::OnBnClickedShowHideMainWindowButton() { ::PostMessage(m_handle, WM_COMMAND, ID_SHOW_MAIN_WND, 0); } void CAppAlreadyRuningDlg::OnBnClickedShowHideTaskbarWindowButton() { ::PostMessage(m_handle, WM_COMMAND, ID_SHOW_TASK_BAR_WND, 0); } ================================================ FILE: TrafficMonitor/AppAlreadyRuningDlg.h ================================================ #pragma once // CAppAlreadyRuningDlg 对话框 class CAppAlreadyRuningDlg : public CDialog { DECLARE_DYNAMIC(CAppAlreadyRuningDlg) public: CAppAlreadyRuningDlg(HWND handel, CWnd* pParent = nullptr); // 标准构造函数 virtual ~CAppAlreadyRuningDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_APP_ALREAD_RUNING_DIALOG }; #endif private: HWND m_handle{}; //正在运行的TrafficMonitor进程主窗口的句柄 protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnBnClickedExitInstButton(); afx_msg void OnBnClickedOpenSettingsButton(); afx_msg void OnBnClickedShowHideMainWindowButton(); afx_msg void OnBnClickedShowHideTaskbarWindowButton(); }; ================================================ FILE: TrafficMonitor/BaseDialog.cpp ================================================ // BaseDialog.cpp : 实现文件 // #include "stdafx.h" #include "BaseDialog.h" #include "afxdialogex.h" #include "IniHelper.h" #include "TrafficMonitor.h" // CBaseDialog 对话框 std::map CBaseDialog::m_unique_hwnd; IMPLEMENT_DYNAMIC(CBaseDialog, CDialog) CBaseDialog::CBaseDialog(UINT nIDTemplate, CWnd* pParent /*=NULL*/) : CDialog(nIDTemplate, pParent) { } CBaseDialog::~CBaseDialog() { } void CBaseDialog::SetMinSize(int cx, int cy) { m_min_size.cx = cx; m_min_size.cy = cy; } HWND CBaseDialog::GetUniqueHandel(LPCTSTR dlg_name) { return m_unique_hwnd[dlg_name]; } const std::map& CBaseDialog::AllUniqueHandels() { return m_unique_hwnd; } void CBaseDialog::LoadConfig() { if (!GetDialogName().IsEmpty()) { CIniHelper ini{ theApp.m_config_path }; //载入窗口大小设置 m_window_size.cx = ini.GetInt(_T("window_size"), GetDialogName() + _T("_width"), -1); m_window_size.cy = ini.GetInt(_T("window_size"), GetDialogName() + _T("_height"), -1); } } void CBaseDialog::SaveConfig() const { if (!GetDialogName().IsEmpty()) { CIniHelper ini{ theApp.m_config_path }; //保存窗口大小设置 ini.WriteInt(_T("window_size"), GetDialogName() + _T("_width"), m_window_size.cx); ini.WriteInt(_T("window_size"), GetDialogName() + _T("_height"), m_window_size.cy); ini.Save(); } } void CBaseDialog::EnableDlgCtrl(UINT id, bool enable) { CWnd* pWnd = GetDlgItem(id); if (pWnd != nullptr) pWnd->EnableWindow(enable); } void CBaseDialog::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CBaseDialog, CDialog) ON_WM_DESTROY() ON_WM_GETMINMAXINFO() ON_WM_SIZE() END_MESSAGE_MAP() // CBaseDialog 消息处理程序 BOOL CBaseDialog::OnInitDialog() { m_unique_hwnd[GetDialogName()] = m_hWnd; CDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 //获取初始时窗口的大小 if (m_min_size.cx <= 0 || m_min_size.cy <= 0) { CRect rect; GetWindowRect(rect); m_min_size.cx = rect.Width() * 96 / theApp.GetDpi(); m_min_size.cy = rect.Height() * 96 / theApp.GetDpi(); } //载入设置 LoadConfig(); //初始化窗口大小 if (m_window_size.cx > 0 && m_window_size.cy > 0) { SetWindowPos(nullptr, 0, 0, m_window_size.cx, m_window_size.cy, SWP_NOZORDER | SWP_NOMOVE); } return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CBaseDialog::OnDestroy() { CDialog::OnDestroy(); // TODO: 在此处添加消息处理程序代码 m_unique_hwnd[GetDialogName()] = NULL; SaveConfig(); } void CBaseDialog::OnGetMinMaxInfo(MINMAXINFO* lpMMI) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //限制窗口最小大小 lpMMI->ptMinTrackSize.x = theApp.DPI(m_min_size.cx); //设置最小宽度 lpMMI->ptMinTrackSize.y = theApp.DPI(m_min_size.cy); //设置最小高度 CDialog::OnGetMinMaxInfo(lpMMI); } void CBaseDialog::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 if (nType != SIZE_MAXIMIZED && nType != SIZE_MINIMIZED) { //m_window_width = cx; //m_window_hight = cy; CRect rect; GetWindowRect(&rect); m_window_size.cx = rect.Width(); m_window_size.cy = rect.Height(); } } INT_PTR CBaseDialog::DoModal() { HWND unique_hwnd{ m_unique_hwnd[GetDialogName()] }; if (unique_hwnd != NULL && !GetDialogName().IsEmpty()) ///如果对话框已存在,则显示已存在的对话框 { ::ShowWindow(unique_hwnd, SW_RESTORE); ::SetForegroundWindow(unique_hwnd); return 0; } return CDialog::DoModal(); } ================================================ FILE: TrafficMonitor/BaseDialog.h ================================================ #pragma once // CBaseDialog 对话框 //用于实现记住对话框大小 //并将窗口初始大小设置为最小大小 class CBaseDialog : public CDialog { DECLARE_DYNAMIC(CBaseDialog) public: CBaseDialog(UINT nIDTemplate, CWnd* pParent = NULL); // 标准构造函数 virtual ~CBaseDialog(); // 对话框数据 //#ifdef AFX_DESIGN_TIME // enum { IDD = IDD_BASEDIALOG }; //#endif void SetMinSize(int cx, int cy); //设置窗口的最小大小,如果未设置,则使用窗口的初始大小作为最小大小 static HWND GetUniqueHandel(LPCTSTR dlg_name); //获指定窗口唯一的句柄 static const std::map& AllUniqueHandels(); //获取所有窗口的句柄 private: void LoadConfig(); void SaveConfig() const; private: CSize m_min_size{}; //窗口的最小大小(以 96dpi 的大小保存) CSize m_window_size{ -1, -1 }; static std::map m_unique_hwnd; //针对每一个基类的唯一的窗口句柄 protected: virtual CString GetDialogName() const = 0; void EnableDlgCtrl(UINT id, bool enable); virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnDestroy(); afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI); afx_msg void OnSize(UINT nType, int cx, int cy); virtual INT_PTR DoModal(); }; ================================================ FILE: TrafficMonitor/CAutoAdaptSettingsDlg.cpp ================================================ // CAutoAdaptSettingsDlg.cpp: 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "CAutoAdaptSettingsDlg.h" #include "afxdialogex.h" // CAutoAdaptSettingsDlg 对话框 IMPLEMENT_DYNAMIC(CAutoAdaptSettingsDlg, CDialog) CAutoAdaptSettingsDlg::CAutoAdaptSettingsDlg(TaskBarSettingData& data, CWnd* pParent /*=nullptr*/) : CDialog(IDD_ATUO_ADAPT_SETTING_DIALOG, pParent), m_data(data) { } CAutoAdaptSettingsDlg::~CAutoAdaptSettingsDlg() { } void CAutoAdaptSettingsDlg::InitComboBox(CComboBox& combo_box, int style_sel) { for (int i = 0; i < TASKBAR_DEFAULT_STYLE_NUM; i++) combo_box.AddString(CCommon::LoadText(IDS_PRESET, std::to_wstring(i + 1).c_str())); if (style_sel >= 0 && style_sel < TASKBAR_DEFAULT_STYLE_NUM) combo_box.SetCurSel(style_sel); else combo_box.SetCurSel(0); } int CAutoAdaptSettingsDlg::GetComboBoxSel(const CComboBox& combo_box) { int sel = combo_box.GetCurSel(); if (sel >= 0 && sel < TASKBAR_DEFAULT_STYLE_NUM) return sel; else return 0; } void CAutoAdaptSettingsDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_DARK_MODE_DEFAULT_STYLE_COMBO, m_dark_mode_default_style_combo); DDX_Control(pDX, IDC_LIGHT_MODE_DEFAULT_STYLE_COMBO, m_light_mode_default_style_combo); } BEGIN_MESSAGE_MAP(CAutoAdaptSettingsDlg, CDialog) END_MESSAGE_MAP() // CAutoAdaptSettingsDlg 消息处理程序 BOOL CAutoAdaptSettingsDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 InitComboBox(m_dark_mode_default_style_combo, m_data.dark_default_style); InitComboBox(m_light_mode_default_style_combo, m_data.light_default_style); CheckDlgButton(IDC_AUTO_SAVE_TO_PRESET_CHECK, m_data.auto_save_taskbar_color_settings_to_preset); m_toolTip.Create(this); m_toolTip.SetMaxTipWidth(theApp.DPI(300)); m_toolTip.AddTool(GetDlgItem(IDC_AUTO_SAVE_TO_PRESET_CHECK), CCommon::LoadText(IDS_AUTO_SAVE_TO_PRESET_TIP)); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CAutoAdaptSettingsDlg::OnOK() { // TODO: 在此添加专用代码和/或调用基类 //获取控件中的设置 m_data.dark_default_style = GetComboBoxSel(m_dark_mode_default_style_combo); m_data.light_default_style = GetComboBoxSel(m_light_mode_default_style_combo); m_data.auto_save_taskbar_color_settings_to_preset = (IsDlgButtonChecked(IDC_AUTO_SAVE_TO_PRESET_CHECK) != 0); CDialog::OnOK(); } BOOL CAutoAdaptSettingsDlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 if (pMsg->message == WM_MOUSEMOVE) m_toolTip.RelayEvent(pMsg); return CDialog::PreTranslateMessage(pMsg); } ================================================ FILE: TrafficMonitor/CAutoAdaptSettingsDlg.h ================================================ #pragma once // CAutoAdaptSettingsDlg 对话框 class CAutoAdaptSettingsDlg : public CDialog { DECLARE_DYNAMIC(CAutoAdaptSettingsDlg) public: CAutoAdaptSettingsDlg(TaskBarSettingData& data, CWnd* pParent = nullptr); // 标准构造函数 virtual ~CAutoAdaptSettingsDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ATUO_ADAPT_SETTING_DIALOG }; #endif private: CComboBox m_dark_mode_default_style_combo; CComboBox m_light_mode_default_style_combo; TaskBarSettingData& m_data; CToolTipCtrl m_toolTip; private: void InitComboBox(CComboBox& combo_box, int style_sel); int GetComboBoxSel(const CComboBox& combo_box); protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); virtual void OnOK(); virtual BOOL PreTranslateMessage(MSG* pMsg); }; ================================================ FILE: TrafficMonitor/CMFCColorDialogEx.cpp ================================================ // CMFCColorDialogEx.cpp: 实现文件 // #include "stdafx.h" #include "CMFCColorDialogEx.h" #include "Common.h" // CMFCColorDialogEx //IMPLEMENT_DYNAMIC(CMFCColorDialogEx, CMFCColorDialog) CMFCColorDialogEx::CMFCColorDialogEx(COLORREF clrInit, DWORD dwFlags, CWnd* pParentWnd, HPALETTE hPal) :CMFCColorDialog(clrInit, dwFlags, pParentWnd, hPal) { } CMFCColorDialogEx::~CMFCColorDialogEx() { } BEGIN_MESSAGE_MAP(CMFCColorDialogEx, CMFCColorDialog) END_MESSAGE_MAP() // CMFCColorDialogEx 消息处理程序 BOOL CMFCColorDialogEx::OnInitDialog() { CMFCColorDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 //设置控件字体 CWnd* pParent = GetParent(); if (pParent != nullptr) { CCommon::SetDialogFont(this, pParent->GetFont()); CWnd* pPropSheet = m_pColourSheetOne->GetParent(); if (pPropSheet != nullptr) CCommon::SetDialogFont(pPropSheet, pParent->GetFont()); //CCommon::SetDialogFont(m_pColourSheetOne, pParent->GetFont()); //CCommon::SetDialogFont(m_pColourSheetTwo, pParent->GetFont()); } return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } ================================================ FILE: TrafficMonitor/CMFCColorDialogEx.h ================================================ #pragma once // CMFCColorDialogEx class CMFCColorDialogEx : public CMFCColorDialog { //DECLARE_DYNAMIC(CMFCColorDialogEx) public: CMFCColorDialogEx(COLORREF clrInit = 0, DWORD dwFlags = 0 /* reserved */, CWnd* pParentWnd = NULL, HPALETTE hPal = NULL); virtual ~CMFCColorDialogEx(); protected: DECLARE_MESSAGE_MAP() virtual BOOL OnInitDialog(); }; ================================================ FILE: TrafficMonitor/CPUUsage.cpp ================================================ #include "stdafx.h" #include "CPUUsage.h" #include "Common.h" #include "TrafficMonitor.h" void CCPUUsage::SetUseCPUTimes(bool use_get_system_times) { if (m_use_get_system_times != use_get_system_times) { m_use_get_system_times = use_get_system_times; m_first_get_CPU_utility = true; } } int CCPUUsage::GetCPUUsage() { if (m_use_get_system_times) return GetCPUUsageByGetSystemTimes(); else return GetCPUUsageByPdh(); } int CCPUUsage::GetCPUUsageByGetSystemTimes() { int cpu_usage{}; FILETIME idleTime; FILETIME kernelTime; FILETIME userTime; GetSystemTimes(&idleTime, &kernelTime, &userTime); __int64 idle = CCommon::CompareFileTime2(m_preidleTime, idleTime); __int64 kernel = CCommon::CompareFileTime2(m_prekernelTime, kernelTime); __int64 user = CCommon::CompareFileTime2(m_preuserTime, userTime); if (kernel + user == 0) { cpu_usage = 0; } else { //ܵʱ-ʱ䣩/ܵʱ=ռcpuʱʹ cpu_usage = static_cast(abs((kernel + user - idle) * 100 / (kernel + user))); } m_preidleTime = idleTime; m_prekernelTime = kernelTime; m_preuserTime = userTime; return cpu_usage; } int CCPUUsage::GetCPUUsageByPdh() { int cpu_usage{}; HQUERY hQuery; HCOUNTER hCounter; DWORD counterType; PDH_RAW_COUNTER rawData; PdhOpenQuery(NULL, 0, &hQuery);//ʼѯ const wchar_t* query_str{}; if (theApp.m_win_version.GetMajorVersion() >= 10) query_str = L"\\Processor Information(_Total)\\% Processor Utility"; else query_str = L"\\Processor Information(_Total)\\% Processor Time"; PdhAddCounter(hQuery, query_str, NULL, &hCounter); PdhCollectQueryData(hQuery); PdhGetRawCounterValue(hCounter, &counterType, &rawData); if (m_first_get_CPU_utility) {//ҪݲܼCPUʹ cpu_usage = 0; m_first_get_CPU_utility = false; } else { PDH_FMT_COUNTERVALUE fmtValue; PdhCalculateCounterFromRawValue(hCounter, PDH_FMT_DOUBLE, &rawData, &m_last_rawData, &fmtValue);//ʹ cpu_usage = fmtValue.doubleValue;// if (cpu_usage > 100) cpu_usage = 100; } m_last_rawData = rawData;//һ PdhCloseQuery(hQuery);//رղѯ return cpu_usage; } ================================================ FILE: TrafficMonitor/CPUUsage.h ================================================ #pragma once #include #include #pragma comment(lib,"pdh.lib") class CCPUUsage { public: CCPUUsage() {} ~CCPUUsage() {} void SetUseCPUTimes(bool use_get_system_times); //ûȡCPUʵķʽͨGetSystemTimesPdh int GetCPUUsage(); private: int GetCPUUsageByGetSystemTimes(); int GetCPUUsageByPdh(); private: bool m_use_get_system_times{ true }; //ǷʹGetSysTimeAPIȡCPU PDH_RAW_COUNTER m_last_rawData;//CPUʹʵһ bool m_first_get_CPU_utility{ true }; FILETIME m_preidleTime{}; FILETIME m_prekernelTime{}; FILETIME m_preuserTime{}; }; ================================================ FILE: TrafficMonitor/CSkinPreviewView.cpp ================================================ // CSkinPreviewView.cpp: 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "CSkinPreviewView.h" // CSkinPreviewView IMPLEMENT_DYNCREATE(CSkinPreviewView, CScrollView) CSkinPreviewView::CSkinPreviewView() { } CSkinPreviewView::~CSkinPreviewView() { } BEGIN_MESSAGE_MAP(CSkinPreviewView, CScrollView) END_MESSAGE_MAP() // CSkinPreviewView 绘图 void CSkinPreviewView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal; // TODO: 计算此视图的合计大小 m_size.cx = 0; m_size.cy = 0; SetScrollSizes(MM_TEXT, m_size); } void CSkinPreviewView::OnDraw(CDC* pDC) { CDocument* pDoc = GetDocument(); // TODO: 在此添加绘制代码 CRect draw_rect(CPoint(0, 0), m_size); m_skin_data->DrawPreview(pDC, draw_rect); } // CSkinPreviewView 诊断 //#ifdef _DEBUG //void CSkinPreviewView::AssertValid() const //{ // CScrollView::AssertValid(); //} //#ifndef _WIN32_WCE //void CSkinPreviewView::Dump(CDumpContext& dc) const //{ // CScrollView::Dump(dc); //} //#endif //#endif //_DEBUG void CSkinPreviewView::InitialUpdate() { OnInitialUpdate(); } void CSkinPreviewView::SetSize(int width, int hight) { m_size = CSize(width, hight); SetScrollSizes(MM_TEXT, m_size); } // CSkinPreviewView 消息处理程序 ================================================ FILE: TrafficMonitor/CSkinPreviewView.h ================================================ #pragma once #include "DrawCommon.h" #include "SkinFile.h" // CSkinPreviewView 视图 class CSkinPreviewView : public CScrollView { DECLARE_DYNCREATE(CSkinPreviewView) protected: CSkinPreviewView(); // 动态创建所使用的受保护的构造函数 virtual ~CSkinPreviewView(); public: //#ifdef _DEBUG // virtual void AssertValid() const; //#ifndef _WIN32_WCE // virtual void Dump(CDumpContext& dc) const; //#endif //#endif //成员函数 public: void InitialUpdate(); void SetSize(int width, int hight); void SetSkinData(CSkinFile* skin_data) { m_skin_data = skin_data; } //成员变量 protected: CSize m_size; CPoint m_start_point; //绘图的起始位置 CSkinFile* m_skin_data; protected: virtual void OnDraw(CDC* pDC); // 重写以绘制该视图 virtual void OnInitialUpdate(); // 构造后的第一次 DECLARE_MESSAGE_MAP() }; ================================================ FILE: TrafficMonitor/CTabCtrlEx.cpp ================================================ // CTabCtrlEx.cpp: 实现文件 // #include "stdafx.h" #include "CTabCtrlEx.h" // CTabCtrlEx IMPLEMENT_DYNAMIC(CTabCtrlEx, CTabCtrl) CTabCtrlEx::CTabCtrlEx() { } CTabCtrlEx::~CTabCtrlEx() { } void CTabCtrlEx::AddWindow(CWnd* pWnd, LPCTSTR lable_text) { if (pWnd == nullptr || pWnd->GetSafeHwnd() == NULL) return; InsertItem(m_tab_list.size(), lable_text, m_tab_list.size()); pWnd->SetParent(this); pWnd->MoveWindow(m_tab_rect); m_tab_list.push_back(pWnd); } void CTabCtrlEx::SetCurTab(int index) { if (index < 0 || index >= static_cast(m_tab_list.size())) index = 0; SetCurSel(index); int tab_size = m_tab_list.size(); for (int i = 0; i < tab_size; i++) { if (i == index) { m_tab_list[i]->ShowWindow(SW_SHOW); m_tab_list[i]->SetFocus(); } else { m_tab_list[i]->ShowWindow(SW_HIDE); } } } CWnd* CTabCtrlEx::GetCurrentTab() { int cur_tab_index = GetCurSel(); if (cur_tab_index >= 0 && cur_tab_index < m_tab_list.size()) { return m_tab_list[cur_tab_index]; } return nullptr; } void CTabCtrlEx::AdjustTabWindowSize() { CalSubWindowSize(); for (size_t i{}; i < m_tab_list.size(); i++) { m_tab_list[i]->MoveWindow(m_tab_rect); } } void CTabCtrlEx::CalSubWindowSize() { GetClientRect(m_tab_rect); CRect rc_temp = m_tab_rect; AdjustRect(FALSE, rc_temp); int margin = rc_temp.left - m_tab_rect.left; CRect rcTabItem; GetItemRect(0, rcTabItem); m_tab_rect.top += rcTabItem.Height() + margin; m_tab_rect.left += margin; m_tab_rect.bottom -= margin; m_tab_rect.right -= margin; } BEGIN_MESSAGE_MAP(CTabCtrlEx, CTabCtrl) ON_NOTIFY_REFLECT(TCN_SELCHANGE, &CTabCtrlEx::OnTcnSelchange) ON_WM_SIZE() END_MESSAGE_MAP() // CTabCtrlEx 消息处理程序 void CTabCtrlEx::OnTcnSelchange(NMHDR *pNMHDR, LRESULT *pResult) { // TODO: 在此添加控件通知处理程序代码 int tab_selected = GetCurSel(); SetCurTab(tab_selected); *pResult = 0; } void CTabCtrlEx::PreSubclassWindow() { // TODO: 在此添加专用代码和/或调用基类 //计算子窗口的位置 CalSubWindowSize(); CTabCtrl::PreSubclassWindow(); } void CTabCtrlEx::OnSize(UINT nType, int cx, int cy) { CTabCtrl::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 AdjustTabWindowSize(); } ================================================ FILE: TrafficMonitor/CTabCtrlEx.h ================================================ #pragma once // CTabCtrlEx class CTabCtrlEx : public CTabCtrl { DECLARE_DYNAMIC(CTabCtrlEx) public: CTabCtrlEx(); virtual ~CTabCtrlEx(); void AddWindow(CWnd* pWnd, LPCTSTR lable_text); //ǰtabؼһӴ void SetCurTab(int index); CWnd* GetCurrentTab(); void AdjustTabWindowSize(); protected: void CalSubWindowSize(); DECLARE_MESSAGE_MAP() protected: vector m_tab_list; //tabؼÿӴڵָ public: afx_msg void OnTcnSelchange(NMHDR *pNMHDR, LRESULT *pResult); virtual void PreSubclassWindow(); CRect m_tab_rect; afx_msg void OnSize(UINT nType, int cx, int cy); }; ================================================ FILE: TrafficMonitor/CVariant.cpp ================================================ #include "stdafx.h" #include "CVariant.h" CVariant::CVariant(int value) { m_value_int = value; m_type = eType::INT; } CVariant::CVariant(size_t value) { m_value_int = static_cast(value); m_type = eType::UINT; } CVariant::CVariant(double value) { m_value_double = value; m_type = eType::DOUBLE; } CVariant::CVariant(LPCTSTR value) { m_value_string = value; m_type = eType::STRING; } CVariant::CVariant(const CString& value) { m_value_string = value; m_type = eType::STRING; } CVariant::CVariant(const wstring & value) { m_value_string = value.c_str(); m_type = eType::STRING; } CVariant::~CVariant() { } CString CVariant::ToString() const { CString str; switch (m_type) { case CVariant::eType::INT: str.Format(_T("%d"), m_value_int); break; case eType::UINT: str.Format(_T("%u"), static_cast(m_value_int)); break; case CVariant::eType::DOUBLE: str.Format(_T("%g"), m_value_double); break; case CVariant::eType::STRING: str = m_value_string; break; default: break; } return str; } ================================================ FILE: TrafficMonitor/CVariant.h ================================================ #pragma once class CVariant { public: CVariant(int value); CVariant(size_t value); CVariant(double value); CVariant(LPCTSTR value); CVariant(const CString& value); CVariant(const wstring& value); ~CVariant(); CString ToString() const; private: enum class eType { INT, UINT, DOUBLE, STRING }; int m_value_int; double m_value_double; CString m_value_string; eType m_type; }; ================================================ FILE: TrafficMonitor/CalendarHelper.cpp ================================================ #include "stdafx.h" #include "CalendarHelper.h" CCalendarHelper::CCalendarHelper() { } CCalendarHelper::~CCalendarHelper() { } bool CCalendarHelper::IsLeapYear(int year) { return ((0 == year % 4 && 0 != year % 100) || 0 == year % 400); } int CCalendarHelper::CaculateWeekDay(int y, int m, int d) { if (m <= 2) { m += 12; y--; } return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400 + 1) % 7; } int CCalendarHelper::DaysInMonth(int year, int month) { bool leap{ IsLeapYear(year) }; switch (month) { case 2: if (leap) return 29; else return 28; case 4: case 6: case 9: case 11: return 30; default: return 31; } } void CCalendarHelper::GetCalendar(int year, int month, DayTraffic calendar[CALENDAR_HEIGHT][CALENDAR_WIDTH], bool sunday_first) { memset(calendar, 0, sizeof(DayTraffic)*CALENDAR_HEIGHT*CALENDAR_WIDTH); int days{ DaysInMonth(year, month) }; int first_weak_day{ CaculateWeekDay(year, month, 1) }; if(!sunday_first) { first_weak_day--; if (first_weak_day < 0) first_weak_day = 6; } int i{}, j{}; for (int n{}; n < 37; n++) { if (n < first_weak_day) { calendar[i][j].day = 0; } else { int day = n - first_weak_day + 1; if (day <= days) calendar[i][j].day = day; } j++; if (j >= 7) { j = 0; i++; } } } ================================================ FILE: TrafficMonitor/CalendarHelper.h ================================================ #pragma once #define CALENDAR_WIDTH 7 #define CALENDAR_HEIGHT 6 struct DayTraffic { int day; __int64 up_traffic; __int64 down_traffic; bool mixed; CRect rect; __int64 traffic() const { return up_traffic + down_traffic; } }; class CCalendarHelper { public: CCalendarHelper(); ~CCalendarHelper(); //ǷΪ static bool IsLeapYear(int year); //ڼ(0~6~) static int CaculateWeekDay(int y, int m, int d); //һж static int DaysInMonth(int year, int month); //ȡָ·ݵݣcalendar //sunday_firstΪtrueΪÿܵĵһ죬򣬽һΪÿܵĵһ static void GetCalendar(int year, int month, DayTraffic calendar[CALENDAR_HEIGHT][CALENDAR_WIDTH], bool sunday_first = true); }; ================================================ FILE: TrafficMonitor/ColorSettingListCtrl.cpp ================================================ #include "stdafx.h" #include "ColorSettingListCtrl.h" IMPLEMENT_DYNAMIC(CColorSettingListCtrl, CListCtrl) CColorSettingListCtrl::CColorSettingListCtrl() { } CColorSettingListCtrl::~CColorSettingListCtrl() { } void CColorSettingListCtrl::SetItemColor(int row, int col, COLORREF color) { m_colors[row][col] = color; } COLORREF CColorSettingListCtrl::GetItemColor(int row, int col) { return m_colors[row][col]; } BEGIN_MESSAGE_MAP(CColorSettingListCtrl, CListCtrl) ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CColorSettingListCtrl::OnNMCustomdraw) END_MESSAGE_MAP() void CColorSettingListCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult) { *pResult = CDRF_DODEFAULT; LPNMLVCUSTOMDRAW lplvdr = reinterpret_cast(pNMHDR); NMCUSTOMDRAW& nmcd = lplvdr->nmcd; switch (lplvdr->nmcd.dwDrawStage) //判断状态 { case CDDS_PREPAINT: *pResult = CDRF_NOTIFYITEMDRAW; break; case CDDS_ITEMPREPAINT: //如果为画ITEM之前就要进行颜色的改变 if (nmcd.dwItemSpec >= 0 && nmcd.dwItemSpec < GetItemCount()) { //double range = m_item_rage_data[nmcd.dwItemSpec].data_value; //CDC* pDC = CDC::FromHandle(nmcd.hdc); //获取绘图DC //CRect item_rect, draw_rect; //GetSubItemRect(nmcd.dwItemSpec,m_draw_item_range_row, LVIR_BOUNDS, item_rect); //获取绘图单元格的矩形区域 //CDrawCommon::SetDrawRect(pDC, item_rect); //设置绘图区域为当前列 //draw_rect = item_rect; //if (draw_rect.Height() > 2 * m_margin) //{ // draw_rect.top += m_margin; // draw_rect.bottom -= m_margin; //} //int width; //if (m_use_log_scale) //使用对数比例(y=ln(x+1)) //{ // range = std::log(range + 1); // width = static_cast(range*draw_rect.Width() / std::log(1000 + 1)); //} //else //使用线性比例(y=x) //{ // width = static_cast(range*draw_rect.Width() / 1000); //} //draw_rect.right = draw_rect.left + width; //pDC->FillSolidRect(draw_rect, m_item_rage_data[nmcd.dwItemSpec].color); ////当前列绘制完成后将绘图区域设置为左边的区域,防止当前列的区域被覆盖 //CRect rect1{ item_rect }; //rect1.left = 0; //rect1.right = item_rect.left; //CDrawCommon::SetDrawRect(pDC, rect1); CDC* pDC = CDC::FromHandle(nmcd.hdc); //获取绘图DC CRect item_rect; auto& col_color_map = m_colors[nmcd.dwItemSpec]; for (auto iter = col_color_map.begin(); iter != col_color_map.end(); ++iter) { GetSubItemRect(nmcd.dwItemSpec, iter->first, LVIR_BOUNDS, item_rect); //获取绘图单元格的矩形区域 //设置绘图剪辑区域 CDrawCommon::SetDrawRect(pDC, item_rect); //使用双缓冲绘图 CDrawDoubleBuffer draw_double_buffer(pDC, item_rect); //填充背景 item_rect.MoveToXY(0, 0); draw_double_buffer.GetMemDC()->FillSolidRect(item_rect, GetSysColor(COLOR_WINDOW)); //绘制颜色矩形 item_rect.DeflateRect(m_margin, m_margin); draw_double_buffer.GetMemDC()->FillSolidRect(item_rect, iter->second); //绘制矩形边框 CDrawCommon drawer; drawer.Create(draw_double_buffer.GetMemDC(), this); drawer.DrawRectOutLine(item_rect, RGB(192, 192, 192)); } //当前列绘制完成后将绘图区域设置为第一列的区域,防止颜色列的区域被覆盖 CRect rect1{}; GetSubItemRect(nmcd.dwItemSpec, 1, LVIR_BOUNDS, rect1); //获取第1列单元格的矩形区域 rect1.right = rect1.left; rect1.left = 0; CDrawCommon::SetDrawRect(pDC, rect1); } *pResult = CDRF_DODEFAULT; break; } } ================================================ FILE: TrafficMonitor/ColorSettingListCtrl.h ================================================ #pragma once #include "afxcmn.h" #include "DrawCommon.h" class CColorSettingListCtrl : public CListCtrl { DECLARE_DYNAMIC(CColorSettingListCtrl) public: CColorSettingListCtrl(); ~CColorSettingListCtrl(); void SetItemColor(int row, int col, COLORREF color); COLORREF GetItemColor(int row, int col); void SetDrawItemRangMargin(int margin) { m_margin = margin; } //ûƻƵľεıԵԪ߿ľΣֵԽƵľԽϸDzܳбоһ protected: int m_margin{}; std::map> m_colors; //ڱÿһÿһеɫ DECLARE_MESSAGE_MAP() afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult); }; ================================================ FILE: TrafficMonitor/ColorStatic.cpp ================================================ // ColorStatic.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "ColorStatic.h" #include "DrawCommon.h" // CColorStatic IMPLEMENT_DYNAMIC(CColorStatic, CStatic) CColorStatic::CColorStatic() { } CColorStatic::~CColorStatic() { } void CColorStatic::SetFillColor(COLORREF fill_color) { m_colors.resize(1); m_colors[0] = fill_color; //m_fill_color = fill_color; Invalidate(); } void CColorStatic::SetColorNum(int color_num) { if (color_num <= 0 || color_num > 32) color_num = 1; m_colors.resize(color_num); } void CColorStatic::SetFillColor(int index, COLORREF fill_color) { if (index >= 0 && index < static_cast(m_colors.size())) m_colors[index] = fill_color; } void CColorStatic::SetLinkCursor(bool link_cursor) { m_link_cursor = link_cursor; } void CColorStatic::EnableWindow(bool enable) { CStatic::EnableWindow(enable); Invalidate(FALSE); } BEGIN_MESSAGE_MAP(CColorStatic, CStatic) ON_WM_PAINT() ON_WM_MOUSEHOVER() ON_WM_MOUSELEAVE() ON_WM_SETCURSOR() ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() END_MESSAGE_MAP() // CColorStatic 消息处理程序 void CColorStatic::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CStatic::OnPaint() CRect rect; GetClientRect(rect); rect.MoveToXY(0, 0); CRect rc_tmp{ rect }; CDrawCommon draw; draw.Create(&dc, this); int color_num = static_cast(m_colors.size()); if (IsWindowEnabled() && color_num > 0) { switch (color_num) { case 1: dc.FillSolidRect(rect, m_colors[0]); break; case 4: dc.FillSolidRect(rect, RGB(255,255,255)); rc_tmp.right /= 2; rc_tmp.bottom /= 2; dc.FillSolidRect(rc_tmp, m_colors[0]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[1]); rc_tmp.MoveToXY(0, rc_tmp.bottom); dc.FillSolidRect(rc_tmp, m_colors[2]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[3]); break; case 8: dc.FillSolidRect(rect, RGB(255, 255, 255)); rc_tmp.right /= (color_num / 2); rc_tmp.bottom /= 2; dc.FillSolidRect(rc_tmp, m_colors[0]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[1]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[4]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[5]); rc_tmp.MoveToXY(0, rc_tmp.bottom); dc.FillSolidRect(rc_tmp, m_colors[2]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[3]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[6]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[7]); break; case 16: dc.FillSolidRect(rect, RGB(255, 255, 255)); rc_tmp.right /= color_num / 2; rc_tmp.bottom /= 2; dc.FillSolidRect(rc_tmp, m_colors[0]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[1]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[4]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[5]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[8]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[9]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[12]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[13]); rc_tmp.MoveToXY(0, rc_tmp.bottom); dc.FillSolidRect(rc_tmp, m_colors[2]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[3]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[6]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[7]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[10]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[11]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[14]); rc_tmp.MoveToX(rc_tmp.right); dc.FillSolidRect(rc_tmp, m_colors[15]); break; default: dc.FillSolidRect(rect, RGB(255, 255, 255)); rc_tmp.right = rect.Width() / color_num; for (int i{}; i < color_num; i++) { rc_tmp.MoveToX(i*(rect.Width() / color_num)); dc.FillSolidRect(rc_tmp, m_colors[i]); } } //画边框 draw.DrawRectOutLine(rect, RGB(160, 160, 160)); } else { CBrush brush(HS_BDIAGONAL, RGB(160, 160, 160)); dc.FillRect(rect, &brush); draw.DrawRectOutLine(rect, RGB(192, 192, 192)); } } void CColorStatic::OnMouseHover(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_hover = true; CStatic::OnMouseHover(nFlags, point); } void CColorStatic::OnMouseLeave() { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_hover = false; CStatic::OnMouseLeave(); } BOOL CColorStatic::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if(m_link_cursor && m_hover) { ::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(32649))); return TRUE; } return CStatic::OnSetCursor(pWnd, nHitTest, message); } void CColorStatic::PreSubclassWindow() { // TODO: 在此添加专用代码和/或调用基类 DWORD dwStyle = GetStyle(); ::SetWindowLong(GetSafeHwnd(), GWL_STYLE, dwStyle | SS_NOTIFY); ModifyStyleEx(WS_EX_STATICEDGE, NULL); CStatic::PreSubclassWindow(); } void CColorStatic::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (m_link_cursor) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.hwndTrack = m_hWnd; tme.dwFlags = TME_LEAVE | TME_HOVER; tme.dwHoverTime = 1; _TrackMouseEvent(&tme); } CStatic::OnMouseMove(nFlags, point); } void CColorStatic::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //如果单击了鼠标左键,则向父窗口发送一个WM_STATIC_CLICKED消息 CWnd* pParent{ GetParent() }; if (pParent != nullptr) pParent->SendMessage(WM_STATIC_CLICKED, (WPARAM)this); CStatic::OnLButtonUp(nFlags, point); } ================================================ FILE: TrafficMonitor/ColorStatic.h ================================================ // CColorStatic //派生自CStatic,用于显示颜色的Static控件 #pragma once #define WM_STATIC_CLICKED (WM_USER + 1001) class CColorStatic : public CStatic { DECLARE_DYNAMIC(CColorStatic) public: CColorStatic(); virtual ~CColorStatic(); void SetFillColor(COLORREF fill_color); //设置要填充单一的背景色 void SetColorNum(int color_num); //设置颜色的数量 void SetFillColor(int index, COLORREF fill_color); void SetLinkCursor(bool link_cursor = true); //设置指向控件时光标变成超链接形状 void EnableWindow(bool enable); protected: //COLORREF m_fill_color{ RGB(255, 255,255) }; vector m_colors; bool m_hover{ false }; //当鼠标指向控件时为true bool m_link_cursor{ false }; //是否启用超链接形状的光标 protected: DECLARE_MESSAGE_MAP() public: afx_msg void OnPaint(); afx_msg void OnMouseHover(UINT nFlags, CPoint point); afx_msg void OnMouseLeave(); afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); virtual void PreSubclassWindow(); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); }; ================================================ FILE: TrafficMonitor/ComboBox2.cpp ================================================ // ComboBox2.cpp: 实现文件 // #include "stdafx.h" #include "ComboBox2.h" // CComboBox2 IMPLEMENT_DYNAMIC(CComboBox2, CComboBox) CComboBox2::CComboBox2() { } CComboBox2::~CComboBox2() { } void CComboBox2::SetMouseWheelEnable(bool enable) { m_mouse_wheel_enable = enable; } BEGIN_MESSAGE_MAP(CComboBox2, CComboBox) END_MESSAGE_MAP() // CComboBox2 消息处理程序 BOOL CComboBox2::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 //如果m_mouse_wheel_enable为false,则不响应鼠标滚轮消息 if (pMsg->message == WM_MOUSEWHEEL && !m_mouse_wheel_enable) { //将鼠标滚轮消息发送给父窗口 CWnd* pParent = GetParent(); pParent->SendMessage(WM_MOUSEWHEEL, pMsg->wParam, pMsg->lParam); return true; } return CComboBox::PreTranslateMessage(pMsg); } ================================================ FILE: TrafficMonitor/ComboBox2.h ================================================ #pragma once // CComboBox2 class CComboBox2 : public CComboBox { DECLARE_DYNAMIC(CComboBox2) public: CComboBox2(); virtual ~CComboBox2(); void SetMouseWheelEnable(bool enable); //设置是否允许响应鼠标滚轮 private: bool m_mouse_wheel_enable{ true }; protected: DECLARE_MESSAGE_MAP() public: virtual BOOL PreTranslateMessage(MSG* pMsg); }; ================================================ FILE: TrafficMonitor/Common.cpp ================================================ #include "stdafx.h" #include "Common.h" #include "TrafficMonitor.h" CCommon::CCommon() { } CCommon::~CCommon() { } wstring CCommon::StrToUnicode(const char* str, bool utf8) { wstring result; int size; size = MultiByteToWideChar((utf8 ? CP_UTF8 : CP_ACP), 0, str, -1, NULL, 0); if (size <= 0) return wstring(); wchar_t* str_unicode = new wchar_t[size + 1]; MultiByteToWideChar((utf8 ? CP_UTF8 : CP_ACP), 0, str, -1, str_unicode, size); result.assign(str_unicode); delete[] str_unicode; return result; } string CCommon::UnicodeToStr(const wchar_t* wstr, bool utf8) { string result; int size{ 0 }; size = WideCharToMultiByte((utf8 ? CP_UTF8 : CP_ACP), 0, wstr, -1, NULL, 0, NULL, NULL); if (size <= 0) return string(); char* str = new char[size + 1]; WideCharToMultiByte((utf8 ? CP_UTF8 : CP_ACP), 0, wstr, -1, str, size, NULL, NULL); result.assign(str); delete[] str; return result; } bool CCommon::GetFileContent(const wchar_t* file_path, string& contents_buff, bool binary /*= true*/) { std::ifstream file{ file_path, (binary ? std::ios::binary : std::ios::in) }; if (file.fail()) return false; //获取文件长度 file.seekg(0, file.end); size_t length = file.tellg(); file.seekg(0, file.beg); char* buff = new char[length]; file.read(buff, length); file.close(); contents_buff.assign(buff, length); delete[] buff; return true; } const char* CCommon::GetFileContent(const wchar_t* file_path, size_t& length, bool binary /*= true*/) { std::ifstream file{ file_path, (binary ? std::ios::binary : std::ios::in) }; length = 0; if (file.fail()) return nullptr; //获取文件长度 file.seekg(0, file.end); length = file.tellg(); file.seekg(0, file.beg); char* buff = new char[length]; file.read(buff, length); file.close(); return buff; } CString CCommon::DataSizeToString(unsigned long long size, const PublicSettingData& cfg) { //CString str; CString value_str, unit_str; if (!cfg.unit_byte) //如果使用比特(bit)为单位,则数值乘以8 { size *= 8; } switch (cfg.speed_unit) { case SpeedUnit::AUTO: if (cfg.speed_short_mode) { if (size < 1024 * 10) //10KB以下以KB为单位,保留1位小数 { value_str.Format(_T("%.1f"), size / 1024.0f); unit_str = _T("K"); } else if (size < 1024 * 1000) //1000KB以下以KB为单位,保留整数 { value_str.Format(_T("%.0f"), size / 1024.0f); unit_str = _T("K"); } else if (size < 1024 * 1024 * 1000) //1000MB以下以MB为单位,保留1位小数 { value_str.Format(_T("%.1f"), size / 1024.0f / 1024.0f); unit_str = _T("M"); } else { value_str.Format(_T("%.2f"), size / 1024.0f / 1024.0f / 1024.0f); unit_str = _T("G"); } } else { if (size < 1024 * 10) //10KB以下以KB为单位,保留2位小数 { value_str.Format(_T("%.2f"), size / 1024.0f); unit_str = _T("KB"); } else if (size < 1024 * 1000) //1000KB以下以KB为单位,保留1位小数 { value_str.Format(_T("%.1f"), size / 1024.0f); unit_str = _T("KB"); } else if (size < 1024 * 1024 * 1000) //1000MB以下以MB为单位,保留2位小数 { value_str.Format(_T("%.2f"), size / 1024.0f / 1024.0f); unit_str = _T("MB"); } else { value_str.Format(_T("%.2f"), size / 1024.0f / 1024.0f / 1024.0f); unit_str = _T("GB"); } } break; case SpeedUnit::KBPS: if (cfg.speed_short_mode) { if (size < 1024 * 10) //10KB以下保留1位小数 value_str.Format(_T("%.1f"), size / 1024.0f); else //10KB以上保留整数 value_str.Format(_T("%.0f"), size / 1024.0f); if (!cfg.hide_unit) unit_str = _T("K"); } else { if (size < 1024 * 10) //10KB以下保留2位小数 value_str.Format(_T("%.2f"), size / 1024.0f); else //10KB以上保留1位小数 value_str.Format(_T("%.1f"), size / 1024.0f); if (!cfg.hide_unit) unit_str = _T("KB"); } break; case SpeedUnit::MBPS: if (cfg.speed_short_mode) { value_str.Format(_T("%.1f"), size / 1024.0f / 1024.0f); if (!cfg.hide_unit) unit_str = _T("M"); } else { value_str.Format(_T("%.2f"), size / 1024.0f / 1024.0f); if (!cfg.hide_unit) unit_str = _T("MB"); } break; } CString str; if (cfg.separate_value_unit_with_space && !cfg.hide_unit) str = value_str + _T(' ') + unit_str; else str = value_str + unit_str; if (!cfg.unit_byte) { if (cfg.speed_short_mode && !cfg.hide_unit) str += _T('b'); //如果使用比特(bit)为单位,即使设置了网速简洁模式,也将“b”显示出来 else str.Replace(_T('B'), _T('b')); //如果使用比特(bit)为单位,将B替换成b } return str; } CString CCommon::DataSizeToString(unsigned long long size, bool with_space) { CString str; if (size < 1024 * 10) //10KB以下以KB为单位,保留2位小数 str.Format(_T("%.2f KB"), size / 1024.0); else if (size < 1024 * 1024) //1MB以下以KB为单位,保留1位小数 str.Format(_T("%.1f KB"), size / 1024.0); else if (size < 1024 * 1024 * 1024) //1GB以下以MB为单位,保留2位小数 str.Format(_T("%.2f MB"), size / 1024.0 / 1024.0); else if (size < 1024ll * 1024 * 1024 * 1024) str.Format(_T("%.2f GB"), size / 1024.0 / 1024.0 / 1024.0); else str.Format(_T("%.2f TB"), size / 1024.0 / 1024.0 / 1024.0 / 1024.0); if (!with_space) str.Remove(_T(' ')); return str; } CString CCommon::TemperatureToString(float temperature, const PublicSettingData& cfg) { CString str_val; if (temperature <= 0) str_val = _T("--"); else str_val.Format(_T("%d"), static_cast(temperature)); if (cfg.separate_value_unit_with_space) str_val += _T(' '); str_val += _T("°C"); return str_val; } CString CCommon::UsageToString(int usage, const PublicSettingData& cfg) { CString str_val; if (usage < 0) str_val = _T("--"); else str_val.Format(_T("%d"), usage); if (!cfg.hide_percent) { if (cfg.separate_value_unit_with_space) str_val += _T(' '); str_val += _T('%'); } return str_val; } CString CCommon::FreqToString(float freq, const PublicSettingData& cfg) { CString str_val; if (freq < 0) str_val = _T("--"); else str_val.Format(_T("%.2f GHz"), freq); return str_val; } //CString CCommon::KBytesToString(unsigned int kb_size) //{ // CString k_bytes_str; // if (kb_size < 1024) // k_bytes_str.Format(_T("%d KB"), kb_size); // else if (kb_size < 1024 * 1024) // k_bytes_str.Format(_T("%.2f MB"), kb_size / 1024.0); // else if (kb_size < 1024 * 1024 * 1024) // k_bytes_str.Format(_T("%.2f GB"), kb_size / 1024.0 / 1024.0); // else // k_bytes_str.Format(_T("%.2f TB"), kb_size / 1024.0 / 1024.0 / 1024.0); // return k_bytes_str; //} CString CCommon::KBytesToString(unsigned __int64 kb_size) { CString k_bytes_str; if (kb_size < 1024) k_bytes_str.Format(_T("%d KB"), kb_size); else if (kb_size < 1024 * 1024) k_bytes_str.Format(_T("%.2f MB"), kb_size / 1024.0); else if (kb_size < 1024 * 1024 * 1024) k_bytes_str.Format(_T("%.2f GB"), kb_size / 1024.0 / 1024.0); else k_bytes_str.Format(_T("%.2f TB"), kb_size / 1024.0 / 1024.0 / 1024.0); return k_bytes_str; } __int64 CCommon::CompareFileTime2(FILETIME time1, FILETIME time2) { __int64 a = static_cast<__int64>(time1.dwHighDateTime) << 32 | time1.dwLowDateTime; __int64 b = static_cast<__int64>(time2.dwHighDateTime) << 32 | time2.dwLowDateTime; return b - a; } void CCommon::WriteLog(const char* str_text, LPCTSTR file_path) { SYSTEMTIME cur_time; GetLocalTime(&cur_time); char buff[32]; sprintf_s(buff, "%d/%.2d/%.2d %.2d:%.2d:%.2d.%.3d: ", cur_time.wYear, cur_time.wMonth, cur_time.wDay, cur_time.wHour, cur_time.wMinute, cur_time.wSecond, cur_time.wMilliseconds); ofstream file{ file_path, std::ios::app }; //以追加的方式打开日志文件 file << buff; file << str_text << std::endl; } void CCommon::WriteLog(const wchar_t* str_text, LPCTSTR file_path) { SYSTEMTIME cur_time; GetLocalTime(&cur_time); char buff[32]; sprintf_s(buff, "%d/%.2d/%.2d %.2d:%.2d:%.2d.%.3d: ", cur_time.wYear, cur_time.wMonth, cur_time.wDay, cur_time.wHour, cur_time.wMinute, cur_time.wSecond, cur_time.wMilliseconds); ofstream file{ file_path, std::ios::app }; //以追加的方式打开日志文件 file << buff; file << UnicodeToStr(str_text).c_str() << std::endl; } BOOL CCommon::CreateFileShortcut(LPCTSTR lpszLnkFileDir, LPCTSTR lpszFileName, LPCTSTR lpszLnkFileName, LPCTSTR lpszWorkDir, WORD wHotkey, LPCTSTR lpszDescription, int iShowCmd) { if (lpszLnkFileDir == NULL) return FALSE; HRESULT hr; IShellLink* pLink; //IShellLink对象指针 IPersistFile* ppf; //IPersisFil对象指针 //创建IShellLink对象 hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pLink); if (FAILED(hr)) return FALSE; //从IShellLink对象中获取IPersistFile接口 hr = pLink->QueryInterface(IID_IPersistFile, (void**)&ppf); if (FAILED(hr)) { pLink->Release(); return FALSE; } TCHAR file_path[MAX_PATH]; GetModuleFileName(NULL, file_path, MAX_PATH); //目标 if (lpszFileName == NULL) pLink->SetPath(file_path); else pLink->SetPath(lpszFileName); //工作目录 if (lpszWorkDir != NULL) { pLink->SetWorkingDirectory(lpszWorkDir); } else { //设置工作目录为快捷方式目标所在位置 TCHAR workDirBuf[MAX_PATH]{}; if (lpszFileName == NULL) //wcscpy_s(workDirBuf, file_path); WStringCopy(workDirBuf, 260, file_path, 260); else //wcscpy_s(workDirBuf, lpszFileName); WStringCopy(workDirBuf, 260, lpszFileName); LPTSTR pstr = wcsrchr(workDirBuf, _T('\\')); *pstr = _T('\0'); pLink->SetWorkingDirectory(workDirBuf); } //快捷键 if (wHotkey != 0) pLink->SetHotkey(wHotkey); //备注 if (lpszDescription != NULL) pLink->SetDescription(lpszDescription); //显示方式 pLink->SetShowCmd(iShowCmd); //快捷方式的路径 + 名称 wchar_t szBuffer[MAX_PATH]; if (lpszLnkFileName != NULL) //指定了快捷方式的名称 swprintf_s(szBuffer, L"%s\\%s", lpszLnkFileDir, lpszLnkFileName); else { //没有指定名称,就从取指定文件的文件名作为快捷方式名称。 const wchar_t* pstr; if (lpszFileName != NULL) pstr = wcsrchr(lpszFileName, L'\\'); else pstr = wcsrchr(file_path, L'\\'); if (pstr == NULL) { ppf->Release(); pLink->Release(); return FALSE; } //注意后缀名要从.exe改为.lnk swprintf_s(szBuffer, L"%s\\%s", lpszLnkFileDir, pstr); int nLen = wcslen(szBuffer); szBuffer[nLen - 3] = L'l'; szBuffer[nLen - 2] = L'n'; szBuffer[nLen - 1] = L'k'; } //保存快捷方式到指定目录下 //WCHAR wsz[MAX_PATH]; //定义Unicode字符串 //MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, wsz, MAX_PATH); hr = ppf->Save(szBuffer, TRUE); ppf->Release(); pLink->Release(); return SUCCEEDED(hr); } wstring CCommon::GetStartUpPath() { LPITEMIDLIST ppidl; TCHAR pszStartUpPath[MAX_PATH]{}; if (SHGetSpecialFolderLocation(NULL, CSIDL_STARTUP, &ppidl) == S_OK) { SHGetPathFromIDList(ppidl, pszStartUpPath); CoTaskMemFree(ppidl); } return wstring(pszStartUpPath); } void CCommon::GetFiles(const wchar_t* path, vector& files) { //文件句柄 intptr_t hFile = 0; //文件信息(用Unicode保存使用_wfinddata_t,多字节字符集使用_finddata_t) _wfinddata_t fileinfo; wstring file_name; if ((hFile = _wfindfirst(path, &fileinfo)) != -1) { do { file_name.assign(fileinfo.name); if (file_name != L"." && file_name != L"..") //files.push_back(wstring(path) + L"\\" + file_name); //将文件名保存(忽略"."和"..") files.push_back(L"\\" + file_name); //将文件名保存(忽略"."和"..") } while (_wfindnext(hFile, &fileinfo) == 0); } _findclose(hFile); } void CCommon::GetFiles(const wchar_t* path, std::function func) { //文件句柄 intptr_t hFile = 0; _wfinddata_t fileinfo; wstring file_name; if ((hFile = _wfindfirst(path, &fileinfo)) != -1) { do { file_name.assign(fileinfo.name); if (file_name != L"." && file_name != L"..") func(file_name); } while (_wfindnext(hFile, &fileinfo) == 0); } _findclose(hFile); } bool CCommon::FileExist(LPCTSTR file_name) { return (PathFileExists(file_name) != 0); } bool CCommon::IsFolder(const wstring& path) { DWORD dwAttrib = GetFileAttributes(path.c_str()); return (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0; } bool CCommon::MoveAFile(LPCTSTR exist_file, LPCTSTR new_file) { if (!FileExist(exist_file)) return false; //if (FileExist(new_file)) //如果目标文件已经存在,则先删除它 // DeleteFile(new_file); return (MoveFile(exist_file, new_file) != 0); } SYSTEMTIME CCommon::CompareSystemTime(SYSTEMTIME a, SYSTEMTIME b) { SYSTEMTIME result{}; short hour = a.wHour - b.wHour; short minute = a.wMinute - b.wMinute; short second = a.wSecond - b.wSecond; if (second < 0) { second += 60; minute--; } if (minute < 0) { minute += 60; hour--; } if (hour < 0) { hour += 24; } result.wHour = hour; result.wMinute = minute; result.wSecond = second; return result; } wstring CCommon::GetModuleDir() { wchar_t path[MAX_PATH]; GetModuleFileNameW(NULL, path, MAX_PATH); size_t index; wstring current_path{ path }; index = current_path.find_last_of(L'\\'); current_path = current_path.substr(0, index + 1); return current_path; } wstring CCommon::GetSystemDir() { wchar_t buff[MAX_PATH]; GetSystemDirectory(buff, MAX_PATH); return wstring(buff); } wstring CCommon::GetTemplateDir() { wstring result; wchar_t buff[MAX_PATH]; GetTempPath(MAX_PATH, buff); //获取临时文件夹的路径 result = buff; if (result.back() != L'\\' && result.back() != L'/') //确保路径后面有斜杠 result.push_back(L'\\'); return result; } wstring CCommon::GetAppDataConfigDir() { LPITEMIDLIST ppidl; TCHAR pszAppDataPath[MAX_PATH]; if (SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &ppidl) == S_OK) { SHGetPathFromIDList(ppidl, pszAppDataPath); CoTaskMemFree(ppidl); } wstring app_data_path{ pszAppDataPath }; //获取到C:/User/用户名/AppData/Roaming路径 CreateDirectory(app_data_path.c_str(), NULL); //如果Roaming不存在,则创建它 app_data_path += L"\\TrafficMonitor\\"; CreateDirectory(app_data_path.c_str(), NULL); //如果C:/User/用户名/AppData/Roaming/TrafficMonitor不存在,则创建它 return app_data_path; } void CCommon::DrawWindowText(CDC* pDC, CRect rect, LPCTSTR lpszString, COLORREF color, COLORREF back_color) { pDC->SetTextColor(color); //m_pDC->SetBkMode(TRANSPARENT); //用背景色填充矩形区域 pDC->FillSolidRect(rect, back_color); pDC->DrawText(lpszString, rect, DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); } //void CCommon::SetDrawArea(CDC * pDC, CRect rect) //{ // CRgn rgn; // rgn.CreateRectRgnIndirect(rect); // pDC->SelectClipRgn(&rgn); //} bool CCommon::IsForegroundFullscreen() { bool bFullscreen{ false }; //用于指示前台窗口是否是全屏 HWND hWnd; RECT rcApp; RECT rcDesk; hWnd = GetForegroundWindow(); //获取当前正在与用户交互的前台窗口句柄 TCHAR buff[256]; GetClassName(hWnd, buff, 256); //获取前台窗口的类名 CString class_name{ buff }; if (hWnd != GetDesktopWindow() && class_name != _T("WorkerW") && hWnd != GetShellWindow())//如果前台窗口不是桌面窗口,也不是控制台窗口 { GetWindowRect(hWnd, &rcApp); //获取前台窗口的坐标 GetWindowRect(GetDesktopWindow(), &rcDesk); //根据桌面窗口句柄,获取整个屏幕的坐标 if (rcApp.left <= rcDesk.left && //如果前台窗口的坐标完全覆盖住桌面窗口,就表示前台窗口是全屏的 rcApp.top <= rcDesk.top && rcApp.right >= rcDesk.right && rcApp.bottom >= rcDesk.bottom) { bFullscreen = true; } }//如果前台窗口是桌面窗口,或者是控制台窗口,就直接返回不是全屏 return bFullscreen; } bool CCommon::CopyStringToClipboard(const wstring& str) { if (OpenClipboard(NULL)) { HGLOBAL clipbuffer; EmptyClipboard(); size_t size = (str.size() + 1) * 2; clipbuffer = GlobalAlloc(GMEM_DDESHARE, size); memcpy_s(GlobalLock(clipbuffer), size, str.c_str(), size); GlobalUnlock(clipbuffer); if (SetClipboardData(CF_UNICODETEXT, clipbuffer) == NULL) return false; CloseClipboard(); return true; } else return false; } wstring CCommon::GetJsonValueSimple(const wstring& json_str, const wstring& name) { wstring str_name{ L"\"" }; str_name += name; str_name += L'\"'; size_t index = json_str.find(str_name); if (index == wstring::npos) return wstring(); index = json_str.find(L':', index + 1); if (index == wstring::npos) return wstring(); index = json_str.find_first_not_of(L"\" ", index + 1); size_t index_end = json_str.find_first_of(L"\",]}\r\n", index); wstring result = json_str.substr(index, index_end - index); return result; } bool CCommon::GetURL(const wstring& url, wstring& result, bool utf8, const wstring& user_agent) { bool succeed{ false }; CInternetSession* pSession{}; CHttpFile* pfile{}; try { pSession = new CInternetSession(user_agent.c_str()); pfile = (CHttpFile*)pSession->OpenURL(url.c_str()); DWORD dwStatusCode; pfile->QueryInfoStatusCode(dwStatusCode); if (dwStatusCode == HTTP_STATUS_OK) { CString content; CString data; while (pfile->ReadString(data)) { content += data; } result = StrToUnicode((const char*)content.GetString(), utf8); succeed = true; } pfile->Close(); delete pfile; pSession->Close(); } catch (CInternetException* e) { //写入错误日志 if (theApp.m_debug_log) { CString info = CCommon::LoadTextFormat(IDS_GET_URL_ERROR_LOG_INFO, { url, static_cast(e->m_dwError) }); CCommon::WriteLog(info, theApp.m_log_path.c_str()); } if (pfile != nullptr) { pfile->Close(); delete pfile; } if (pSession != nullptr) pSession->Close(); succeed = false; e->Delete(); //没有这句会造成内存泄露 SAFE_DELETE(pSession); } SAFE_DELETE(pSession); return succeed; } void CCommon::GetInternetIp(wstring& ip_address, wstring& ip_location, bool global) { wstring web_page; if (GetURL(L"https://ip.cn/", web_page, true)) { #ifdef _DEBUG ofstream file{ L".\\IP_web_page.log" }; file << UnicodeToStr(web_page.c_str()) << std::endl; #endif // _DEBUG size_t index, index1; index = web_page.find(L""); index1 = web_page.find(L"", index + 6); if (index == wstring::npos || index1 == wstring::npos) ip_address.clear(); else ip_address = web_page.substr(index + 6, index1 - index - 6); //获取IP地址 if (ip_address.size() > 15 || ip_address.size() < 7) //IP地址最长15个字符,最短7个字符 ip_address.clear(); //获取IP地址归属地 if (!global) { index = web_page.find(L"", index1 + 7); index1 = web_page.find(L"", index + 6); if (index == wstring::npos || index1 == wstring::npos) ip_location.clear(); else ip_location = web_page.substr(index + 6, index1 - index - 6); } else { index = web_page.find(L"GeoIP", index1 + 7); index1 = web_page.find(L"

", index + 6); if (index == wstring::npos || index1 == wstring::npos) ip_location.clear(); else ip_location = web_page.substr(index + 7, index1 - index - 7); } } else { ip_address.clear(); } } void CCommon::GetInternetIp2(wstring& ip_address, wstring& ip_location, bool ipv6) { wstring raw_string; wstring user_agent{ L"TrafficMonitor/" }; user_agent += VERSION; if (GetURL((ipv6 ? L"https://v6.yinghualuo.cn/bejson" : L"https://v4.yinghualuo.cn/bejson"), raw_string, true, user_agent)) { //解析获取的json字符串 ip_address = GetJsonValueSimple(raw_string, L"ip"); ip_location = GetJsonValueSimple(raw_string, L"location"); } else { ip_address.clear(); ip_location.clear(); } } void CCommon::SetRect(CRect& rect, int x, int y, int width, int height) { rect.left = x; rect.top = y; rect.right = x + width; rect.bottom = y + height; } CString CCommon::LoadText(UINT id, LPCTSTR back_str) { CString str; str.LoadString(id); if (back_str != nullptr) str += back_str; return str; } CString CCommon::LoadText(LPCTSTR front_str, UINT id, LPCTSTR back_str) { CString str; str.LoadString(id); if (back_str != nullptr) str += back_str; if (front_str != nullptr) str = front_str + str; return str; } CString CCommon::StringFormat(LPCTSTR format_str, const std::initializer_list& paras) { CString str_rtn = format_str; int index = 1; for (const auto& para : paras) { CString para_str = para.ToString(); CString format_para; format_para.Format(_T("<%%%d%%>"), index); str_rtn.Replace(format_para, para_str); index++; } return str_rtn; } CString CCommon::LoadTextFormat(UINT id, const std::initializer_list& paras) { CString str; str.LoadString(id); return StringFormat(str.GetString(), paras); } CString CCommon::IntToString(__int64 n, bool thousand_separation, bool is_unsigned) { wstring str = std::to_wstring(is_unsigned ? static_cast(n) : n); int count{}; if (thousand_separation) { int length{ static_cast(str.size()) }; for (int i{ length - 1 }; i > 0; i--) { count++; if (count % 3 == 0) str.insert(i, L","); } } return str.c_str(); } void CCommon::NormalizeFont(LOGFONT& font) { wstring name; wstring style; name = font.lfFaceName; if (name.empty()) return; if (name.back() == L' ') name.pop_back(); size_t index = name.rfind(L' '); if (index == wstring::npos) return; style = name.substr(index + 1); bool style_acquired = false; if (style == L"Light") { font.lfWeight = FW_LIGHT; style_acquired = true; } else if (style == L"Semilight") { font.lfWeight = 350; style_acquired = true; } else if (style == L"Semibold") { font.lfWeight = FW_SEMIBOLD; style_acquired = true; } else if (style == L"Bold") { font.lfWeight = FW_BOLD; style_acquired = true; } else if (style == L"Black") { font.lfWeight = FW_BLACK; style_acquired = true; } if (style_acquired) { name = name.substr(0, index); } //wcsncpy_s(font.lfFaceName, name.c_str(), 32); WStringCopy(font.lfFaceName, 32, name.c_str(), name.size()); } void CCommon::WStringCopy(wchar_t* str_dest, int dest_size, const wchar_t* str_source, int source_size) { if (dest_size <= 0) return; if (source_size <= 0 || str_source == nullptr) { str_dest[0] = L'\0'; return; } int i; for (i = 0; i < dest_size && i < source_size && str_source[i] != L'\0'; i++) str_dest[i] = str_source[i]; //确保目标字符串末尾有一个\0 int copy_cnt = i; if (copy_cnt < dest_size) str_dest[copy_cnt] = L'\0'; else str_dest[dest_size - 1] = L'\0'; } void CCommon::SetThreadLanguage(Language language) { switch (language) { case Language::ENGLISH: SetThreadUILanguage(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); break; case Language::SIMPLIFIED_CHINESE: SetThreadUILanguage(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)); break; case Language::TRADITIONAL_CHINESE: SetThreadUILanguage(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)); break; default: break; } } void CCommon::SetColorMode(ColorMode mode) { switch (mode) { case ColorMode::Default: CTrafficMonitorApp::self->m_taskbar_data.dft_back_color = 0; CTrafficMonitorApp::self->m_taskbar_data.dft_transparent_color = 0; CTrafficMonitorApp::self->m_taskbar_data.dft_status_bar_color = 0x005A5A5A; CTrafficMonitorApp::self->m_taskbar_data.dft_text_colors = 0x00ffffffU; CTrafficMonitorApp::self->m_cfg_data.m_dft_notify_icon = 0; break; case ColorMode::Light: CTrafficMonitorApp::self->m_taskbar_data.dft_back_color = 0x00D3D2D2; CTrafficMonitorApp::self->m_taskbar_data.dft_transparent_color = 0x00D3D2D2; CTrafficMonitorApp::self->m_taskbar_data.dft_status_bar_color = 0x00A5A5A5; CTrafficMonitorApp::self->m_taskbar_data.dft_text_colors = 0x00000000U; CTrafficMonitorApp::self->m_cfg_data.m_dft_notify_icon = 4; break; default: break; } } void CCommon::TransparentColorConvert(COLORREF& transparent_color) { if (transparent_color == 0) return; BYTE r = GetRValue(transparent_color); BYTE g = GetGValue(transparent_color); BYTE b = GetBValue(transparent_color); if (r == b) { if (b >= 255) b--; else b++; transparent_color = RGB(r, g, b); } } void CCommon::SetDialogFont(CWnd* pDlg, CFont* pFont) { if (pDlg->GetSafeHwnd() != NULL) { CWnd* pWndChild; pWndChild = pDlg->GetWindow(GW_CHILD); while (pWndChild) { pWndChild->SetFont(pFont); pWndChild = pWndChild->GetWindow(GW_HWNDNEXT); } } } CString CCommon::GetTextResource(UINT id, int code_type) { CString res_str; HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(id), _T("TEXT")); if (hRes != NULL) { HGLOBAL hglobal = LoadResource(NULL, hRes); if (hglobal != NULL) { if (code_type == 2) { res_str = (const wchar_t*)hglobal; } else { res_str = CCommon::StrToUnicode((const char*)hglobal, (code_type != 0)).c_str(); } } } return res_str; } CString CCommon::GetLastCompileTime() { CString str_compile_time = GetTextResource(IDR_COMPILE_TIME, 0); str_compile_time.Replace(_T("\r\n"), _T("")); str_compile_time.Delete(str_compile_time.GetLength() - 1, 1); return str_compile_time; } HICON CCommon::LoadIconResource(UINT id, int size) { return (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), IMAGE_ICON, size, size, 0); } int CCommon::GetMenuItemPosition(CMenu* pMenu, UINT id) { int pos = -1; int item_count = pMenu->GetMenuItemCount(); for (int i = 0; i < item_count; i++) { if (pMenu->GetMenuItemID(i) == id) { pos = i; break; } } return pos; } bool CCommon::IsColorSimilar(COLORREF color1, COLORREF color2) { const int DIFF{ 24 }; return (std::abs(GetRValue(color1) - GetRValue(color2)) < DIFF && std::abs(GetGValue(color1) - GetGValue(color2)) < DIFF && std::abs(GetBValue(color1) - GetBValue(color2)) < DIFF); } int CCommon::CountOneBits(unsigned int value) { int count = 0; while (value != 0) { if (value % 2 == 1) { count++; } value = value >> 1; } return count; } void CCommon::SetNumberBit(unsigned int& num, int bit, bool value) { if (value) { num |= (1 << bit); } else { num &= ~(1 << bit); } } bool CCommon::GetNumberBit(unsigned int num, int bit) { return (num & (1 << bit)) != 0; } ================================================ FILE: TrafficMonitor/Common.h ================================================ #pragma once #include "CommonData.h" #include "CVariant.h" #include #include class CCommon { public: CCommon(); ~CCommon(); //将const char*字符串转换成宽字符字符串 static wstring StrToUnicode(const char* str, bool utf8 = false); static string UnicodeToStr(const wchar_t* wstr, bool utf8 = false); template static void StringNormalize(T& str) { if (str.empty()) return; int size = str.size(); //字符串的长度 if (size < 0) return; int index1 = 0; //字符串中第1个不是空格或控制字符的位置 int index2 = size - 1; //字符串中最后一个不是空格或控制字符的位置 while (index1 < size && str[index1] >= 0 && str[index1] <= 32) index1++; while (index2 >= 0 && str[index2] >= 0 && str[index2] <= 32) index2--; if (index1 > index2) //如果index1 > index2,说明字符串全是空格或控制字符 str.clear(); else if (index1 == 0 && index2 == size - 1) //如果index1和index2的值分别为0和size - 1,说明字符串前后没有空格或控制字符,直接返回 return; else str = str.substr(index1, index2 - index1 + 1); } //将一个字符串分割成若干个字符(模板类型只能为string或wstring) //str: 原始字符串 //div_ch: 用于分割的字符 //result: 接收分割后的结果 template static void StringSplit(const T& str, wchar_t div_ch, vector& results, bool skip_empty = true, bool trim = true) { results.clear(); size_t split_index = -1; size_t last_split_index = -1; while (true) { split_index = str.find(div_ch, split_index + 1); T split_str = str.substr(last_split_index + 1, split_index - last_split_index - 1); if (trim) StringNormalize(split_str); if (!split_str.empty() || !skip_empty) results.push_back(split_str); if (split_index == wstring::npos) break; last_split_index = split_index; } } template static void StringSplit(const T& str, const T& div_str, vector& results, bool skip_empty = true, bool trim = true) { results.clear(); size_t split_index = 0 - div_str.size(); size_t last_split_index = 0 - div_str.size(); while (true) { split_index = str.find(div_str, split_index + div_str.size()); T split_str = str.substr(last_split_index + div_str.size(), split_index - last_split_index - div_str.size()); if (trim) StringNormalize(split_str); if (!split_str.empty() || !skip_empty) results.push_back(split_str); if (split_index == wstring::npos) break; last_split_index = split_index; } } template static bool StringTransform(T& str, bool upper) { if (str.empty()) return false; if (upper) { for (auto& ch : str) { { if (ch >= 'a' && ch <= 'z') ch -= 32; } } } else { for (auto& ch : str) { if (ch >= 'A' && ch <= 'Z') ch += 32; } } return true; } //读取文件内容 static bool GetFileContent(const wchar_t* file_path, string& contents_buff, bool binary = true); //读取文件内容 //file_path: 文件的路径 //length: 文件的长度 //binary: 是否以进制方式读取 //返回值: 读取成功返回读取到的文件内容的const char类型的指针,在使用完毕后这个指针需要自行使用delete释放。读取失败返回nullptr static const char* GetFileContent(const wchar_t* file_path, size_t& length, bool binary = true); /*根据数据的大小转换成以KB、MB、GB为单位的字符串 size:数据的字节数 返回值:转换后的字符串 */ static CString DataSizeToString(unsigned long long size, const PublicSettingData& cfg); /*根据数据的大小转换成以KB、MB、GB为单位的字符串 size:数据的字节数 with_space:数值和单位是否使用空格分隔 返回值:转换后的字符串 */ static CString DataSizeToString(unsigned long long size, bool with_space = true); //将温度信息转换成字符串 static CString TemperatureToString(float temperature, const PublicSettingData& cfg); //将使用率转换成字符串 static CString UsageToString(int usage, const PublicSettingData& cfg); static CString FreqToString(float usage, const PublicSettingData& cfg); //static CString KBytesToString(unsigned int kb_size); static CString KBytesToString(unsigned __int64 kb_size); //返回两个FILETIME结构的时间差 static __int64 CompareFileTime2(FILETIME time1, FILETIME time2); //将一个日志信息str_text写入到file_path文件中 static void WriteLog(const char* str_text, LPCTSTR file_path); static void WriteLog(const wchar_t* str_text, LPCTSTR file_path); /* 函数功能:对指定文件在指定的目录下创建其快捷方式 函数参数: lpszLnkFileDir 指定目录,不能为NULL。 lpszFileName 指定文件,为NULL表示当前进程的EXE文件。 lpszLnkFileName 快捷方式名称,为NULL表示EXE文件名。 wHotkey 为0表示不设置快捷键 pszDescription 备注 iShowCmd 运行方式,默认为常规窗口 */ static BOOL CreateFileShortcut(LPCTSTR lpszLnkFileDir, LPCTSTR lpszFileName = NULL, LPCTSTR lpszLnkFileName = NULL, LPCTSTR lpszWorkDir = NULL, WORD wHotkey = 0, LPCTSTR lpszDescription = NULL, int iShowCmd = SW_SHOWNORMAL); //获取开始菜单“所有程序”中的“启动”目录的路径 static wstring GetStartUpPath(); //获取path路径下的文件或文件夹,并将文件或文件夹名称保存在files容器中。 static void GetFiles(const wchar_t* path, vector& files); //获取path路径下的文件或文件夹,每次遍历时调用函数对数func //path: 查找的路径 //func: 可以是一个函数对象或lambda表达式,参数是遍历到的文件或文件夹名 static void GetFiles(const wchar_t* path, std::function func); //判断一个文件是否存在 static bool FileExist(LPCTSTR file_name); //判断是否是文件夹 static bool IsFolder(const wstring& path); static bool MoveAFile(LPCTSTR exist_file, LPCTSTR new_file); //计算两个SYSTEMTIME结构时间的差(a-b,只保留时、分、秒) static SYSTEMTIME CompareSystemTime(SYSTEMTIME a, SYSTEMTIME b); //获取当前程序的目录 static wstring GetModuleDir(); //获取system32文件夹的路径 static wstring GetSystemDir(); //获取临时文件夹的路径 static wstring GetTemplateDir(); //获取Appdata/Local/TrafficMonitor的目录,如果不存在,则会自动创建 static wstring GetAppDataConfigDir(); //在指定位置绘制文本 static void DrawWindowText(CDC* pDC, CRect rect, LPCTSTR lpszString, COLORREF color, COLORREF back_color); ////设置绘图的剪辑区域 //static void SetDrawArea(CDC* pDC, CRect rect); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 函数名称:IsForegroundFullscreen * 功能说明:判断当前正在与用户交互的前台窗口是否是全屏的。 * 参数说明:无 * 返回说明:true:是。 false:否。 * 线程安全:是 * 调用样例:IsForegroundFullscreen (),表示判断当前正在与用户交互的前台窗口是否是全屏的。 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static bool IsForegroundFullscreen(); //将一个字符串保存到剪贴板 static bool CopyStringToClipboard(const wstring& str); static wstring GetJsonValueSimple(const wstring& json_str, const wstring& name); //获取URL的内容 static bool GetURL(const wstring& url, wstring& result, bool utf8 = false, const wstring& user_agent = wstring()); //获取外网IP地址和IP归属地 static void GetInternetIp(wstring& ip_address, wstring& ip_location, bool global); static void GetInternetIp2(wstring& ip_address, wstring& ip_location, bool ipv6); static void SetRect(CRect& rect, int x, int y, int width, int height); //从资源文件载入字符串。其中,front_str、back_str为载入字符串时需要在前面或后面添加的字符串 static CString LoadText(UINT id, LPCTSTR back_str = nullptr); static CString LoadText(LPCTSTR front_str, UINT id, LPCTSTR back_str = nullptr); //安全的格式化字符串,将format_str中形如<%序号%>的字符串替换成初始化列表paras中的元素,元素支持int/double/LPCTSTR/CString格式,序号从1开始 static CString StringFormat(LPCTSTR format_str, const std::initializer_list& paras); //从资源文件中载入字符串,并将资源字符串中形如<%序号%>的字符串替换成可变参数列表中的参数 static CString LoadTextFormat(UINT id, const std::initializer_list& paras); //将int类型转换成字符串 //n:要转换的数值 //thousand_separation:是否要每隔3位数使用逗号分隔 //is_unsigned:数值是否是无符号的 static CString IntToString(__int64 n, bool thousand_separation = false, bool is_unsigned = false); //删除字体名称后面的Bold、Light等字符串,并根据这些字符串设置字体粗细 static void NormalizeFont(LOGFONT& font); //安全的字符串复制函数 static void WStringCopy(wchar_t* str_dest, int dest_size, const wchar_t* str_source, int source_size = INT_MAX); /// /// 字符串相似度算法-编辑距离法 /// /// 返回的值为0~1,越大相似度越高 template static double StringSimilarDegree_LD(const T& srcString, const T& matchString) { int n = srcString.size(); int m = matchString.size(); //int[, ] d = new int[n + 1, m + 1]; // matrix vector> d(n + 1, vector(m + 1)); int cost; // cost // Step 1(如果其中一个字符串长度为0,则相似度为1)? //if (n == 0) return (double)m / max(srcString.size(), matchString.size()); //if (m == 0) return (double)n / max(srcString.size(), matchString.size()); if (n == 0 || m == 0) return 0.0; //如果其中一个字符串长度为0,则相似度为0 // Step 2 for (int i = 0; i <= n; d[i][0] = i++); for (int j = 0; j <= m; d[0][j] = j++); // Step 3 for (int i = 1; i <= n; i++) { //Step 4 for (int j = 1; j <= m; j++) { // Step 5 cost = (matchString.substr(j - 1, 1) == srcString.substr(i - 1, 1) ? 0 : 1); // Step 6 d[i][j] = min(min(d[i - 1][j] + 1, d[i][j - 1] + 1), d[i - 1][j - 1] + cost); } } // Step 7 double ds = 1 - (double)d[n][m] / max(srcString.size(), matchString.size()); return ds; } //设置线程语言 static void SetThreadLanguage(Language language); //设置颜色模式 static void SetColorMode(ColorMode mode); //经过测试发现,似乎当透明色的R和B值相等时,会出现右击任务栏窗口时无法弹出右键菜单,而是弹出系统任务栏右键菜单的问题 //为了解决这个问题,需要将颜色值进行转换 //此函数的作用是判断一个颜色的R和B值是否相等,如果是则将颜色的B值加1(如果B==255,则减1) static void TransparentColorConvert(COLORREF& transparent_color); static void SetDialogFont(CWnd* pDlg, CFont* pFont); //从资源加载自定义文本资源。id:资源的ID,code_type:文本的编码格式:0:ANSI, 1:UTF8, 2:UTF16 static CString GetTextResource(UINT id, int code_type); //从资源文件读取上次编译时间 static CString GetLastCompileTime(); //从资源加载一个图标 static HICON LoadIconResource(UINT id, int size); //获取一个菜单项的序号 static int GetMenuItemPosition(CMenu* pMenu, UINT id); static bool IsColorSimilar(COLORREF color1, COLORREF color2); //计算二进制中1的个数 static int CountOneBits(unsigned int value); //设置一个数字的某个bit位 static void SetNumberBit(unsigned int& num, int bit, bool value); //获取一个数字的某个bit位 static bool GetNumberBit(unsigned int num, int bit); //在不排序的情况下删除vector中的重复元素 template static void RemoveVectorDuplicateItem(vector& vec) { std::set si; for (auto it = vec.begin(); it != vec.end();) { if (si.count(*it) == 0)//这里判断当前元素是否已经出现过,若没有出现过则将该元素保留,并做标记 { si.insert(*it); ++it; } else//如果前面已经出现过,则删除当前元素 { it = vec.erase(it);//这里删除it指向的元素 } } } }; ================================================ FILE: TrafficMonitor/CommonData.cpp ================================================ #include "stdafx.h" #include "CommonData.h" #include "Common.h" #include "CalendarHelper.h" #include "TrafficMonitor.h" /////////////////////////////////////////////////////////////////////////////////// int Date::week() const { //计算当前是一年的第几天 int days{}; for (int i{ 1 }; i < month; i++) { days += CCalendarHelper::DaysInMonth(year, i); } days += day; //计算这一年的1月1日是星期几 int week_day = CCalendarHelper::CaculateWeekDay(year, 1, 1); if (theApp.m_cfg_data.m_sunday_first) { days += (week_day - 1); } else { days += (week_day - 2); } return days / 7 + 1; } bool Date::DateGreater(const Date& a, const Date& b) { if (a.year != b.year) return a.year > b.year; else if (a.month != b.month) return a.month > b.month; else if (a.day != b.day) return a.day > b.day; else return false; } bool Date::DateEqual(const Date& a, const Date& b) { return a.year == b.year && a.month == b.month && a.day == b.day; } /////////////////////////////////////////////////////////////////////////////////// //HistoryTraffic unsigned __int64 HistoryTraffic::kBytes() const { return up_kBytes + down_kBytes; } /////////////////////////////////////////////////////////////////////////////////// wstring& DispStrings::Get(CommonDisplayItem item) { return map_str[item]; } const std::map& DispStrings::GetAllItems() const { return map_str; } void DispStrings::operator=(const DispStrings& disp_str) { map_str = disp_str.map_str; //如果赋值的字符串是定义的无效字符串,则不赋值 for (auto& iter = map_str.begin(); iter != map_str.end(); ++iter) { if (iter->second == NONE_STR) iter->second.clear(); } } bool DispStrings::IsInvalid() const { for (auto& iter = map_str.begin(); iter != map_str.end(); ++iter) { if (iter->second == NONE_STR) return true; } return false; } void DispStrings::Load(const std::wstring& plugin_id, const std::wstring& disp_str) { auto plugin = theApp.m_plugins.GetItemById(plugin_id); if (plugin != nullptr) { map_str[plugin] = disp_str; } } /////////////////////////////////////////////////////////////////////////////////// bool StringSet::Contains(const std::wstring& str) const { return string_set.count(str) != 0; } void StringSet::SetStrContained(const std::wstring& str, bool contained) { if (contained) string_set.insert(str); else string_set.erase(str); } void StringSet::FromString(const std::wstring& str) { std::vector item_vect; CCommon::StringSplit(str, L',', item_vect); string_set.clear(); for (const auto& i : item_vect) string_set.insert(i); } std::wstring StringSet::ToString() const { std::vector item_vect; for (const auto& i : string_set) item_vect.push_back(i); std::wstring item_str; for (const auto& i : item_vect) { item_str += i; item_str += L','; } if (!item_str.empty()) item_str.pop_back(); return item_str; } void StringSet::FromVector(const std::vector& vec) { string_set.clear(); for (const auto& str : vec) string_set.insert(str); } std::vector StringSet::ToVector() const { std::vector vec; for (const auto& str : string_set) vec.push_back(str); return vec; } std::set& StringSet::data() { return string_set; } void TaskBarSettingData::ValidItemSpace() { if (item_space < 0) item_space = 0; if (item_space > 32) item_space = 32; } unsigned __int64 TaskBarSettingData::GetNetspeedFigureMaxValueInBytes() const { if (netspeed_figure_max_value_unit == 0) //单位为KB return static_cast(netspeed_figure_max_value) * 1024; else return static_cast(netspeed_figure_max_value) * 1024 * 1024; } ================================================ FILE: TrafficMonitor/CommonData.h ================================================ //此文件包含全局结构体、枚举类型的定义 #pragma once #include "stdafx.h" #include "TaskbarItemOrderHelper.h" struct Date { int year{}; int month{}; int day{}; int week() const; //该日期是一年的第几周 //比较两个HistoryTraffic对象的日期,如果a的时间大于b,则返回true static bool DateGreater(const Date& a, const Date& b); //判断两个HistoryTraffic对象的日期是否相等 static bool DateEqual(const Date& a, const Date& b); }; //储存某一天的历史流量 struct HistoryTraffic : public Date { //当天使用的流量(以KB为单位) unsigned __int64 up_kBytes{}; unsigned __int64 down_kBytes{}; bool mixed{ true }; //如果不区分上传和下载流量,则为true unsigned __int64 kBytes() const; }; //历史流量统计中用于指示不同范围内的流量的颜色 #define TRAFFIC_COLOR_BLUE RGB(0, 183, 238) #define TRAFFIC_COLOR_GREEN RGB(128, 194, 105) #define TRAFFIC_COLOR_YELLOE RGB(255, 216, 58) #define TRAFFIC_COLOR_RED RGB(255, 95, 74) #define TRAFFIC_COLOR_DARK_RED RGB(166, 19, 0) //网速单位 enum class SpeedUnit { AUTO, //自动 KBPS, //KB/s MBPS //MB/s }; //硬件监控的项目 enum HardwareItem { HI_CPU = 1 << 0, //CPU HI_GPU = 1 << 1, //显卡 HI_HDD = 1 << 2, //硬盘 HI_MBD = 1 << 3 //主板 }; #define DEF_CH L'\"' //写入和读取ini文件字符串时,在字符串前后添加的字符 #define NONE_STR L"@@@" //用于指定一个无效字符串 struct DispStrings //显示的文本 { private: std::map map_str; public: //获取一个显示的文本 wstring& Get(CommonDisplayItem item); const std::map& GetAllItems() const; void operator=(const DispStrings& disp_str); //重载赋值运算符 //载入一个插件项目的显示文本 void Load(const std::wstring& plugin_id, const std::wstring& disp_str); //是否无效 bool IsInvalid() const; }; //鼠标双击窗口的动作 enum class DoubleClickAction { CONNECTION_INFO, //连接详情 HISTORY_TRAFFIC, //历史流量统计 SHOW_MORE_INFO, //显示更多信息 OPTIONS, //选项设置 TASK_MANAGER, //任务管理器 SEPCIFIC_APP, //指定应用程序 CHANGE_SKIN, //更换皮肤 NONE //不执行任何动作 }; //语言 enum class Language { FOLLOWING_SYSTEM, //跟随系统 ENGLISH, //英语 SIMPLIFIED_CHINESE, //简体中文 TRADITIONAL_CHINESE //繁体中文 }; //颜色模式 enum class ColorMode { Default, //默认颜色 Light //浅色 }; //将字号转成LOGFONT结构中的lfHeight inline int FontSizeToLfHeight(int font_size, int dpi = 0) { if (dpi == 0) { HDC hDC = ::GetDC(HWND_DESKTOP); dpi = GetDeviceCaps(hDC, LOGPIXELSY); ::ReleaseDC(HWND_DESKTOP, hDC); } int lfHeight = -MulDiv(font_size, dpi, 72); return lfHeight; } //字体 struct FontInfo { CString name; //字体名称 int size; //字体大小 bool bold; //粗体 bool italic; //斜体 bool underline; //下划线 bool strike_out; //删除线 //创建一个CFont对象 void Create(CFont& font, int dpi = 0) { font.CreateFont( FontSizeToLfHeight(size, dpi), // nHeight 0, // nWidth 0, // nEscapement 0, // nOrientation (bold ? FW_BOLD : FW_NORMAL), // nWeight italic, // bItalic underline, // bUnderline strike_out, // cStrikeOut DEFAULT_CHARSET, // nCharSet OUT_DEFAULT_PRECIS, // nOutPrecision CLIP_DEFAULT_PRECIS, // nClipPrecision DEFAULT_QUALITY, // nQuality DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily name); } }; //历史流量统计列表视图中显示模式 enum class HistoryTrafficViewType { HV_DAY, //日视图 HV_WEEK, //周视图 HV_MONTH, //月视图 HV_QUARTER, //季视图 HV_YEAR //年视图 }; struct StringSet { public: bool Contains(const std::wstring& str) const; void SetStrContained(const std::wstring& str, bool contained); void FromString(const std::wstring& str); std::wstring ToString() const; void FromVector(const std::vector& vec); std::vector ToVector() const; std::set& data(); private: std::set string_set; }; //选项设置数据 struct MainConfigData { int m_transparency{ 100 }; //窗口透明度 bool m_show_more_info{ false }; //显示更多信息 bool m_show_task_bar_wnd{ false }; //显示任务栏窗口 bool m_hide_main_window; //隐藏主窗口 //bool m_tbar_show_cpu_memory; //任务栏窗口显示CPU和内存利用率 int m_position_x; //窗口位置的x坐标 int m_position_y; //窗口位置的y坐标 bool m_auto_select{ false }; //自动选择连接 bool m_select_all{ false }; //统计所有连接的网速 string m_connection_name; //当前选择网络的名称 wstring m_skin_name; //选择的皮肤的名称 int m_dft_notify_icon = 0; //默认的通知图标(用于区分win10的深色和浅色模式) int m_notify_icon_selected{}; //要显示的通知区图标 bool m_notify_icon_auto_adapt{ false }; //通知区图标是否自动适应Win10深浅色模式 //bool m_show_internet_ip{ false }; //是否在“连接详情”对话框中显示外网IP地址 bool m_use_log_scale{ false }; //“历史流量统计”对话框中绘制表示历史流量数值的矩形时是否使用对数比例 HistoryTrafficViewType m_view_type{}; bool m_sunday_first{ true }; //是否将周日作为一周的第一天 StringSet plugin_disabled; //已禁用的插件 int taskbar_left_space_win11{}; //Windows11下,任务栏窗口显示在左侧时的边距 }; //内存显示方式 enum class MemoryDisplay { USAGE_PERCENTAGE, //已使用百分比 MEMORY_USED, //内存已使用 MEMORY_AVAILABLE //内存可用 }; //选项设置中“主窗口设置”和“任务栏窗口设置”中公共的数据(不使用此结构体创建对象) struct PublicSettingData { bool specify_each_item_color{ false }; //是否指定每个项目的颜色 FontInfo font; //字体 DispStrings disp_str; //显示的文本 bool speed_short_mode{ false }; //网速显示简洁模式(减少小数点的位数,单位不显示“B”) bool separate_value_unit_with_space{ true }; //网速数值和单位用空格分隔 bool show_tool_tip{ true }; //显示鼠标提示 MemoryDisplay memory_display{ MemoryDisplay::USAGE_PERCENTAGE }; //内存显示方式 bool unit_byte{ true }; //使用字节(B)而不是比特(b)为单位 SpeedUnit speed_unit; //网速的单位 bool hide_unit; //隐藏单位 bool hide_percent; //隐藏百分号 DoubleClickAction double_click_action; //鼠标双击动作 wstring double_click_exe; //鼠标双击动作为打开指定应用程序时,打开的程序路径 }; //#define MAIN_WND_COLOR_NUM 9 //主窗口颜色数量 //选项设置中“主窗口设置”的数据 struct MainWndSettingData : public PublicSettingData { std::map text_colors{}; //方字的颜色 bool swap_up_down{ false }; //交换上传和下载显示的位置 bool hide_main_wnd_when_fullscreen; //有程序全屏运行时隐藏悬浮窗 bool m_always_on_top{ false }; //窗口置顶 bool m_lock_window_pos{ false }; //锁定窗口位置 bool m_mouse_penetrate{ false }; //鼠标穿透 bool m_alow_out_of_border{ false }; //是否允许悬浮窗超出屏幕边界 }; //#define TASKBAR_COLOR_NUM 18 //任务栏窗口颜色数量 struct TaskbarItemColor //任务栏窗口每一项的颜色 { COLORREF label{}; //标签颜色 COLORREF value{}; //数值颜色 bool operator==(const TaskbarItemColor& item) const { return label == item.label && value == item.value; } }; //选项设置中“任务栏窗口设置”的数据 struct TaskBarSettingData : public PublicSettingData { COLORREF back_color{ RGB(0, 0, 0) }; //背景颜色 COLORREF transparent_color{ RGB(0, 0, 0) }; //透明色 COLORREF status_bar_color{ RGB(0, 0, 0) }; // CPU/内存 状态条颜色 std::map text_colors{}; //文字的颜色 int dft_back_color = 0; //默认背景颜色 int dft_transparent_color = 0; //默认透明色 int dft_status_bar_color = 0x005A5A5A; //默认CPU/内存 状态条颜色 int dft_text_colors = 0x00ffffffU; //默认文字颜色 bool auto_adapt_light_theme{ true }; //是否自动适应浅色主题 int dark_default_style{ 0 }; //深色主题时使用的预设方案 int light_default_style{ -1 }; //浅色主题时使用的预设方案 bool auto_set_background_color{ false }; //根据任务栏颜色自动设置背景色 bool auto_save_taskbar_color_settings_to_preset{}; //当启用“自动适应Windows10深色/浅色主题”时,是否在颜色设置有更改时自动将当前颜色设置保存到对应的预设 CTaskbarItemOrderHelper item_order; unsigned int m_tbar_display_item{ TDI_UP | TDI_DOWN }; //任务栏窗口显示的项目 StringSet plugin_display_item; //任务窗口显示的插件项目 bool value_right_align{ false }; //数值是否右对齐 int digits_number{ 4 }; //数据位数 bool horizontal_arrange{ true }; //水平排列 bool show_status_bar{ true }; //显示 CPU/内存的状态条 bool tbar_wnd_on_left{ false }; //如果为true,则任务栏窗口显示在任务栏的左侧(或上方) bool tbar_wnd_snap{ false }; //如果为true,则在Win11中任务栏窗口贴靠中间任务栏,否则靠近边缘 bool cm_graph_type{ false }; //如果为false,默认原样式,柱状图显示占用率,如为true,滚动显示占用率 bool show_graph_dashed_box{ true }; //显示占用图虚线框 int item_space{}; //任务栏项目间距 void ValidItemSpace(); bool show_netspeed_figure{ false }; //是否显示网速占用图 int netspeed_figure_max_value; //网速占用图的最大值 int netspeed_figure_max_value_unit{}; //网速占用图最大值的单位(0: KB, 1: MB) unsigned __int64 GetNetspeedFigureMaxValueInBytes() const; //获取网速占用图的最大值(以字节为单位) }; //选项设置中“常规设置”的数据 struct GeneralSettingData { bool check_update_when_start{ true }; int update_source{}; //更新源。0: GitHub; 1: Gitee bool auto_run{ false }; bool allow_skin_cover_font{ true }; bool allow_skin_cover_text{ true }; bool show_notify_icon{ true }; //显示通知区域图标 //通知消息 bool traffic_tip_enable{ false }; //是否启用流量超出时提示 int traffic_tip_value; //要提示的流量临界值 int traffic_tip_unit{}; //要提示的流量值的单位(0: MB, 1: GB) struct NotifyTipSettings //超过某个值时弹出提示的设置 { bool enable; //是否启用提示 int tip_value; //要弹出提示的临界值 }; NotifyTipSettings memory_usage_tip; //用内存使用率超出提示 NotifyTipSettings cpu_temp_tip; //CPU温度超出提示 NotifyTipSettings gpu_temp_tip; //显卡温度超出提示 NotifyTipSettings hdd_temp_tip; //硬盘温度超出提示 NotifyTipSettings mainboard_temp_tip; //主板温度超出提示 //语言 Language language; bool show_all_interface{ true }; bool m_get_cpu_usage_by_cpu_times{ true }; //获取CPU利用率的方式,如果为true则是使用GetSystemTimes,否则使用Pdh(性能计数器) bool portable_mode{ false }; //便携模式,如果为true,则程序所有数据都保存到exe所在目录下,否则保存到Appdata\Romaing目录下 int monitor_time_span{ 1000 }; //监控的时间间隔 std::wstring hard_disk_name; //要监控的硬盘名称 std::wstring cpu_core_name; //要监控的CPU核心的名称 unsigned int hardware_monitor_item{}; //要监控哪些硬件 bool IsHardwareEnable(HardwareItem item_type) const { return hardware_monitor_item & item_type; } void SetHardwareEnable(HardwareItem item_type, bool enable) { if (enable) hardware_monitor_item |= item_type; else hardware_monitor_item &= ~item_type; } StringSet connections_hide; //用于保存哪些网络要从“选择网络连接”子菜单项中隐藏 }; //定义监控时间间隔有效的最大值和最小值 #define MONITOR_TIME_SPAN_MIN 200 #define MONITOR_TIME_SPAN_MAX 2000 enum class Alignment { LEFT, //左对齐 RIGHT, //右对齐 CENTER, //居中 SIDE //两端对齐 }; //通过构造函数传递一个bool变量的引用,在构造时将其置为true,析构时置为false class CFlagLocker { public: CFlagLocker(bool& flag) : m_flag(flag) { m_flag = true; } ~CFlagLocker() { m_flag = false; } private: bool& m_flag; }; ================================================ FILE: TrafficMonitor/DisplayTextSettingDlg.cpp ================================================ // DisplayTextSettingDlg.cpp: 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "DisplayTextSettingDlg.h" // CDisplayTextSettingDlg 对话框 IMPLEMENT_DYNAMIC(CDisplayTextSettingDlg, CBaseDialog) CDisplayTextSettingDlg::CDisplayTextSettingDlg(DispStrings& display_texts, bool main_window_text, CWnd* pParent /*=nullptr*/) : CBaseDialog(IDD_DISPLAY_TEXT_SETTINGS_DIALOG, pParent), m_display_texts(display_texts), m_main_window_text(main_window_text) { } CDisplayTextSettingDlg::~CDisplayTextSettingDlg() { } void CDisplayTextSettingDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST1, m_list_ctrl); } CString CDisplayTextSettingDlg::GetDialogName() const { return _T("DisplayTextSettingDlg"); } BEGIN_MESSAGE_MAP(CDisplayTextSettingDlg, CBaseDialog) ON_BN_CLICKED(IDC_RESTORE_DEFAULT_BUTTON, &CDisplayTextSettingDlg::OnBnClickedRestoreDefaultButton) END_MESSAGE_MAP() // CDisplayTextSettingDlg 消息处理程序 BOOL CDisplayTextSettingDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetIcon(theApp.GetMenuIcon(IDI_ITEM), FALSE); // 设置小图标 //初始化列表控件 CRect rect; m_list_ctrl.GetClientRect(rect); m_list_ctrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP); int width0, width1; width0 = rect.Width() / 2; width1 = rect.Width() - width0 - theApp.DPI(20) - 1; m_list_ctrl.InsertColumn(0, CCommon::LoadText(IDS_ITEM), LVCFMT_LEFT, width0); //插入第0列 m_list_ctrl.InsertColumn(1, CCommon::LoadText(IDS_VALUE), LVCFMT_LEFT, width1); //插入第1列 //向列表中插入行 for (auto iter = m_display_texts.GetAllItems().begin(); iter != m_display_texts.GetAllItems().end(); ++iter) { CString item_name = iter->first.GetItemName(); if (!item_name.IsEmpty()) { int index = m_list_ctrl.GetItemCount(); m_list_ctrl.InsertItem(index, item_name); m_list_ctrl.SetItemText(index, 1, iter->second.c_str()); m_list_ctrl.SetItemData(index, (DWORD_PTR)&(iter->first)); } } m_list_ctrl.SetEditColMethod(CListCtrlEx::EC_SPECIFIED); //设置列表可编辑 m_list_ctrl.SetEditableCol({ 1 }); //设置可编辑的列 return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } CommonDisplayItem CDisplayTextSettingDlg::GetDisplayItem(int row) { CommonDisplayItem* item = (CommonDisplayItem*)m_list_ctrl.GetItemData(row); return *item; } void CDisplayTextSettingDlg::OnOK() { // TODO: 在此添加专用代码和/或调用基类 int item_count = m_list_ctrl.GetItemCount(); for (int i{}; i < item_count; i++) { CommonDisplayItem display_item = GetDisplayItem(i); m_display_texts.Get(display_item) = m_list_ctrl.GetItemText(i, 1).GetString(); } CBaseDialog::OnOK(); } void CDisplayTextSettingDlg::OnBnClickedRestoreDefaultButton() { // TODO: 在此添加控件通知处理程序代码 int item_count = m_list_ctrl.GetItemCount(); for (int i{}; i < item_count; i++) { CommonDisplayItem display_item = GetDisplayItem(i); CString default_text; if (display_item.is_plugin) { default_text = display_item.plugin_item->GetItemLableText(); } else { switch (display_item.item_type) { case TDI_UP: if (m_main_window_text) default_text = CCommon::LoadText(IDS_UPLOAD_DISP, _T(": ")); else default_text = _T("↑: "); break; case TDI_DOWN: if (m_main_window_text) default_text = CCommon::LoadText(IDS_DOWNLOAD_DISP, _T(": ")); else default_text = _T("↓: "); break; case TDI_TOTAL_SPEED: default_text = _T("↑↓: "); break; case TDI_CPU: default_text = _T("CPU: "); break; case TDI_CPU_FREQ: default_text = CCommon::LoadText(IDS_CPU_FREQ, _T(": ")); break; case TDI_MEMORY: default_text = CCommon::LoadText(IDS_MEMORY_DISP, _T(": ")); break; case TDI_GPU_USAGE: default_text = CCommon::LoadText(IDS_GPU_DISP, _T(": ")); break; case TDI_CPU_TEMP: default_text = _T("CPU: "); break; case TDI_GPU_TEMP: default_text = CCommon::LoadText(IDS_GPU_DISP, _T(": ")); break; case TDI_HDD_TEMP: default_text = CCommon::LoadText(IDS_HDD_DISP, _T(": ")); break; case TDI_MAIN_BOARD_TEMP: default_text = CCommon::LoadText(IDS_MAINBOARD_DISP, _T(": ")); break; case TDI_HDD_USAGE: default_text = CCommon::LoadText(IDS_HDD_DISP, _T(": ")); break; default: break; } } m_list_ctrl.SetItemText(i, 1, default_text); } } ================================================ FILE: TrafficMonitor/DisplayTextSettingDlg.h ================================================ #pragma once #include "BaseDialog.h" #include "CommonData.h" #include "ListCtrlEx.h" // CDisplayTextSettingDlg 对话框 class CDisplayTextSettingDlg : public CBaseDialog { DECLARE_DYNAMIC(CDisplayTextSettingDlg) public: CDisplayTextSettingDlg(DispStrings& display_texts, bool main_window_text = false, CWnd* pParent = nullptr); // 标准构造函数 virtual ~CDisplayTextSettingDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_DISPLAY_TEXT_SETTINGS_DIALOG }; #endif private: DispStrings& m_display_texts; CListCtrlEx m_list_ctrl; bool m_main_window_text{ false }; //如果为true,则为主窗口文本设置,否则为任务栏窗口设置 protected: virtual CString GetDialogName() const override; CommonDisplayItem GetDisplayItem(int row); virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); virtual void OnOK(); afx_msg void OnBnClickedRestoreDefaultButton(); }; ================================================ FILE: TrafficMonitor/DonateDlg.cpp ================================================ // DonateDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "DonateDlg.h" #include "afxdialogex.h" #include "DrawCommon.h" // CDonateDlg 对话框 IMPLEMENT_DYNAMIC(CDonateDlg, CBaseDialog) CDonateDlg::CDonateDlg(CWnd* pParent /*=NULL*/) : CBaseDialog(IDD_DONATE_DIALOG, pParent) { } CDonateDlg::~CDonateDlg() { } void CDonateDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); //DDX_Control(pDX, IDC_DONATE_PIC, m_donate_pic); } CString CDonateDlg::GetDialogName() const { return _T("DonateDlg"); } BEGIN_MESSAGE_MAP(CDonateDlg, CBaseDialog) ON_WM_PAINT() END_MESSAGE_MAP() // CDonateDlg 消息处理程序 BOOL CDonateDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetWindowText(CCommon::LoadText(IDS_TITLE_DONATE)); //计算两个二维码图片的位置 CRect rect{}; CWnd* pWnd = nullptr; pWnd = GetDlgItem(IDC_TEXT_STATIC); if (pWnd != nullptr) { pWnd->GetWindowRect(rect); ScreenToClient(rect); } CRect rc_pic_area; GetClientRect(rc_pic_area); rc_pic_area.top = rect.bottom + theApp.DPI(8); rc_pic_area.left += theApp.DPI(10); rc_pic_area.right -= theApp.DPI(10); pWnd = GetDlgItem(IDOK); if (pWnd != nullptr) { pWnd->GetWindowRect(rect); ScreenToClient(rect); } rc_pic_area.bottom = rect.top - theApp.DPI(8); m_pic1_rect = rc_pic_area; m_pic1_rect.right = m_pic1_rect.left + (rc_pic_area.Width() / 2) - theApp.DPI(4); m_pic2_rect = rc_pic_area; m_pic2_rect.left = m_pic2_rect.right - (rc_pic_area.Width() / 2) + theApp.DPI(4); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CDonateDlg::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CBaseDialog::OnPaint() CDrawCommon draw; draw.Create(&dc, this); draw.DrawBitmap(IDB_DONATE_BITMAP, m_pic1_rect.TopLeft(), m_pic1_rect.Size(), CDrawCommon::StretchMode::FIT); draw.DrawBitmap(IDB_DONATE_WECHAT, m_pic2_rect.TopLeft(), m_pic2_rect.Size(), CDrawCommon::StretchMode::FIT); } ================================================ FILE: TrafficMonitor/DonateDlg.h ================================================ #pragma once #include "afxwin.h" #include "PictureStatic.h" #include "BaseDialog.h" // CDonateDlg 对话框 class CDonateDlg : public CBaseDialog { DECLARE_DYNAMIC(CDonateDlg) public: CDonateDlg(CWnd* pParent = NULL); // 标准构造函数 virtual ~CDonateDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_DONATE_DIALOG }; #endif protected: //CPictureStatic m_donate_pic; CRect m_pic1_rect; CRect m_pic2_rect; virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 virtual CString GetDialogName() const override; DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnPaint(); }; ================================================ FILE: TrafficMonitor/DrawCommon.cpp ================================================ #include "stdafx.h" #include "DrawCommon.h" CDrawCommon::CDrawCommon() { } CDrawCommon::~CDrawCommon() { } void CDrawCommon::Create(CDC* pDC, CWnd* pMainWnd) { m_pDC = pDC; m_pMainWnd = pMainWnd; if (pMainWnd != nullptr) m_pfont = m_pMainWnd->GetFont(); } void CDrawCommon::SetFont(CFont* pfont) { m_pfont = pfont; m_pDC->SelectObject(m_pfont); } void CDrawCommon::SetDC(CDC* pDC) { m_pDC = pDC; } void CDrawCommon::DrawWindowText(CRect rect, LPCTSTR lpszString, COLORREF color, Alignment align, bool draw_back_ground, bool multi_line) { m_pDC->SetTextColor(color); if (!draw_back_ground) m_pDC->SetBkMode(TRANSPARENT); m_pDC->SelectObject(m_pfont); CSize text_size = m_pDC->GetTextExtent(lpszString); UINT format; //CDC::DrawText()函数的文本格式 if (multi_line) format = DT_EDITCONTROL | DT_WORDBREAK | DT_NOPREFIX; else format = DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX; if (text_size.cx > rect.Width()) //如果文本宽度超过了矩形区域的宽度,设置了居中时左对齐 { if (align == Alignment::RIGHT) format |= DT_RIGHT; } else { switch (align) { case Alignment::RIGHT: format |= DT_RIGHT; break; case Alignment::CENTER: format |= DT_CENTER; break; } } if (draw_back_ground) m_pDC->FillSolidRect(rect, m_back_color); m_pDC->DrawText(lpszString, rect, format); } void CDrawCommon::SetDrawRect(CRect rect) { CRgn rgn; rgn.CreateRectRgnIndirect(rect); m_pDC->SelectClipRgn(&rgn); } void CDrawCommon::SetDrawRect(CDC* pDC, CRect rect) { CRgn rgn; rgn.CreateRectRgnIndirect(rect); pDC->SelectClipRgn(&rgn); } void CDrawCommon::DrawBitmap(CBitmap& bitmap, CPoint start_point, CSize size, StretchMode stretch_mode) { CDC memDC; //获取图像实际大小 BITMAP bm; GetObject(bitmap, sizeof(BITMAP), &bm); memDC.CreateCompatibleDC(m_pDC); memDC.SelectObject(&bitmap); // 以下两行避免图片失真 m_pDC->SetStretchBltMode(HALFTONE); m_pDC->SetBrushOrg(0, 0); CSize draw_size; if (size.cx == 0 || size.cy == 0) //如果指定的size为0,则使用位图的实际大小绘制 { draw_size = CSize(bm.bmWidth, bm.bmHeight); } else { draw_size = size; if (stretch_mode == StretchMode::FILL) { SetDrawRect(CRect(start_point, draw_size)); float w_h_radio, w_h_radio_draw; //图像的宽高比、绘制大小的宽高比 w_h_radio = static_cast(bm.bmWidth) / bm.bmHeight; w_h_radio_draw = static_cast(size.cx) / size.cy; if (w_h_radio > w_h_radio_draw) //如果图像的宽高比大于绘制区域的宽高比,则需要裁剪两边的图像 { int image_width; //按比例缩放后的宽度 image_width = bm.bmWidth * draw_size.cy / bm.bmHeight; start_point.x -= ((image_width - draw_size.cx) / 2); draw_size.cx = image_width; } else { int image_height; //按比例缩放后的高度 image_height = bm.bmHeight * draw_size.cx / bm.bmWidth; start_point.y -= ((image_height - draw_size.cy) / 2); draw_size.cy = image_height; } } else if (stretch_mode == StretchMode::FIT) { draw_size = CSize(bm.bmWidth, bm.bmHeight); float w_h_radio, w_h_radio_draw; //图像的宽高比、绘制大小的宽高比 w_h_radio = static_cast(bm.bmWidth) / bm.bmHeight; w_h_radio_draw = static_cast(size.cx) / size.cy; if (w_h_radio > w_h_radio_draw) //如果图像的宽高比大于绘制区域的宽高比 { draw_size.cy = draw_size.cy * size.cx / draw_size.cx; draw_size.cx = size.cx; start_point.y += ((size.cy - draw_size.cy) / 2); } else { draw_size.cx = draw_size.cx * size.cy / draw_size.cy; draw_size.cy = size.cy; start_point.x += ((size.cx - draw_size.cx) / 2); } } } m_pDC->StretchBlt(start_point.x, start_point.y, draw_size.cx, draw_size.cy, &memDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); memDC.DeleteDC(); } void CDrawCommon::DrawBitmap(UINT bitmap_id, CPoint start_point, CSize size, StretchMode stretch_mode) { CBitmap bitmap; bitmap.LoadBitmap(bitmap_id); DrawBitmap(bitmap, start_point, size, stretch_mode); } void CDrawCommon::DrawBitmap(HBITMAP hbitmap, CPoint start_point, CSize size, StretchMode stretch_mode) { CBitmap bitmap; if (!bitmap.Attach(hbitmap)) return; DrawBitmap(bitmap, start_point, size, stretch_mode); bitmap.Detach(); } void CDrawCommon::DrawIcon(HICON hIcon, CPoint start_point, CSize size) { if (m_pDC->GetSafeHdc() == NULL) return; if (size.cx == 0 || size.cy == 0) ::DrawIconEx(m_pDC->GetSafeHdc(), start_point.x, start_point.y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_DEFAULTSIZE); else ::DrawIconEx(m_pDC->GetSafeHdc(), start_point.x, start_point.y, hIcon, size.cx, size.cy, 0, NULL, DI_NORMAL); } void CDrawCommon::BitmapStretch(CImage* pImage, CImage* ResultImage, CSize size) { if (pImage->IsDIBSection()) { // 取得 pImage 的 DC CDC* pImageDC1 = CDC::FromHandle(pImage->GetDC()); // Image 因為有自己的 DC, 所以必須使用 FromHandle 取得對應的 DC CBitmap* bitmap1 = pImageDC1->GetCurrentBitmap(); BITMAP bmpInfo; bitmap1->GetBitmap(&bmpInfo); // 建立新的 CImage ResultImage->Create(size.cx, size.cy, bmpInfo.bmBitsPixel); CDC* ResultImageDC = CDC::FromHandle(ResultImage->GetDC()); // 當 Destination 比較小的時候, 會根據 Destination DC 上的 Stretch Blt mode 決定是否要保留被刪除點的資訊 ResultImageDC->SetStretchBltMode(HALFTONE); // 使用最高品質的方式 ::SetBrushOrgEx(ResultImageDC->m_hDC, 0, 0, NULL); // 調整 Brush 的起點 // 把 pImage 畫到 ResultImage 上面 StretchBlt(*ResultImageDC, 0, 0, size.cx, size.cy, *pImageDC1, 0, 0, pImage->GetWidth(), pImage->GetHeight(), SRCCOPY); // pImage->Draw(*ResultImageDC,0,0,StretchWidth,StretchHeight,0,0,pImage->GetWidth(),pImage->GetHeight()); pImage->ReleaseDC(); ResultImage->ReleaseDC(); } } void CDrawCommon::FillRect(CRect rect, COLORREF color) { m_pDC->FillSolidRect(rect, color); } void CDrawCommon::FillRectWithBackColor(CRect rect) { m_pDC->FillSolidRect(rect, m_back_color); } void CDrawCommon::DrawRectOutLine(CRect rect, COLORREF color, int width, bool dot_line) { CPen aPen, * pOldPen; aPen.CreatePen((dot_line ? PS_DOT : PS_SOLID), width, color); pOldPen = m_pDC->SelectObject(&aPen); CBrush* pOldBrush{ dynamic_cast(m_pDC->SelectStockObject(NULL_BRUSH)) }; rect.DeflateRect(width / 2, width / 2); m_pDC->Rectangle(rect); m_pDC->SelectObject(pOldPen); m_pDC->SelectObject(pOldBrush); // Restore the old brush aPen.DeleteObject(); } void CDrawCommon::GetRegionFromImage(CRgn& rgn, CBitmap& cBitmap, int threshold) { CDC memDC; memDC.CreateCompatibleDC(NULL); CBitmap* pOldMemBmp = NULL; pOldMemBmp = memDC.SelectObject(&cBitmap); //创建总的窗体区域,初始region为0 rgn.CreateRectRgn(0, 0, 0, 0); BITMAP bit; cBitmap.GetBitmap(&bit);//取得位图参数,这里要用到位图的长和宽 int y; for (y = 0; y < bit.bmHeight; y++) { CRgn rgnTemp; //保存临时region int iX = 0; do { //跳过透明色找到下一个非透明色的点. while (iX < bit.bmWidth && GetColorBritness(memDC.GetPixel(iX, y)) <= threshold) iX++; int iLeftX = iX; //记住这个起始点 //寻找下个透明色的点 while (iX < bit.bmWidth && GetColorBritness(memDC.GetPixel(iX, y)) > threshold) ++iX; //创建一个包含起点与重点间高为1像素的临时“region” rgnTemp.CreateRectRgn(iLeftX, y, iX, y + 1); rgn.CombineRgn(&rgn, &rgnTemp, RGN_OR); //删除临时"region",否则下次创建时和出错 rgnTemp.DeleteObject(); } while (iX < bit.bmWidth); } memDC.DeleteDC(); } int CDrawCommon::GetColorBritness(COLORREF color) { return (GetRValue(color) + GetGValue(color) + GetBValue(color)) / 3; } void CDrawCommon::DrawLine(CPoint start_point, int height, COLORREF color) { CPen aPen, * pOldPen; aPen.CreatePen(PS_SOLID, 1, color); pOldPen = m_pDC->SelectObject(&aPen); CBrush* pOldBrush{ dynamic_cast(m_pDC->SelectStockObject(NULL_BRUSH)) }; m_pDC->MoveTo(start_point); //移动到起始点,默认是从下向上画 m_pDC->LineTo(CPoint(start_point.x, start_point.y - height)); m_pDC->SelectObject(pOldPen); m_pDC->SelectObject(pOldBrush); // Restore the old brush aPen.DeleteObject(); } ================================================ FILE: TrafficMonitor/DrawCommon.h ================================================ //封装的绘图类 #pragma once #include "CommonData.h" class CDrawCommon { public: //拉伸模式 enum class StretchMode { STRETCH, //拉伸,会改变比例 FILL, //填充,不改变比例,会裁剪长边 FIT //适应,不会改变比例,不裁剪 }; CDrawCommon(); ~CDrawCommon(); void Create(CDC* pDC, CWnd* pMainWnd); void SetFont(CFont* pfont); //设置绘制文本的字体 void SetDC(CDC* pDC); //设置绘图的DC CDC* GetDC() { return m_pDC; } void SetBackColor(COLORREF back_color) { m_back_color = back_color; } void DrawWindowText(CRect rect, LPCTSTR lpszString, COLORREF color, Alignment align = Alignment::LEFT, bool draw_back_ground = false, bool multi_line = false); //在指定的矩形区域内绘制文本 void SetDrawRect(CRect rect); //设置绘图剪辑区域 static void SetDrawRect(CDC* pDC, CRect rect); //绘制一个位图 //(注意:当stretch_mode设置为StretchMode::FILL(填充)时,会设置绘图剪辑区域,如果之后需要绘制其他图形, //需要重新设置绘图剪辑区域,否则图片外的区域会无法绘制) void DrawBitmap(CBitmap& bitmap, CPoint start_point, CSize size, StretchMode stretch_mode = StretchMode::STRETCH); void DrawBitmap(UINT bitmap_id, CPoint start_point, CSize size, StretchMode stretch_mode = StretchMode::STRETCH); void DrawBitmap(HBITMAP hbitmap, CPoint start_point, CSize size, StretchMode stretch_mode = StretchMode::STRETCH); void DrawIcon(HICON hIcon, CPoint start_point, CSize size); //将图片拉伸到指定尺寸(https://blog.csdn.net/sichuanpb/article/details/22986877) static void BitmapStretch(CImage* pImage, CImage* ResultImage, CSize size); void FillRect(CRect rect, COLORREF color); //用纯色填充矩形 void FillRectWithBackColor(CRect rect); //使用背景色填充矩形 void DrawRectOutLine(CRect rect, COLORREF color, int width = 1, bool dot_line = false); //绘制矩形边框。如果dot_line为true,则为虚线 //从图像创建区域,如果像素点的亮度小于threshold(取值为0~255,0为黑色,255为白色),则该像素点在区域外 //https://blog.csdn.net/tajon1226/article/details/6589180 static void GetRegionFromImage(CRgn& rgn, CBitmap& cBitmap, int threshold); void DrawLine(CPoint start_point, int height, COLORREF color); //使用当前画笔画线 private: CDC* m_pDC{}; //用于绘图的CDC类的指针 CWnd* m_pMainWnd{}; //绘图窗口的句柄 CFont* m_pfont{}; COLORREF m_back_color{}; static int GetColorBritness(COLORREF color); }; //用于双缓冲绘图的类 class CDrawDoubleBuffer { public: CDrawDoubleBuffer(CDC* pDC, CRect rect) : m_pDC(pDC), m_rect(rect) { if (m_pDC != nullptr) { m_memDC.CreateCompatibleDC(NULL); m_memBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); m_pOldBit = m_memDC.SelectObject(&m_memBitmap); } } ~CDrawDoubleBuffer() { if (m_pDC != nullptr) { m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(), &m_memDC, 0, 0, SRCCOPY); m_memDC.SelectObject(m_pOldBit); m_memBitmap.DeleteObject(); m_memDC.DeleteDC(); } } CDC* GetMemDC() { return &m_memDC; } private: CDC* m_pDC; CDC m_memDC; CBitmap m_memBitmap; CBitmap* m_pOldBit; CRect m_rect; }; ================================================ FILE: TrafficMonitor/DrawCommonEx.cpp ================================================ #include "stdafx.h" #include "DrawCommonEx.h" CDrawCommonEx::CDrawCommonEx(CDC* pDC) { m_pDC = pDC; hThm = OpenThemeData(::GetDesktopWindow(), L"Window"); } CDrawCommonEx::~CDrawCommonEx() { CloseThemeData(hThm); } void CDrawCommonEx::DrawWindowText(CRect rect, LPCTSTR str, COLORREF color) { m_pDC->SelectObject(m_pFont); m_pDC->SetTextColor(color); DTTOPTS dttopts{}; dttopts.dwSize = sizeof(DTTOPTS); dttopts.dwFlags = DTT_GLOWSIZE | DTT_COMPOSITED; //ѡ dttopts.iGlowSize = 0; //ķΧС HRESULT hr = DrawThemeTextEx(hThm, m_pDC->GetSafeHdc(), TEXT_LABEL, 0, str, -1, DT_LEFT | DT_SINGLELINE, rect, &dttopts); } void CDrawCommonEx::SetFont(CFont * pFont) { m_pFont = pFont; } ================================================ FILE: TrafficMonitor/DrawCommonEx.h ================================================ #pragma once class CDrawCommonEx { public: CDrawCommonEx(CDC* pDC); ~CDrawCommonEx(); void DrawWindowText(CRect rect, LPCTSTR str, COLORREF color); void SetFont(CFont* pFont); private: HTHEME hThm; CFont* m_pFont{}; CDC* m_pDC{}; }; ================================================ FILE: TrafficMonitor/FilePathHelper.cpp ================================================ #include "stdafx.h" #include "FilePathHelper.h" #include "Common.h" CFilePathHelper::CFilePathHelper(const wstring & file_path) : m_file_path{ file_path } { } CFilePathHelper::~CFilePathHelper() { } wstring CFilePathHelper::GetFileExtension(bool upper, bool width_dot) const { size_t index; index = m_file_path.rfind('.'); if (index == wstring::npos || index == m_file_path.size() - 1) return wstring(); wstring file_extension{ m_file_path.substr(width_dot ? index : index + 1) }; CCommon::StringTransform(file_extension, upper); return file_extension; } wstring CFilePathHelper::GetFileName() const { size_t index; index = m_file_path.rfind('\\'); if (index == wstring::npos) index = m_file_path.rfind('/'); return m_file_path.substr(index + 1); } wstring CFilePathHelper::GetFileNameWithoutExtension() const { size_t index, index1; index = m_file_path.rfind('.'); index1 = m_file_path.rfind('\\'); if (index1 == wstring::npos) index1 = m_file_path.rfind('/'); return m_file_path.substr(index1 + 1, (index - index1 - 1)); } wstring CFilePathHelper::GetFolderName() const { int index, index1; index = m_file_path.find_last_of(L"\\/"); if (index == wstring::npos || index == 0) return wstring(); index1 = m_file_path.find_last_of(L"\\/", index - 1); if (index1 == wstring::npos || index1 == 0) return wstring(); return m_file_path.substr(index1 + 1, (index - index1 - 1)); } wstring CFilePathHelper::GetDir() const { if (!m_file_path.empty() && (m_file_path.back() == L'\\' || m_file_path.back() == L'/')) return m_file_path; size_t index; index = m_file_path.rfind('\\'); if (index == wstring::npos) index = m_file_path.rfind('/'); return m_file_path.substr(0, index + 1); } wstring CFilePathHelper::GetParentDir() const { wstring dir{ GetDir() }; size_t index; if (!dir.empty() && (dir.back() == L'\\' || dir.back() == L'/')) dir.pop_back(); index = dir.rfind('\\'); if (index == wstring::npos) index = dir.rfind('/'); return m_file_path.substr(0, index + 1); } const wstring& CFilePathHelper::ReplaceFileExtension(const wchar_t * new_extension) { size_t index, index1; index = m_file_path.rfind('.'); index1 = m_file_path.rfind('\\'); if (index == wstring::npos || (index1 != wstring::npos && index < index1)) //如果没有找到“.”,或者“.”在反斜杠的左边,则在末尾添加一个“.” { m_file_path.push_back(L'.'); } else if (index != m_file_path.size() - 1) //如果“.”不在最后的位置,则删除“.”后面的字符串 { m_file_path.erase(index + 1); } if (new_extension == nullptr || *new_extension == L'\0') { if (!m_file_path.empty() && m_file_path.back() == L'.') m_file_path.pop_back(); } else { m_file_path.append(new_extension); //在末尾添加扩展名 } return m_file_path; } wstring CFilePathHelper::GetFilePathWithoutExtension() const { size_t index; index = m_file_path.rfind('.'); return m_file_path.substr(0, index); } ================================================ FILE: TrafficMonitor/FilePathHelper.h ================================================ #pragma once class CFilePathHelper { public: CFilePathHelper(const wstring& file_path); CFilePathHelper(){} ~CFilePathHelper(); void SetFilePath(const wstring& file_path) { m_file_path = file_path; } wstring GetFileExtension(bool upper = false, bool width_dot = false) const; //获取文件的扩展名(upper:是否大写; width_dot:是否包含“.”) wstring GetFileName() const; //获取文件名 wstring GetFileNameWithoutExtension() const; //获取文件名(不含扩展名) wstring GetFolderName() const; //获取文件夹名 wstring GetDir() const; //获取目录 wstring GetParentDir() const; //获取上级目录 wstring GetFilePath() const { return m_file_path; } //获取完整路径 const wstring& ReplaceFileExtension(const wchar_t* new_extension); //替换文件的扩展名,返回文件完整路径 wstring GetFilePathWithoutExtension() const; //获取文件路径(不含扩展名) protected: wstring m_file_path; }; ================================================ FILE: TrafficMonitor/GeneralSettingsDlg.cpp ================================================ // GeneralSettingsDlg.cpp : implementation file // #include "stdafx.h" #include "TrafficMonitor.h" #include "GeneralSettingsDlg.h" #include "PluginManagerDlg.h" #include "SelectConnectionsDlg.h" // CGeneralSettingsDlg dialog static const int MONITOR_SPAN_STEP = 100; IMPLEMENT_DYNAMIC(CGeneralSettingsDlg, CTabDlg) CGeneralSettingsDlg::CGeneralSettingsDlg(CWnd* pParent /*=NULL*/) : CTabDlg(IDD_GENERAL_SETTINGS_DIALOG, pParent) { } CGeneralSettingsDlg::~CGeneralSettingsDlg() { } void CGeneralSettingsDlg::CheckTaskbarDisplayItem() { //如果选项设置中关闭了某个硬件监控,则不显示对应的温度监控相关项目 int taskbar_displat_item_ori = theApp.m_taskbar_data.m_tbar_display_item; if (!theApp.m_general_data.IsHardwareEnable(HI_CPU)) { theApp.m_taskbar_data.m_tbar_display_item &= ~TDI_CPU_TEMP; theApp.m_taskbar_data.m_tbar_display_item &= ~TDI_CPU_FREQ; } if (!theApp.m_general_data.IsHardwareEnable(HI_GPU)) { theApp.m_taskbar_data.m_tbar_display_item &= ~TDI_GPU_USAGE; theApp.m_taskbar_data.m_tbar_display_item &= ~TDI_GPU_TEMP; } if (!theApp.m_general_data.IsHardwareEnable(HI_HDD)) { theApp.m_taskbar_data.m_tbar_display_item &= ~TDI_HDD_TEMP; theApp.m_taskbar_data.m_tbar_display_item &= ~TDI_HDD_USAGE; } if (!theApp.m_general_data.IsHardwareEnable(HI_MBD)) theApp.m_taskbar_data.m_tbar_display_item &= ~TDI_MAIN_BOARD_TEMP; } void CGeneralSettingsDlg::SetControlMouseWheelEnable(bool enable) { m_traffic_tip_combo.SetMouseWheelEnable(enable); m_language_combo.SetMouseWheelEnable(enable); m_traffic_tip_edit.SetMouseWheelEnable(enable); m_memory_tip_edit.SetMouseWheelEnable(enable); m_monitor_span_edit.SetMouseWheelEnable(enable); m_cpu_temp_tip_edit.SetMouseWheelEnable(enable); m_gpu_temp_tip_edit.SetMouseWheelEnable(enable); m_hdd_temp_tip_edit.SetMouseWheelEnable(enable); m_mbd_temp_tip_edit.SetMouseWheelEnable(enable); m_hard_disk_combo.SetMouseWheelEnable(enable); m_select_cpu_combo.SetMouseWheelEnable(enable); } bool CGeneralSettingsDlg::ShowHardwareMonitorWarning() { if (SHMessageBoxCheck(m_hWnd, CCommon::LoadText(IDS_HARDWARE_MONITOR_WARNING), APP_NAME, MB_OKCANCEL | MB_ICONWARNING, IDOK, _T("{B8A281A7-76DF-4F0F-BF6A-1A394EF8BAD5}")) == IDOK) { //if (SHMessageBoxCheck(m_hWnd, CCommon::LoadText(IDS_HARDWARE_MONITOR_WARNING2), APP_NAME, MB_OKCANCEL | MB_ICONWARNING, IDOK, _T("{2777F260-6175-41E4-AF59-4085B3F58E32}")) == IDOK) //{ return true; //} } return false; } void CGeneralSettingsDlg::AddOrUpdateAutoRunTooltip(bool add) { CString str_tool_tip; #ifdef WITHOUT_TEMPERATURE str_tool_tip = CCommon::LoadText(IDS_AUTO_RUN_METHOD_REGESTRY); #else str_tool_tip = CCommon::LoadText(IDS_AUTO_RUN_METHOD_TASK_SCHEDULE); #endif if (!m_auto_run_path.empty()) { str_tool_tip += _T("\r\n"); str_tool_tip += CCommon::LoadText(IDS_PATH, _T(": ")); str_tool_tip += m_auto_run_path.c_str(); } if (add) m_toolTip.AddTool(GetDlgItem(IDC_AUTO_RUN_CHECK), str_tool_tip); else m_toolTip.UpdateTipText(str_tool_tip, GetDlgItem(IDC_AUTO_RUN_CHECK)); } bool CGeneralSettingsDlg::IsMonitorTimeSpanModified() const { return m_data.monitor_time_span != m_monitor_time_span_ori; } void CGeneralSettingsDlg::DoDataExchange(CDataExchange* pDX) { CTabDlg::DoDataExchange(pDX); DDX_Control(pDX, IDC_TODAY_TRAFFIC_TIP_EDIT, m_traffic_tip_edit); DDX_Control(pDX, IDC_TODAY_TRAFFIC_TIP_COMBO, m_traffic_tip_combo); DDX_Control(pDX, IDC_MEMORY_USAGE_TIP_EDIT, m_memory_tip_edit); DDX_Control(pDX, IDC_LANGUAGE_COMBO, m_language_combo); DDX_Control(pDX, IDC_MONITOR_SPAN_EDIT, m_monitor_span_edit); DDX_Control(pDX, IDC_CPU_TEMP_TIP_EDIT, m_cpu_temp_tip_edit); DDX_Control(pDX, IDC_GPU_TEMP_TIP_EDIT, m_gpu_temp_tip_edit); DDX_Control(pDX, IDC_HDD_TIP_EDIT, m_hdd_temp_tip_edit); DDX_Control(pDX, IDC_MBD_TEMP_TIP_EDIT, m_mbd_temp_tip_edit); DDX_Control(pDX, IDC_SELECT_HARD_DISK_COMBO, m_hard_disk_combo); DDX_Control(pDX, IDC_SELECT_CPU_COMBO, m_select_cpu_combo); DDX_Control(pDX, IDC_PLUGIN_MANAGE_BUTTON, m_plugin_manager_btn); DDX_Control(pDX, IDC_SELECT_CONNECTIONS_BUTTON, m_select_connection_btn); } void CGeneralSettingsDlg::SetControlEnable() { m_traffic_tip_edit.EnableWindow(m_data.traffic_tip_enable); m_traffic_tip_combo.EnableWindow(m_data.traffic_tip_enable); m_memory_tip_edit.EnableWindow(m_data.memory_usage_tip.enable); m_cpu_temp_tip_edit.EnableWindow(m_data.cpu_temp_tip.enable); m_gpu_temp_tip_edit.EnableWindow(m_data.gpu_temp_tip.enable); m_hdd_temp_tip_edit.EnableWindow(m_data.hdd_temp_tip.enable); m_mbd_temp_tip_edit.EnableWindow(m_data.mainboard_temp_tip.enable); m_hard_disk_combo.EnableWindow(m_data.IsHardwareEnable(HI_HDD)); m_select_cpu_combo.EnableWindow(m_data.IsHardwareEnable(HI_CPU)); } BEGIN_MESSAGE_MAP(CGeneralSettingsDlg, CTabDlg) ON_BN_CLICKED(IDC_CHECK_NOW_BUTTON, &CGeneralSettingsDlg::OnBnClickedCheckNowButton) ON_BN_CLICKED(IDC_CHECK_UPDATE_CHECK, &CGeneralSettingsDlg::OnBnClickedCheckUpdateCheck) ON_BN_CLICKED(IDC_AUTO_RUN_CHECK, &CGeneralSettingsDlg::OnBnClickedAutoRunCheck) ON_BN_CLICKED(IDC_ALLOW_SKIN_FONT_CHECK, &CGeneralSettingsDlg::OnBnClickedAllowSkinFontCheck) ON_BN_CLICKED(IDC_ALLOW_SKIN_DISP_STR_CHECK, &CGeneralSettingsDlg::OnBnClickedAllowSkinDispStrCheck) ON_BN_CLICKED(IDC_TODAY_TRAFFIC_TIP_CHECK, &CGeneralSettingsDlg::OnBnClickedTodayTrafficTipCheck) ON_BN_CLICKED(IDC_MEMORY_USAGE_TIP_CHECK, &CGeneralSettingsDlg::OnBnClickedMemoryUsageTipCheck) ON_BN_CLICKED(IDC_OPEN_CONFIG_PATH_BUTTON, &CGeneralSettingsDlg::OnBnClickedOpenConfigPathButton) ON_BN_CLICKED(IDC_SHOW_ALL_CONNECTION_CHECK, &CGeneralSettingsDlg::OnBnClickedShowAllConnectionCheck) ON_BN_CLICKED(IDC_USE_CPU_TIME_RADIO, &CGeneralSettingsDlg::OnBnClickedUseCpuTimeRadio) ON_BN_CLICKED(IDC_USE_PDH_RADIO, &CGeneralSettingsDlg::OnBnClickedUsePdhRadio) ON_NOTIFY(UDN_DELTAPOS, SPIN_ID, &CGeneralSettingsDlg::OnDeltaposSpin) ON_EN_KILLFOCUS(IDC_MONITOR_SPAN_EDIT, &CGeneralSettingsDlg::OnEnKillfocusMonitorSpanEdit) ON_BN_CLICKED(IDC_CPU_TEMP_TIP_CHECK, &CGeneralSettingsDlg::OnBnClickedCpuTempTipCheck) ON_BN_CLICKED(IDC_GPU_TEMP_TIP_CHECK, &CGeneralSettingsDlg::OnBnClickedGpuTempTipCheck) ON_BN_CLICKED(IDC_HDD_TEMP_TIP_CHECK, &CGeneralSettingsDlg::OnBnClickedHddTempTipCheck) ON_BN_CLICKED(IDC_MBD_TEMP_TIP_CHECK, &CGeneralSettingsDlg::OnBnClickedMbdTempTipCheck) ON_BN_CLICKED(IDC_GITHUB_RADIO, &CGeneralSettingsDlg::OnBnClickedGithubRadio) ON_BN_CLICKED(IDC_GITEE_RADIO, &CGeneralSettingsDlg::OnBnClickedGiteeRadio) ON_BN_CLICKED(IDC_RESTORE_DEFAULT_TIME_SPAN_BUTTON, &CGeneralSettingsDlg::OnBnClickedRestoreDefaultTimeSpanButton) ON_CBN_SELCHANGE(IDC_SELECT_HARD_DISK_COMBO, &CGeneralSettingsDlg::OnCbnSelchangeSelectHardDiskCombo) ON_BN_CLICKED(IDC_CPU_CHECK, &CGeneralSettingsDlg::OnBnClickedCpuCheck) ON_BN_CLICKED(IDC_GPU_CHECK, &CGeneralSettingsDlg::OnBnClickedGpuCheck) ON_BN_CLICKED(IDC_HDD_CHECK, &CGeneralSettingsDlg::OnBnClickedHddCheck) ON_BN_CLICKED(IDC_MBD_CHECK, &CGeneralSettingsDlg::OnBnClickedMbdCheck) ON_CBN_SELCHANGE(IDC_SELECT_CPU_COMBO, &CGeneralSettingsDlg::OnCbnSelchangeSelectCpuCombo) ON_BN_CLICKED(IDC_PLUGIN_MANAGE_BUTTON, &CGeneralSettingsDlg::OnBnClickedPluginManageButton) ON_BN_CLICKED(IDC_SHOW_NOTIFY_ICON_CHECK, &CGeneralSettingsDlg::OnBnClickedShowNotifyIconCheck) ON_BN_CLICKED(IDC_SELECT_CONNECTIONS_BUTTON, &CGeneralSettingsDlg::OnBnClickedSelectConnectionsButton) ON_BN_CLICKED(IDC_RESET_AUTO_RUN_BUTTON, &CGeneralSettingsDlg::OnBnClickedResetAutoRunButton) END_MESSAGE_MAP() // CGeneralSettingsDlg 消息处理程序 BOOL CGeneralSettingsDlg::OnInitDialog() { CTabDlg::OnInitDialog(); // TODO: 在此添加额外的初始化 ((CButton*)GetDlgItem(IDC_CHECK_UPDATE_CHECK))->SetCheck(m_data.check_update_when_start); ((CButton*)GetDlgItem(IDC_ALLOW_SKIN_FONT_CHECK))->SetCheck(m_data.allow_skin_cover_font); ((CButton*)GetDlgItem(IDC_ALLOW_SKIN_DISP_STR_CHECK))->SetCheck(m_data.allow_skin_cover_text); if (theApp.IsForceShowNotifyIcon()) { m_data.show_notify_icon = true; EnableDlgCtrl(IDC_SHOW_NOTIFY_ICON_CHECK, FALSE); } CheckDlgButton(IDC_SHOW_NOTIFY_ICON_CHECK, m_data.show_notify_icon); if (m_data.update_source == 0) CheckDlgButton(IDC_GITHUB_RADIO, TRUE); else CheckDlgButton(IDC_GITEE_RADIO, TRUE); //检查开始菜单的“启动”目录下有没有程序的快捷方式,如果有则设置开机自启动,然后删除快捷方式 wstring start_up_path = CCommon::GetStartUpPath(); bool shortcut_exist = CCommon::FileExist((start_up_path + L"\\TrafficMonitor.lnk").c_str()); if (shortcut_exist) { theApp.SetAutoRun(true); m_data.auto_run = true; DeleteFile((start_up_path + L"\\TrafficMonitor.lnk").c_str()); } else { m_data.auto_run = theApp.GetAutoRun(&m_auto_run_path); } ((CButton*)GetDlgItem(IDC_SAVE_TO_APPDATA_RADIO))->SetCheck(!m_data.portable_mode); ((CButton*)GetDlgItem(IDC_SAVE_TO_PROGRAM_DIR_RADIO))->SetCheck(m_data.portable_mode); GetDlgItem(IDC_SAVE_TO_PROGRAM_DIR_RADIO)->EnableWindow(theApp.m_module_dir_writable); ((CButton*)GetDlgItem(IDC_AUTO_RUN_CHECK))->SetCheck(m_data.auto_run); ((CButton*)GetDlgItem(IDC_TODAY_TRAFFIC_TIP_CHECK))->SetCheck(m_data.traffic_tip_enable); m_traffic_tip_edit.SetRange(1, 32767); m_traffic_tip_edit.SetValue(m_data.traffic_tip_value); m_traffic_tip_combo.AddString(_T("MB")); m_traffic_tip_combo.AddString(_T("GB")); m_traffic_tip_combo.SetCurSel(m_data.traffic_tip_unit); CheckDlgButton(IDC_MEMORY_USAGE_TIP_CHECK, m_data.memory_usage_tip.enable); m_memory_tip_edit.SetRange(1, 100); m_memory_tip_edit.SetValue(m_data.memory_usage_tip.tip_value); CheckDlgButton(IDC_CPU_TEMP_TIP_CHECK, m_data.cpu_temp_tip.enable); m_cpu_temp_tip_edit.SetRange(1, 100); m_cpu_temp_tip_edit.SetValue(m_data.cpu_temp_tip.tip_value); CheckDlgButton(IDC_GPU_TEMP_TIP_CHECK, m_data.gpu_temp_tip.enable); m_gpu_temp_tip_edit.SetRange(1, 100); m_gpu_temp_tip_edit.SetValue(m_data.gpu_temp_tip.tip_value); CheckDlgButton(IDC_HDD_TEMP_TIP_CHECK, m_data.hdd_temp_tip.enable); m_hdd_temp_tip_edit.SetRange(1, 100); m_hdd_temp_tip_edit.SetValue(m_data.hdd_temp_tip.tip_value); CheckDlgButton(IDC_MBD_TEMP_TIP_CHECK, m_data.mainboard_temp_tip.enable); m_mbd_temp_tip_edit.SetRange(1, 100); m_mbd_temp_tip_edit.SetValue(m_data.mainboard_temp_tip.tip_value); SetControlEnable(); m_language_combo.AddString(CCommon::LoadText(IDS_FOLLOWING_SYSTEM)); m_language_combo.AddString(_T("English")); m_language_combo.AddString(_T("简体中文")); m_language_combo.AddString(_T("繁體中文")); m_language_combo.SetCurSel(static_cast(m_data.language)); ((CButton*)GetDlgItem(IDC_SHOW_ALL_CONNECTION_CHECK))->SetCheck(m_data.show_all_interface); m_toolTip.Create(this); m_toolTip.SetMaxTipWidth(theApp.DPI(300)); m_toolTip.AddTool(GetDlgItem(IDC_SHOW_ALL_CONNECTION_CHECK), CCommon::LoadText(IDS_SHOW_ALL_INFO_TIP)); m_toolTip.AddTool(GetDlgItem(IDC_SAVE_TO_APPDATA_RADIO), theApp.m_appdata_dir.c_str()); m_toolTip.AddTool(GetDlgItem(IDC_SAVE_TO_PROGRAM_DIR_RADIO), theApp.m_module_dir.c_str()); AddOrUpdateAutoRunTooltip(true); ((CButton*)GetDlgItem(IDC_USE_CPU_TIME_RADIO))->SetCheck(m_data.m_get_cpu_usage_by_cpu_times); ((CButton*)GetDlgItem(IDC_USE_PDH_RADIO))->SetCheck(!m_data.m_get_cpu_usage_by_cpu_times); m_monitor_span_edit.SetRange(MONITOR_TIME_SPAN_MIN, MONITOR_TIME_SPAN_MAX); m_monitor_span_edit.SetValue(m_data.monitor_time_span); m_monitor_time_span_ori = m_data.monitor_time_span; m_update_source_ori = m_data.update_source; #ifndef WITHOUT_TEMPERATURE //初始化硬件监控Check box CheckDlgButton(IDC_CPU_CHECK, m_data.IsHardwareEnable(HI_CPU)); CheckDlgButton(IDC_GPU_CHECK, m_data.IsHardwareEnable(HI_GPU)); CheckDlgButton(IDC_HDD_CHECK, m_data.IsHardwareEnable(HI_HDD)); CheckDlgButton(IDC_MBD_CHECK, m_data.IsHardwareEnable(HI_MBD)); if (theApp.m_pMonitor != nullptr) { CSingleLock sync(&theApp.m_minitor_lib_critical, TRUE); //初始化选择硬盘下拉列表 for (const auto& hdd_item : theApp.m_pMonitor->AllHDDTemperature()) m_hard_disk_combo.AddString(hdd_item.first.c_str()); int cur_index = m_hard_disk_combo.FindString(-1, m_data.hard_disk_name.c_str()); m_hard_disk_combo.SetCurSel(cur_index); //初始化选择CPU下拉列表 m_select_cpu_combo.AddString(CCommon::LoadText(IDS_AVREAGE_TEMPERATURE)); for (const auto& cpu_item : theApp.m_pMonitor->AllCpuTemperature()) m_select_cpu_combo.AddString(cpu_item.first.c_str()); cur_index = m_select_cpu_combo.FindString(-1, m_data.cpu_core_name.c_str()); if (cur_index < 0) cur_index = 0; m_select_cpu_combo.SetCurSel(cur_index); } #endif //不含温度监控的版本,禁用温度相关的控件 #ifdef WITHOUT_TEMPERATURE EnableDlgCtrl(IDC_CPU_TEMP_TIP_CHECK, false); EnableDlgCtrl(IDC_CPU_TEMP_TIP_EDIT, false); EnableDlgCtrl(IDC_GPU_TEMP_TIP_CHECK, false); EnableDlgCtrl(IDC_GPU_TEMP_TIP_EDIT, false); EnableDlgCtrl(IDC_HDD_TEMP_TIP_CHECK, false); EnableDlgCtrl(IDC_HDD_TIP_EDIT, false); EnableDlgCtrl(IDC_MBD_TEMP_TIP_CHECK, false); EnableDlgCtrl(IDC_MBD_TEMP_TIP_EDIT, false); EnableDlgCtrl(IDC_CPU_CHECK, false); EnableDlgCtrl(IDC_GPU_CHECK, false); EnableDlgCtrl(IDC_HDD_CHECK, false); EnableDlgCtrl(IDC_MBD_CHECK, false); EnableDlgCtrl(IDC_SELECT_HARD_DISK_COMBO, false); EnableDlgCtrl(IDC_SELECT_CPU_COMBO, false); EnableDlgCtrl(IDC_CPU_TEMP_STATIC, false); EnableDlgCtrl(IDC_GPU_TEMP_STATIC, false); EnableDlgCtrl(IDC_HDD_STATIC, false); EnableDlgCtrl(IDC_MBD_TEMP_STATIC, false); EnableDlgCtrl(IDC_SELECT_HDD_STATIC, false); EnableDlgCtrl(IDC_SELECT_CPU_STATIC, false); EnableDlgCtrl(IDC_HARDWARE_MONITOR_STATIC, false); #endif m_plugin_manager_btn.SetIcon(theApp.GetMenuIcon(IDI_PLUGINS)); m_select_connection_btn.SetIcon(theApp.GetMenuIcon(IDI_CONNECTION)); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CGeneralSettingsDlg::OnBnClickedCheckNowButton() { // TODO: 在此添加控件通知处理程序代码 theApp.CheckUpdateInThread(true); } void CGeneralSettingsDlg::OnBnClickedCheckUpdateCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.check_update_when_start = (((CButton*)GetDlgItem(IDC_CHECK_UPDATE_CHECK))->GetCheck() != 0); } void CGeneralSettingsDlg::OnBnClickedAutoRunCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.auto_run = (((CButton*)GetDlgItem(IDC_AUTO_RUN_CHECK))->GetCheck() != 0); m_auto_run_modified = true; } void CGeneralSettingsDlg::OnBnClickedAllowSkinFontCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.allow_skin_cover_font = (((CButton*)GetDlgItem(IDC_ALLOW_SKIN_FONT_CHECK))->GetCheck() != 0); } void CGeneralSettingsDlg::OnBnClickedAllowSkinDispStrCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.allow_skin_cover_text = (((CButton*)GetDlgItem(IDC_ALLOW_SKIN_DISP_STR_CHECK))->GetCheck() != 0); } void CGeneralSettingsDlg::OnOK() { // TODO: 在此添加专用代码和/或调用基类 //获取消息提示的设置 m_data.traffic_tip_value = m_traffic_tip_edit.GetValue(); if (m_data.traffic_tip_value < 1) m_data.traffic_tip_value = 1; if (m_data.traffic_tip_value > 32767) m_data.traffic_tip_value = 32767; m_data.traffic_tip_unit = m_traffic_tip_combo.GetCurSel(); auto checkTipValue = [](int& value) { if (value < 1) value = 1; if (value > 100) value = 100; }; m_data.memory_usage_tip.tip_value = m_memory_tip_edit.GetValue(); checkTipValue(m_data.memory_usage_tip.tip_value); m_data.cpu_temp_tip.tip_value = m_cpu_temp_tip_edit.GetValue(); checkTipValue(m_data.cpu_temp_tip.tip_value); m_data.gpu_temp_tip.tip_value = m_gpu_temp_tip_edit.GetValue(); checkTipValue(m_data.gpu_temp_tip.tip_value); m_data.hdd_temp_tip.tip_value = m_hdd_temp_tip_edit.GetValue(); checkTipValue(m_data.hdd_temp_tip.tip_value); m_data.mainboard_temp_tip.tip_value = m_mbd_temp_tip_edit.GetValue(); checkTipValue(m_data.mainboard_temp_tip.tip_value); //获取语言的设置 m_data.language = static_cast(m_language_combo.GetCurSel()); if (m_data.language != theApp.m_general_data.language) { MessageBox(CCommon::LoadText(IDS_LANGUAGE_CHANGE_INFO), NULL, MB_ICONINFORMATION | MB_OK); } m_show_all_interface_modified = (m_data.show_all_interface != theApp.m_general_data.show_all_interface); //获取数据文件保存位置的设置 m_data.portable_mode = (((CButton*)GetDlgItem(IDC_SAVE_TO_PROGRAM_DIR_RADIO))->GetCheck() != 0); if (m_data.portable_mode != theApp.m_general_data.portable_mode) { MessageBox(CCommon::LoadText(IDS_CFG_DIR_CHANGED_INFO), NULL, MB_ICONINFORMATION | MB_OK); } m_data.monitor_time_span = m_monitor_span_edit.GetValue(); //m_taskbar_item_modified = (theApp.m_taskbar_data.m_tbar_display_item != taskbar_displat_item_ori); CTabDlg::OnOK(); } void CGeneralSettingsDlg::OnBnClickedTodayTrafficTipCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.traffic_tip_enable = (((CButton*)GetDlgItem(IDC_TODAY_TRAFFIC_TIP_CHECK))->GetCheck() != 0); SetControlEnable(); } void CGeneralSettingsDlg::OnBnClickedMemoryUsageTipCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.memory_usage_tip.enable = (((CButton*)GetDlgItem(IDC_MEMORY_USAGE_TIP_CHECK))->GetCheck() != 0); SetControlEnable(); } void CGeneralSettingsDlg::OnBnClickedOpenConfigPathButton() { // TODO: 在此添加控件通知处理程序代码 ShellExecute(NULL, _T("explore"), theApp.m_config_dir.c_str(), NULL, NULL, SW_SHOWNORMAL); } void CGeneralSettingsDlg::OnBnClickedShowAllConnectionCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.show_all_interface = (((CButton*)GetDlgItem(IDC_SHOW_ALL_CONNECTION_CHECK))->GetCheck() != 0); } BOOL CGeneralSettingsDlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 if (pMsg->message == WM_MOUSEMOVE) m_toolTip.RelayEvent(pMsg); return CTabDlg::PreTranslateMessage(pMsg); } void CGeneralSettingsDlg::OnBnClickedUseCpuTimeRadio() { // TODO: 在此添加控件通知处理程序代码 m_data.m_get_cpu_usage_by_cpu_times = true; } void CGeneralSettingsDlg::OnBnClickedUsePdhRadio() { // TODO: 在此添加控件通知处理程序代码 m_data.m_get_cpu_usage_by_cpu_times = false; } void CGeneralSettingsDlg::OnDeltaposSpin(NMHDR* pNMHDR, LRESULT* pResult) { //这里响应微调按钮(spin button)点击上下按钮时的事件, //CSpinButtonCtrl的对象是作为CSpinEdit的成员变量的,而此消息会向CSpinButtonCtrl的父窗口发送,但是CSpinEdit不是它的父窗口, //因此此消息无法在CSpinEdit中响应,只能在这里响应。 //所有CSpinEdit类中的Spin按钮点击时的响应都在这里,因为这些Spin按钮的ID都是“SPIN_ID”。 //通过GetBuddy的返回值判断微调按钮是属于哪个EditBox的。 CSpinButtonCtrl* pSpin = (CSpinButtonCtrl*)CWnd::FromHandle(pNMHDR->hwndFrom); if (pSpin == nullptr) return; CWnd* pEdit = pSpin->GetBuddy(); if (pEdit == &m_monitor_span_edit) //当用户点击了“监控时间间隔”的微调按钮时 { LPNMUPDOWN pNMUpDown = reinterpret_cast(pNMHDR); if (pNMUpDown->iDelta == -1) { // 用户按下了spin控件的向下箭头 int value = m_monitor_span_edit.GetValue(); value -= MONITOR_SPAN_STEP; value /= MONITOR_SPAN_STEP; value *= MONITOR_SPAN_STEP; m_monitor_span_edit.SetValue(value); } else if (pNMUpDown->iDelta == 1) { // 用户按下了spin控件的向上箭头 int value = m_monitor_span_edit.GetValue(); value += MONITOR_SPAN_STEP; value /= MONITOR_SPAN_STEP; value *= MONITOR_SPAN_STEP; m_monitor_span_edit.SetValue(value); } pNMUpDown->iDelta = 0; } *pResult = 0; } void CGeneralSettingsDlg::OnEnKillfocusMonitorSpanEdit() { // TODO: 在此添加控件通知处理程序代码 //这里限制监控时间间隔只能输入100的倍数 CString str; GetDlgItemText(IDC_MONITOR_SPAN_EDIT, str); str.Replace(_T(","), _T("")); int value = _ttoi(str.GetString()); if (value < MONITOR_TIME_SPAN_MIN || value > MONITOR_TIME_SPAN_MAX) { value = 1000; } else { value /= MONITOR_SPAN_STEP; value *= MONITOR_SPAN_STEP; } m_monitor_span_edit.SetValue(value); } void CGeneralSettingsDlg::OnBnClickedCpuTempTipCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.cpu_temp_tip.enable = (IsDlgButtonChecked(IDC_CPU_TEMP_TIP_CHECK) != 0); SetControlEnable(); } void CGeneralSettingsDlg::OnBnClickedGpuTempTipCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.gpu_temp_tip.enable = (IsDlgButtonChecked(IDC_GPU_TEMP_TIP_CHECK) != 0); SetControlEnable(); } void CGeneralSettingsDlg::OnBnClickedHddTempTipCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.hdd_temp_tip.enable = (IsDlgButtonChecked(IDC_HDD_TEMP_TIP_CHECK) != 0); SetControlEnable(); } void CGeneralSettingsDlg::OnBnClickedMbdTempTipCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.mainboard_temp_tip.enable = (IsDlgButtonChecked(IDC_MBD_TEMP_TIP_CHECK) != 0); SetControlEnable(); } void CGeneralSettingsDlg::OnBnClickedGithubRadio() { // TODO: 在此添加控件通知处理程序代码 m_data.update_source = 0; theApp.m_general_data.update_source = 0; //点击“更新源”的单选按钮时,同时更改theApp中的设置,以确保点击“立即检查”按钮时使用选择的更新源更新 } void CGeneralSettingsDlg::OnBnClickedGiteeRadio() { // TODO: 在此添加控件通知处理程序代码 m_data.update_source = 1; theApp.m_general_data.update_source = 1; } void CGeneralSettingsDlg::OnCancel() { // TODO: 在此添加专用代码和/或调用基类 theApp.m_general_data.update_source = m_update_source_ori; //点击“取消”时恢复开始的“更新源”选项 CTabDlg::OnCancel(); } void CGeneralSettingsDlg::OnBnClickedRestoreDefaultTimeSpanButton() { // TODO: 在此添加控件通知处理程序代码 m_monitor_span_edit.SetValue(1000); } void CGeneralSettingsDlg::OnCbnSelchangeSelectHardDiskCombo() { // TODO: 在此添加控件通知处理程序代码 CString hard_disk_name; m_hard_disk_combo.GetWindowText(hard_disk_name); m_data.hard_disk_name = hard_disk_name.GetString(); } void CGeneralSettingsDlg::OnBnClickedCpuCheck() { // TODO: 在此添加控件通知处理程序代码 bool checked = IsDlgButtonChecked(IDC_CPU_CHECK) != 0; if (checked && !ShowHardwareMonitorWarning()) { checked = false; CheckDlgButton(IDC_CPU_CHECK, FALSE); } m_data.SetHardwareEnable(HI_CPU, checked); } void CGeneralSettingsDlg::OnBnClickedGpuCheck() { // TODO: 在此添加控件通知处理程序代码 bool checked = IsDlgButtonChecked(IDC_GPU_CHECK) != 0; if (checked && !ShowHardwareMonitorWarning()) { checked = false; CheckDlgButton(IDC_GPU_CHECK, FALSE); } m_data.SetHardwareEnable(HI_GPU, checked); } void CGeneralSettingsDlg::OnBnClickedHddCheck() { // TODO: 在此添加控件通知处理程序代码 bool checked = IsDlgButtonChecked(IDC_HDD_CHECK) != 0; if (checked && !ShowHardwareMonitorWarning()) { checked = false; CheckDlgButton(IDC_HDD_CHECK, FALSE); } m_data.SetHardwareEnable(HI_HDD, checked); } void CGeneralSettingsDlg::OnBnClickedMbdCheck() { // TODO: 在此添加控件通知处理程序代码 bool checked = IsDlgButtonChecked(IDC_MBD_CHECK) != 0; if (checked && !ShowHardwareMonitorWarning()) { checked = false; CheckDlgButton(IDC_MBD_CHECK, FALSE); } m_data.SetHardwareEnable(HI_MBD, checked); } void CGeneralSettingsDlg::OnCbnSelchangeSelectCpuCombo() { // TODO: 在此添加控件通知处理程序代码 CString cpu_core_name; m_select_cpu_combo.GetWindowText(cpu_core_name); m_data.cpu_core_name = cpu_core_name.GetString(); } void CGeneralSettingsDlg::OnBnClickedPluginManageButton() { // TODO: 在此添加控件通知处理程序代码 CPluginManagerDlg dlg; dlg.DoModal(); } void CGeneralSettingsDlg::OnBnClickedShowNotifyIconCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.show_notify_icon = (IsDlgButtonChecked(IDC_SHOW_NOTIFY_ICON_CHECK) != 0); } void CGeneralSettingsDlg::OnBnClickedSelectConnectionsButton() { // TODO: 在此添加控件通知处理程序代码 CSelectConnectionsDlg dlg(m_data.connections_hide); if (dlg.DoModal() == IDOK) { m_data.connections_hide = dlg.GetData(); } } void CGeneralSettingsDlg::OnBnClickedResetAutoRunButton() { //先删除开机自动运行 theApp.SetAutoRunByRegistry(false); theApp.SetAutoRunByTaskScheduler(false); if (!theApp.SetAutoRun(true)) //重新设置开机自动运行 { MessageBox(CCommon::LoadText(IDS_SET_AUTO_RUN_FAILED_WARNING), NULL, MB_ICONWARNING | MB_OK); return; } //获取开机自动运行的路径 bool auto_run = theApp.GetAutoRun(&m_auto_run_path); //重新勾选“开机自动运行”复选框 CheckDlgButton(IDC_AUTO_RUN_CHECK, auto_run); //更新鼠标提示 AddOrUpdateAutoRunTooltip(false); } ================================================ FILE: TrafficMonitor/GeneralSettingsDlg.h ================================================ #pragma once #include "TabDlg.h" #include "SpinEdit.h" #include "ComboBox2.h" // CGeneralSettingsDlg dialog class CGeneralSettingsDlg : public CTabDlg { DECLARE_DYNAMIC(CGeneralSettingsDlg) public: CGeneralSettingsDlg(CWnd* pParent = NULL); // standard constructor virtual ~CGeneralSettingsDlg(); static void CheckTaskbarDisplayItem(); //选项设置数据 GeneralSettingData m_data; // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_GENERAL_SETTINGS_DIALOG }; #endif public: bool IsAutoRunModified() const { return m_auto_run_modified; } bool IsShowAllInterfaceModified() const { return m_show_all_interface_modified; } bool IsMonitorTimeSpanModified() const; //bool IsTaskbarItemModified() const { return m_taskbar_item_modified; } protected: bool m_auto_run_modified{ false }; //如果更改了开机自动运行的设置,则会置为true bool m_show_all_interface_modified{ false }; int m_monitor_time_span_ori{}; int m_update_source_ori{}; //bool m_taskbar_item_modified{ false }; wstring m_auto_run_path; //控件变量 CSpinEdit m_traffic_tip_edit; CComboBox2 m_traffic_tip_combo; CSpinEdit m_memory_tip_edit; CComboBox2 m_language_combo; CToolTipCtrl m_toolTip; CSpinEdit m_monitor_span_edit; CSpinEdit m_cpu_temp_tip_edit; CSpinEdit m_gpu_temp_tip_edit; CSpinEdit m_hdd_temp_tip_edit; CSpinEdit m_mbd_temp_tip_edit; CComboBox2 m_hard_disk_combo; CComboBox2 m_select_cpu_combo; CButton m_plugin_manager_btn; CButton m_select_connection_btn; virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //设置控件的启用和禁用 void SetControlEnable(); virtual void SetControlMouseWheelEnable(bool enable) override; //显示开启硬件监控时的提示,如果用户选择了“是”则返回true,否则返回false //“以后不再显示该对话框”的标记保存在注册表“\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\DontShowMeThisDialogAgain” bool ShowHardwareMonitorWarning(); //添加或更新开机自动运行的鼠标提示 void AddOrUpdateAutoRunTooltip(bool add); DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnBnClickedCheckNowButton(); afx_msg void OnBnClickedCheckUpdateCheck(); afx_msg void OnBnClickedAutoRunCheck(); afx_msg void OnBnClickedAllowSkinFontCheck(); afx_msg void OnBnClickedAllowSkinDispStrCheck(); virtual void OnOK(); afx_msg void OnBnClickedTodayTrafficTipCheck(); afx_msg void OnBnClickedMemoryUsageTipCheck(); afx_msg void OnBnClickedOpenConfigPathButton(); afx_msg void OnBnClickedShowAllConnectionCheck(); virtual BOOL PreTranslateMessage(MSG* pMsg); afx_msg void OnBnClickedUseCpuTimeRadio(); afx_msg void OnBnClickedUsePdhRadio(); afx_msg void OnDeltaposSpin(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnEnKillfocusMonitorSpanEdit(); afx_msg void OnBnClickedCpuTempTipCheck(); afx_msg void OnBnClickedGpuTempTipCheck(); afx_msg void OnBnClickedHddTempTipCheck(); afx_msg void OnBnClickedMbdTempTipCheck(); afx_msg void OnBnClickedGithubRadio(); afx_msg void OnBnClickedGiteeRadio(); virtual void OnCancel(); afx_msg void OnBnClickedRestoreDefaultTimeSpanButton(); afx_msg void OnCbnSelchangeSelectHardDiskCombo(); afx_msg void OnBnClickedCpuCheck(); afx_msg void OnBnClickedGpuCheck(); afx_msg void OnBnClickedHddCheck(); afx_msg void OnBnClickedMbdCheck(); afx_msg void OnCbnSelchangeSelectCpuCombo(); afx_msg void OnBnClickedPluginManageButton(); afx_msg void OnBnClickedShowNotifyIconCheck(); afx_msg void OnBnClickedSelectConnectionsButton(); afx_msg void OnBnClickedResetAutoRunButton(); }; ================================================ FILE: TrafficMonitor/HighResolutionTimer.h ================================================ #include #pragma comment(lib, "WINMM.LIB") class CHighResolutionTimer { typedef void(*TIMERCALLBACK)(DWORD_PTR); private: DWORD_PTR m_dwUser; MMRESULT m_nIDTimer; UINT m_uDelay; TIMERCALLBACK m_pfnCallback; public: void KillTimer() { if (m_nIDTimer != NULL) { timeKillEvent(m_nIDTimer); m_nIDTimer = NULL; } } CHighResolutionTimer() { m_nIDTimer = NULL; m_uDelay = 0; m_pfnCallback = 0; } virtual ~CHighResolutionTimer() { KillTimer(); } static void CALLBACK TimeProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { // dwUser contains ptr to Timer object CHighResolutionTimer * ptimer = (CHighResolutionTimer *)dwUser; // Call user-specified callback and pass back user specified data (ptimer->m_pfnCallback) (ptimer->m_dwUser); } BOOL CreateTimer(DWORD_PTR dwUser, UINT uDelay, TIMERCALLBACK lpTimeProc) { ASSERT(dwUser); ASSERT(lpTimeProc); m_dwUser = dwUser; m_pfnCallback = lpTimeProc; BOOL ret = FALSE; KillTimer(); m_nIDTimer = timeSetEvent(uDelay, 0, (LPTIMECALLBACK)TimeProc, (DWORD_PTR)this, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); if (m_nIDTimer != NULL) ret = TRUE; return(ret); } }; ================================================ FILE: TrafficMonitor/HistoryTrafficCalendarDlg.cpp ================================================ // HistoryTrafficCalendarDlg.cpp: 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "HistoryTrafficCalendarDlg.h" #include "afxdialogex.h" // CHistoryTrafficCalendarDlg 对话框 IMPLEMENT_DYNAMIC(CHistoryTrafficCalendarDlg, CTabDlg) CHistoryTrafficCalendarDlg::CHistoryTrafficCalendarDlg(deque& history_traffics, CWnd* pParent /*=nullptr*/) : CTabDlg(IDD_HISTORY_TRAFFIC_CALENDAR_DIALOG, pParent), m_history_traffics(history_traffics) { } CHistoryTrafficCalendarDlg::~CHistoryTrafficCalendarDlg() { } void CHistoryTrafficCalendarDlg::SetDayTraffic() { for (int i{}; i < CALENDAR_HEIGHT; i++) { for (int j{}; j < CALENDAR_WIDTH; j++) { HistoryTraffic history_traffic; history_traffic.year = m_year; history_traffic.month = m_month; history_traffic.day = m_calendar[i][j].day; //使用二分法查找日历中每一个日期的流量 if (history_traffic.day > 0) { if (std::binary_search(m_history_traffics.begin(), m_history_traffics.end(), history_traffic, HistoryTraffic::DateGreater)) { auto iter = std::lower_bound(m_history_traffics.begin(), m_history_traffics.end(), history_traffic, HistoryTraffic::DateGreater); if (iter != m_history_traffics.end()) { m_calendar[i][j].up_traffic = iter->up_kBytes; m_calendar[i][j].down_traffic = iter->down_kBytes; m_calendar[i][j].mixed = iter->mixed; } } } } } } void CHistoryTrafficCalendarDlg::MonthSelectChanged() { CCalendarHelper::GetCalendar(m_year, m_month, m_calendar, theApp.m_cfg_data.m_sunday_first); SetDayTraffic(); CalculateMonthTotalTraffic(); InvalidateRect(m_draw_rect); } void CHistoryTrafficCalendarDlg::CalculateMonthTotalTraffic() { m_month_total_upload = 0; m_month_total_download = 0; for (int i{}; i < CALENDAR_HEIGHT; i++) { for (int j{}; j < CALENDAR_WIDTH; j++) { m_month_total_upload += m_calendar[i][j].up_traffic; m_month_total_download += m_calendar[i][j].down_traffic; } } } void CHistoryTrafficCalendarDlg::SetComboSel() { int cnt{}; int year_selected; for (int i{ m_year_max }; i >= m_year_min; i--) { if (i == m_year) year_selected = cnt; cnt++; } m_year_combo.SetCurSel(year_selected); m_month_combo.SetCurSel(m_month - 1); } void CHistoryTrafficCalendarDlg::DoDataExchange(CDataExchange* pDX) { CTabDlg::DoDataExchange(pDX); DDX_Control(pDX, IDC_YEAR_COMBO, m_year_combo); DDX_Control(pDX, IDC_MONTH_COMBO, m_month_combo); } bool CHistoryTrafficCalendarDlg::IsWeekend(int index) { if (theApp.m_cfg_data.m_sunday_first) return (index == 0 || index == 6); else return (index == 5 || index == 6); } CString CHistoryTrafficCalendarDlg::GetWeekdayString(int index) { CString str; if (!theApp.m_cfg_data.m_sunday_first) { index++; if (index > 6) index = 0; } switch (index) { case 0: str.LoadString(IDS_SUNDAY); break; case 1: str.LoadString(IDS_MONDAY); break; case 2: str.LoadString(IDS_TUESDAY); break; case 3: str.LoadString(IDS_WEDNESDAY); break; case 4: str.LoadString(IDS_THURSDAY); break; case 5: str.LoadString(IDS_FRIDAY); break; case 6: str.LoadString(IDS_SATURDAY); break; } return str; } BEGIN_MESSAGE_MAP(CHistoryTrafficCalendarDlg, CTabDlg) ON_WM_PAINT() ON_CBN_SELCHANGE(IDC_YEAR_COMBO, &CHistoryTrafficCalendarDlg::OnCbnSelchangeYearCombo) ON_CBN_SELCHANGE(IDC_MONTH_COMBO, &CHistoryTrafficCalendarDlg::OnCbnSelchangeMonthCombo) ON_WM_MOUSEMOVE() ON_BN_CLICKED(IDC_PREVIOUS_BUTTON, &CHistoryTrafficCalendarDlg::OnBnClickedPreviousButton) ON_BN_CLICKED(IDC_NEXT_BUTTON, &CHistoryTrafficCalendarDlg::OnBnClickedNextButton) ON_WM_MOUSEWHEEL() ON_BN_CLICKED(IDC_MENU_BUTTON, &CHistoryTrafficCalendarDlg::OnBnClickedMenuButton) ON_WM_INITMENU() ON_COMMAND(ID_FIRST_DAY_OF_WEEK_SUNDAY, &CHistoryTrafficCalendarDlg::OnFirstDayOfWeekSunday) ON_COMMAND(ID_FIRST_DAY_OF_WEEK_MONDAY, &CHistoryTrafficCalendarDlg::OnFirstDayOfWeekMonday) ON_COMMAND(ID_CALENDAR_JUMP_TO_TODAY, &CHistoryTrafficCalendarDlg::OnCalendarJumpToToday) END_MESSAGE_MAP() // CHistoryTrafficCalendarDlg 消息处理程序 BOOL CHistoryTrafficCalendarDlg::OnInitDialog() { CTabDlg::OnInitDialog(); // TODO: 在此添加额外的初始化 m_year = m_history_traffics[0].year; m_month = m_history_traffics[0].month; CCalendarHelper::GetCalendar(m_year, m_month, m_calendar, theApp.m_cfg_data.m_sunday_first); SetDayTraffic(); CalculateMonthTotalTraffic(); //初始化Combo Box m_year_max = m_history_traffics[0].year; m_year_min = m_history_traffics.back().year; for (int i{ m_year_max }; i >= m_year_min; i--) { m_year_combo.AddString(CCommon::IntToString(i)); } m_year_combo.SetCurSel(0); for (int i{ 1 }; i <= 12; i++) { m_month_combo.AddString(CCommon::IntToString(i)); } m_month_combo.SetCurSel(m_month - 1); //初始化鼠标提示 m_tool_tips.Create(this, TTS_ALWAYSTIP | TTS_NOPREFIX); m_tool_tips.SetMaxTipWidth(800); //为鼠标提示设置一个最大宽度,以允许其换行 m_tool_tips.AddTool(this, _T("")); m_menu.LoadMenu(IDR_HISTORY_TRAFFIC_MENU); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CHistoryTrafficCalendarDlg::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CTabDlg::OnPaint() CRect wndRect; GetWindowRect(wndRect); const int width = theApp.DPI(40); //日历中每一个格子的宽度 const int height = theApp.DPI(30); //日历中第一个格子的高度 m_draw_rect.left = m_start_x; m_draw_rect.top = m_start_y; //m_draw_rect.right = m_draw_rect.left + (CALENDAR_WIDTH*width); m_draw_rect.right = wndRect.Width() - m_start_x; m_draw_rect.bottom = m_draw_rect.top + ((CALENDAR_HEIGHT + 2) * height) + theApp.DPI(20); //使用双缓冲绘图 CDrawDoubleBuffer draw_double_buffer(&dc, m_draw_rect); //绘图 CDrawCommon draw; draw.Create(draw_double_buffer.GetMemDC(), this); draw.FillRect(CRect(0, 0, m_draw_rect.Width(), m_draw_rect.Height()), RGB(255, 255, 255)); //填充白色背景色 CRect rect{}; rect.left = 0; rect.top = 0; rect.right = rect.left + width; rect.bottom = rect.top + height; //画星期的行 for (int i{}; i < CALENDAR_WIDTH; i++) { rect.MoveToX(i * width); if (IsWeekend(i)) draw.SetBackColor(RGB(217, 86, 86)); else if (i % 2 == 0) draw.SetBackColor(RGB(1, 84, 151)); else draw.SetBackColor(RGB(1, 107, 191)); CString str = GetWeekdayString(i); draw.DrawWindowText(rect, str, RGB(255, 255, 255), Alignment::CENTER, true); } //绘制日历 for (int i{}; i < CALENDAR_HEIGHT; i++) { for (int j{}; j < CALENDAR_WIDTH; j++) { //设置日历中每一天的矩形的位置 rect.MoveToXY(j * width, height + theApp.DPI(2) + i * height); //保存矩形的位置 m_calendar[i][j].rect = rect; //绘制日期的数据 //绘制格子的背景颜色 if (IsWeekend(j)) //是周末时 { if ((i + j) % 2 == 0) draw.SetBackColor(RGB(250, 234, 234)); else draw.SetBackColor(RGB(252, 242, 242)); } else { if ((i + j) % 2 == 0) draw.SetBackColor(RGB(226, 241, 254)); else draw.SetBackColor(RGB(236, 246, 254)); } draw.FillRectWithBackColor(rect); //绘制格子上的日期的数字 CRect day_rect{ rect }; day_rect.bottom -= (rect.Height() / 2); COLORREF text_color; if (IsWeekend(j)) text_color = RGB(131, 29, 28); else text_color = RGB(0, 57, 107); if (m_calendar[i][j].day != 0) draw.DrawWindowText(day_rect, CCommon::IntToString(m_calendar[i][j].day), text_color, Alignment::CENTER, true); //在今天的日期上画一个矩形框 COLORREF frame_color; if (IsWeekend(j)) frame_color = RGB(218, 91, 91); else frame_color = RGB(1, 133, 238); if (m_year == m_history_traffics[0].year && m_month == m_history_traffics[0].month && m_calendar[i][j].day == m_history_traffics[0].day) draw.DrawRectOutLine(rect, frame_color, theApp.DPI(2)); //绘制指示流量大小的矩形 COLORREF color; if (m_calendar[i][j].traffic() < 1024 * 1024) //流量小于1GB时绘制蓝色 color = TRAFFIC_COLOR_BLUE; else if (m_calendar[i][j].traffic() < 10 * 1024 * 1024) //流量小于10GB时绘制绿色 color = TRAFFIC_COLOR_GREEN; else if (m_calendar[i][j].traffic() < 100 * 1024 * 1024) //流量小于100GB时绘制黄色 color = TRAFFIC_COLOR_YELLOE; else if (m_calendar[i][j].traffic() < 1024 * 1024 * 1024) //流量小于1TB时绘制红色 color = TRAFFIC_COLOR_RED; else //流量超过1TB时显示深红色 color = TRAFFIC_COLOR_DARK_RED; if (m_calendar[i][j].traffic() > 0) { CRect traffic_rect; traffic_rect.left = rect.left + theApp.DPI(14); traffic_rect.right = traffic_rect.left + theApp.DPI(12); traffic_rect.top = rect.top + theApp.DPI(16); traffic_rect.bottom = traffic_rect.top + theApp.DPI(12); draw.FillRect(traffic_rect, color); } } } const COLORREF text_color{ RGB(0, 57, 107) }; //画当前月总流量 CString info; info.Format(_T("%s %s (%s: %s, %s: %s)"), CCommon::LoadText(IDS_CURRENT_MONTH_TOTAL_TRAFFIC), CCommon::KBytesToString(m_month_total_upload + m_month_total_download), CCommon::LoadText(IDS_UPLOAD), CCommon::KBytesToString(m_month_total_upload), CCommon::LoadText(IDS_DOWNLOAD), CCommon::KBytesToString(m_month_total_download) ); CRect info_rect; info_rect.left = 0; info_rect.top = height * (CALENDAR_HEIGHT + 1) + theApp.DPI(5); info_rect.right = info_rect.left + m_draw_rect.Width(); info_rect.bottom = info_rect.top + theApp.DPI(36); draw.SetBackColor(RGB(255, 255, 255)); draw.DrawWindowText(info_rect, info, text_color, Alignment::LEFT, true, true); //画图例 CRect rc_legend{ info_rect }; rc_legend.MoveToXY(CALENDAR_WIDTH * width + theApp.DPI(32), theApp.DPI(16)); rc_legend.right = m_draw_rect.Width(); rc_legend.bottom = rc_legend.top + theApp.DPI(16); draw.DrawWindowText(rc_legend, CCommon::LoadText(IDS_LEGEND, _T(":")), text_color, Alignment::LEFT, true, true); rc_legend.MoveToY(rc_legend.bottom + theApp.DPI(6)); CRect rc_legend_box{ rc_legend }; const int box_side{ theApp.DPI(12) }; const int line_gap{ theApp.DPI(6) }; rc_legend_box.top = rc_legend.top + (rc_legend.Height() - box_side) / 2; rc_legend_box.bottom = rc_legend_box.top + box_side; rc_legend_box.right = rc_legend_box.left + box_side; rc_legend.left = rc_legend_box.right + theApp.DPI(4); //蓝色图例 draw.FillRect(rc_legend_box, TRAFFIC_COLOR_BLUE); draw.DrawWindowText(rc_legend, _T("0~1GB"), text_color); //绿色图例 rc_legend.MoveToY(rc_legend.bottom + line_gap); rc_legend_box.MoveToY(rc_legend.top + (rc_legend.Height() - box_side) / 2); draw.FillRect(rc_legend_box, TRAFFIC_COLOR_GREEN); draw.DrawWindowText(rc_legend, _T("1GB~10GB"), text_color); //黄色图例 rc_legend.MoveToY(rc_legend.bottom + line_gap); rc_legend_box.MoveToY(rc_legend.top + (rc_legend.Height() - box_side) / 2); draw.FillRect(rc_legend_box, TRAFFIC_COLOR_YELLOE); draw.DrawWindowText(rc_legend, _T("10GB~100GB"), text_color); //红色图例 rc_legend.MoveToY(rc_legend.bottom + line_gap); rc_legend_box.MoveToY(rc_legend.top + (rc_legend.Height() - box_side) / 2); draw.FillRect(rc_legend_box, TRAFFIC_COLOR_RED); draw.DrawWindowText(rc_legend, _T("100GB~1TB"), text_color); //深红色图例 rc_legend.MoveToY(rc_legend.bottom + line_gap); rc_legend_box.MoveToY(rc_legend.top + (rc_legend.Height() - box_side) / 2); draw.FillRect(rc_legend_box, TRAFFIC_COLOR_DARK_RED); draw.DrawWindowText(rc_legend, _T("1TB~"), text_color); } void CHistoryTrafficCalendarDlg::OnCbnSelchangeYearCombo() { // TODO: 在此添加控件通知处理程序代码 int index = m_year_combo.GetCurSel(); CString str; m_year_combo.GetLBText(index, str); m_year = _ttoi(str); MonthSelectChanged(); } void CHistoryTrafficCalendarDlg::OnCbnSelchangeMonthCombo() { // TODO: 在此添加控件通知处理程序代码 m_month = m_month_combo.GetCurSel() + 1; MonthSelectChanged(); } void CHistoryTrafficCalendarDlg::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 int tip_day{}; //要显示鼠标提示的日期 DayTraffic tip_traffic{}; static int last_tip_day{}; //查找鼠标指针在哪个日期的矩形内 for (int i{}; i < CALENDAR_HEIGHT; i++) { for (int j{}; j < CALENDAR_WIDTH; j++) { CRect rect{ m_calendar[i][j].rect }; rect.OffsetRect(m_start_x, m_start_y); if (rect.PtInRect(point)) { tip_day = m_calendar[i][j].day; tip_traffic = m_calendar[i][j]; } } } bool show_tip = (tip_day > 0); if (show_tip && last_tip_day != tip_day) { CString tip_info; tip_info.Format(_T("%d/%d/%d\r\n"), m_year, m_month, tip_day); tip_info += CCommon::LoadText(IDS_TRAFFIC_USED1); tip_info += CCommon::KBytesToString(tip_traffic.traffic()); if (!tip_traffic.mixed && tip_traffic.traffic() > 0) { tip_info += _T("\r\n"); tip_info += CCommon::LoadText(IDS_UPLOAD, _T(": ")); tip_info += CCommon::KBytesToString(tip_traffic.up_traffic); tip_info += _T("\r\n"); tip_info += CCommon::LoadText(IDS_DOWNLOAD, _T(": ")); tip_info += CCommon::KBytesToString(tip_traffic.down_traffic); } m_tool_tips.AddTool(this, tip_info); m_tool_tips.Pop(); last_tip_day = tip_day; } if (!show_tip) { m_tool_tips.AddTool(this, _T("")); m_tool_tips.Pop(); last_tip_day = 0; } CTabDlg::OnMouseMove(nFlags, point); } BOOL CHistoryTrafficCalendarDlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 if (m_tool_tips.GetSafeHwnd() != 0) { m_tool_tips.RelayEvent(pMsg); } if (pMsg->message == WM_KEYDOWN) { if (pMsg->wParam == VK_LEFT) { OnBnClickedPreviousButton(); return TRUE; } if (pMsg->wParam == VK_RIGHT) { OnBnClickedNextButton(); return TRUE; } } return CTabDlg::PreTranslateMessage(pMsg); } void CHistoryTrafficCalendarDlg::OnBnClickedPreviousButton() { // TODO: 在此添加控件通知处理程序代码 if (m_year == m_year_min && m_month == 1) return; m_month--; if (m_month <= 0) { m_month = 12; m_year--; } SetComboSel(); MonthSelectChanged(); } void CHistoryTrafficCalendarDlg::OnBnClickedNextButton() { // TODO: 在此添加控件通知处理程序代码 if (m_year == m_year_max && m_month == 12) return; m_month++; if (m_month > 12) { m_month = 1; m_year++; } SetComboSel(); MonthSelectChanged(); } BOOL CHistoryTrafficCalendarDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //通过鼠标滚轮翻页 if (zDelta > 0) { OnBnClickedPreviousButton(); } if (zDelta < 0) { OnBnClickedNextButton(); } return CTabDlg::OnMouseWheel(nFlags, zDelta, pt); } void CHistoryTrafficCalendarDlg::OnBnClickedMenuButton() { // TODO: 在此添加控件通知处理程序代码 CWnd* pBtn = GetDlgItem(IDC_MENU_BUTTON); if (pBtn != nullptr) { CRect rect; pBtn->GetWindowRect(rect); CPoint point; point.x = rect.left; point.y = rect.bottom; CMenu* pMenu = m_menu.GetSubMenu(1); if (pMenu != NULL) pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this); } } void CHistoryTrafficCalendarDlg::OnInitMenu(CMenu* pMenu) { CTabDlg::OnInitMenu(pMenu); // TODO: 在此处添加消息处理程序代码 if (theApp.m_cfg_data.m_sunday_first) pMenu->CheckMenuRadioItem(ID_FIRST_DAY_OF_WEEK_SUNDAY, ID_FIRST_DAY_OF_WEEK_MONDAY, ID_FIRST_DAY_OF_WEEK_SUNDAY, MF_BYCOMMAND | MF_CHECKED); else pMenu->CheckMenuRadioItem(ID_FIRST_DAY_OF_WEEK_SUNDAY, ID_FIRST_DAY_OF_WEEK_MONDAY, ID_FIRST_DAY_OF_WEEK_MONDAY, MF_BYCOMMAND | MF_CHECKED); } void CHistoryTrafficCalendarDlg::OnFirstDayOfWeekSunday() { // TODO: 在此添加命令处理程序代码 theApp.m_cfg_data.m_sunday_first = true; MonthSelectChanged(); } void CHistoryTrafficCalendarDlg::OnFirstDayOfWeekMonday() { // TODO: 在此添加命令处理程序代码 theApp.m_cfg_data.m_sunday_first = false; MonthSelectChanged(); } void CHistoryTrafficCalendarDlg::OnCalendarJumpToToday() { // TODO: 在此添加命令处理程序代码 m_year = m_history_traffics[0].year; m_month = m_history_traffics[0].month; SetComboSel(); MonthSelectChanged(); } ================================================ FILE: TrafficMonitor/HistoryTrafficDlg.cpp ================================================ // HistoryTrafficDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "HistoryTrafficDlg.h" #include "afxdialogex.h" // CHistoryTrafficDlg 对话框 IMPLEMENT_DYNAMIC(CHistoryTrafficDlg, CBaseDialog) CHistoryTrafficDlg::CHistoryTrafficDlg(deque& history_traffics, CWnd* pParent /*=NULL*/) : CBaseDialog(IDD_HISTORY_TRAFFIC_DIALOG, pParent), m_history_traffics(history_traffics), m_tab1_dlg(history_traffics, this), m_tab2_dlg(history_traffics, this) { } CHistoryTrafficDlg::~CHistoryTrafficDlg() { } CString CHistoryTrafficDlg::GetDialogName() const { return _T("HistoryTrafficDlg"); } void CHistoryTrafficDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_TAB1, m_tab); } void CHistoryTrafficDlg::SetTabWndSize() { CRect rect; m_tab.GetClientRect(rect); CRect rcTabItem; m_tab.GetItemRect(0, rcTabItem); rect.top += rcTabItem.Height() + 4; rect.left += 4; rect.bottom -= 4; rect.right -= 4; m_tab1_dlg.MoveWindow(&rect); m_tab2_dlg.MoveWindow(&rect); } BEGIN_MESSAGE_MAP(CHistoryTrafficDlg, CBaseDialog) ON_WM_GETMINMAXINFO() ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, &CHistoryTrafficDlg::OnTcnSelchangeTab1) ON_WM_SIZE() END_MESSAGE_MAP() // CHistoryTrafficDlg 消息处理程序 BOOL CHistoryTrafficDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetWindowText(CCommon::LoadText(IDS_TITLE_HISTORY_TRAFFIC)); SetIcon(theApp.GetMenuIcon(IDI_STATISTICS), FALSE); // 设置小图标 //插入标签 m_tab.InsertItem(0, CCommon::LoadText(IDS_LIST_VIEW)); m_tab.InsertItem(1, CCommon::LoadText(IDS_CALENDAR_VIEW)); //创建子对话框 m_tab1_dlg.Create(IDD_HISTORY_TRAFFIC_LIST_DIALOG, &m_tab); m_tab2_dlg.Create(IDD_HISTORY_TRAFFIC_CALENDAR_DIALOG, &m_tab); //调整子对话框的大小和位置 SetTabWndSize(); //设置默认选中的标签 switch (m_tab_selected) { case 0: m_tab1_dlg.ShowWindow(SW_SHOW); break; case 1: m_tab2_dlg.ShowWindow(SW_SHOW); break; } m_tab.SetCurFocus(m_tab_selected); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } BOOL CHistoryTrafficDlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 //if (GetKeyState(VK_CONTROL) & 0x80) //{ // if (pMsg->wParam == 'D') // { // HistoryTraffic h{}; // h.year = 2018; // h.month = 4; // h.day = 29; // auto iter = std::lower_bound(m_history_traffics.begin(), m_history_traffics.end(), h, HistoryTraffic::DateGreater); // int index = iter - m_history_traffics.begin(); // } //} return CBaseDialog::PreTranslateMessage(pMsg); } void CHistoryTrafficDlg::OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult) { // TODO: 在此添加控件通知处理程序代码 m_tab_selected = m_tab.GetCurSel(); switch (m_tab_selected) { case 0: m_tab1_dlg.ShowWindow(SW_SHOW); m_tab2_dlg.ShowWindow(SW_HIDE); m_tab1_dlg.SetFocus(); break; case 1: m_tab2_dlg.ShowWindow(SW_SHOW); m_tab1_dlg.ShowWindow(SW_HIDE); m_tab2_dlg.SetFocus(); break; } *pResult = 0; } void CHistoryTrafficDlg::OnSize(UINT nType, int cx, int cy) { CBaseDialog::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 if (nType != SIZE_MINIMIZED && m_tab1_dlg.GetSafeHwnd() != NULL && m_tab2_dlg.GetSafeHwnd() != NULL) { SetTabWndSize(); } } ================================================ FILE: TrafficMonitor/HistoryTrafficDlg.h ================================================ #pragma once #include "afxcmn.h" #include "Common.h" #include "HistoryTrafficListDlg.h" #include "HistoryTrafficCalendarDlg.h" #include "BaseDialog.h" // CHistoryTrafficDlg 对话框 class CHistoryTrafficDlg : public CBaseDialog { DECLARE_DYNAMIC(CHistoryTrafficDlg) public: CHistoryTrafficDlg(deque& history_traffics, CWnd* pParent = NULL); // 标准构造函数 virtual ~CHistoryTrafficDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_HISTORY_TRAFFIC_DIALOG }; #endif public: CHistoryTrafficListDlg m_tab1_dlg; CHistoryTrafficCalendarDlg m_tab2_dlg; protected: deque& m_history_traffics; CTabCtrl m_tab; int m_tab_selected; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 void SetTabWndSize(); virtual CString GetDialogName() const override; DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); virtual BOOL PreTranslateMessage(MSG* pMsg); afx_msg void OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnSize(UINT nType, int cx, int cy); }; ================================================ FILE: TrafficMonitor/HistoryTrafficFile.cpp ================================================ #include "stdafx.h" #include "HistoryTrafficFile.h" #include "Common.h" CHistoryTrafficFile::CHistoryTrafficFile(const wstring& file_path) : m_file_path(file_path) { } CHistoryTrafficFile::~CHistoryTrafficFile() { } void CHistoryTrafficFile::Save() const { ofstream file{ m_file_path }; char buff[64]; sprintf_s(buff, "lines: \"%u\"", static_cast(m_history_traffics.size())); //ڵһд file << buff << std::endl; for (const auto& history_traffic : m_history_traffics) { if (history_traffic.mixed) sprintf_s(buff, "%.4d/%.2d/%.2d %llu", history_traffic.year, history_traffic.month, history_traffic.day, history_traffic.down_kBytes); else sprintf_s(buff, "%.4d/%.2d/%.2d %llu/%llu", history_traffic.year, history_traffic.month, history_traffic.day, history_traffic.up_kBytes, history_traffic.down_kBytes); file << buff << std::endl; } file.close(); } void CHistoryTrafficFile::Load() { ifstream file{ m_file_path }; string current_line, temp; HistoryTraffic traffic; //bool first_line{ true }; if (CCommon::FileExist(m_file_path.c_str())) { while (!file.eof()) { if (m_history_traffics.size() > 9999) break; //ȡ10000ʷ¼ std::getline(file, current_line); //if (first_line) //{ // first_line = false; // size_t index = current_line.find("lines:"); // if(index != wstring::npos) // { // index = current_line.find("\"", index + 6); // size_t index1 = current_line.find("\"", index + 1); // temp = current_line.substr(index + 1, index1 - index - 1); // m_size = atoll(temp.c_str()); // continue; // } //} if (current_line.size() < 12) continue; temp = current_line.substr(0, 4); traffic.year = atoi(temp.c_str()); if (traffic.year < 1900 || traffic.year > 3000) continue; temp = current_line.substr(5, 2); traffic.month = atoi(temp.c_str()); if (traffic.month < 1 || traffic.month > 12) continue; temp = current_line.substr(8, 2); traffic.day = atoi(temp.c_str()); if (traffic.day < 1 || traffic.day > 31) continue; int index = current_line.find(L'/', 11); traffic.mixed = (index == wstring::npos); if (traffic.mixed) { temp = current_line.substr(11); traffic.down_kBytes = atoll(temp.c_str()); traffic.up_kBytes = 0; } else { temp = current_line.substr(11, index - 11); traffic.up_kBytes = atoll(temp.c_str()); temp = current_line.substr(index + 1); traffic.down_kBytes = atoll(temp.c_str()); } if (traffic.year > 0 && traffic.month > 0 && traffic.day > 0 && traffic.kBytes() > 0) m_history_traffics.push_back(traffic); } } MormalizeData(); } void CHistoryTrafficFile::LoadSize() { ifstream file{ m_file_path }; string current_line, temp; if (CCommon::FileExist(m_file_path.c_str())) { std::getline(file, current_line); //ȡһ size_t index = current_line.find("lines:"); if (index != wstring::npos) { index = current_line.find("\"", index + 6); size_t index1 = current_line.find("\"", index + 1); temp = current_line.substr(index + 1, index1 - index - 1); m_size = atoll(temp.c_str()); } } } void CHistoryTrafficFile::Merge(const CHistoryTrafficFile& history_traffic, bool ignore_same_data) { for (const HistoryTraffic& traffic : history_traffic.m_history_traffics) { if(ignore_same_data) { //Ҫͬڵʹöַͬҵˣ if (std::binary_search(m_history_traffics.begin(), m_history_traffics.end(), traffic, HistoryTraffic::DateGreater)) { auto iter = std::lower_bound(m_history_traffics.begin(), m_history_traffics.end(), traffic, HistoryTraffic::DateGreater); if (iter != m_history_traffics.end()) { continue; } } } m_history_traffics.push_back(traffic); } MormalizeData(); } void CHistoryTrafficFile::MormalizeData() { SYSTEMTIME current_time; GetLocalTime(¤t_time); HistoryTraffic traffic; traffic.year = current_time.wYear; traffic.month = current_time.wMonth; traffic.day = current_time.wDay; traffic.up_kBytes = 0; traffic.down_kBytes = 0; traffic.mixed = false; if (m_history_traffics.empty()) { m_history_traffics.push_front(traffic); } if (m_history_traffics.size() >= 2) { //ȡʷбڴӴС std::sort(m_history_traffics.begin(), m_history_traffics.end(), HistoryTraffic::DateGreater); //бͬڵĿϲ for (int i{}; i < static_cast(m_history_traffics.size() - 1); i++) { if (HistoryTraffic::DateEqual(m_history_traffics[i], m_history_traffics[i + 1])) { m_history_traffics[i].up_kBytes += m_history_traffics[i + 1].up_kBytes; m_history_traffics[i].down_kBytes += m_history_traffics[i + 1].down_kBytes; m_history_traffics.erase(m_history_traffics.begin() + i + 1); } } } //бһĿǽ죬򽫵һĿͳƵΪʹõбǰһΪĿ if (HistoryTraffic::DateEqual(m_history_traffics[0], traffic)) { m_today_up_traffic = static_cast<__int64>(m_history_traffics[0].up_kBytes) * 1024; m_today_down_traffic = static_cast<__int64>(m_history_traffics[0].down_kBytes) * 1024; m_history_traffics[0].mixed = false; } else { m_history_traffics.push_front(traffic); } m_size = m_history_traffics.size(); } ================================================ FILE: TrafficMonitor/HistoryTrafficFile.h ================================================ #pragma once #include "CommonData.h" class CHistoryTrafficFile { public: CHistoryTrafficFile(const wstring& file_path); ~CHistoryTrafficFile(); void Save() const; void Load(); void LoadSize(); //ȡļĴС void Merge(const CHistoryTrafficFile& history_traffic, bool ignore_same_data = false); //ϲһCHistoryTrafficFileignore_same_dataΪtrueͬڵͬڵ const wstring& GetFilePath() const { return m_file_path; } const void SetFilePath(const wstring& file_path) { m_file_path = file_path; } deque& GetTraffics() { return m_history_traffics; } __int64 GetTodayUpTraffic() const { return m_today_up_traffic; } __int64 GetTodayDownTraffic() const { return m_today_down_traffic; } size_t Size() { return m_size; } private: void MormalizeData(); //ʷ򲢺ϲͬ private: wstring m_file_path; deque m_history_traffics; //ʷ __int64 m_today_up_traffic{}; //ʹõϴ __int64 m_today_down_traffic{}; //ʹõ size_t m_size{}; //ݵ }; ================================================ FILE: TrafficMonitor/HistoryTrafficListCtrl.cpp ================================================ #include "stdafx.h" #include "HistoryTrafficListCtrl.h" IMPLEMENT_DYNAMIC(CHistoryTrafficListCtrl, CListCtrl) CHistoryTrafficListCtrl::CHistoryTrafficListCtrl() { } CHistoryTrafficListCtrl::~CHistoryTrafficListCtrl() { } void CHistoryTrafficListCtrl::SetDrawItemRangeData(int item, double range, COLORREF color) { if (item < 0) return; if (item >= static_cast(m_item_rage_data.size())) m_item_rage_data.resize(item + 1); m_item_rage_data[item].data_value = range; m_item_rage_data[item].color = color; } void CHistoryTrafficListCtrl::SetDrawItemRangInLogScale(bool log_scale) { m_use_log_scale = log_scale; Invalidate(); } BEGIN_MESSAGE_MAP(CHistoryTrafficListCtrl, CListCtrl) ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CHistoryTrafficListCtrl::OnNMCustomdraw) END_MESSAGE_MAP() void CHistoryTrafficListCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult) { if (m_draw_item_range) { *pResult = CDRF_DODEFAULT; LPNMLVCUSTOMDRAW lplvdr = reinterpret_cast(pNMHDR); NMCUSTOMDRAW& nmcd = lplvdr->nmcd; switch (lplvdr->nmcd.dwDrawStage) //判断状态 { case CDDS_PREPAINT: *pResult = CDRF_NOTIFYITEMDRAW; break; case CDDS_ITEMPREPAINT: //如果为画ITEM之前就要进行颜色的改变 if (nmcd.dwItemSpec >= 0 && nmcd.dwItemSpec < m_item_rage_data.size()) { double range = m_item_rage_data[nmcd.dwItemSpec].data_value; CDC* pDC = CDC::FromHandle(nmcd.hdc); //获取绘图DC CRect item_rect, draw_rect; GetSubItemRect(nmcd.dwItemSpec,m_draw_item_range_row, LVIR_BOUNDS, item_rect); //获取绘图单元格的矩形区域 CDrawCommon::SetDrawRect(pDC, item_rect); //设置绘图区域为当前列 //使用双缓冲绘图 { CDrawDoubleBuffer draw_double_buffer(pDC, item_rect); //填充背景 draw_rect = item_rect; draw_rect.MoveToXY(0, 0); draw_double_buffer.GetMemDC()->FillSolidRect(draw_rect, GetSysColor(COLOR_WINDOW)); if (draw_rect.Height() > 2 * m_margin) { draw_rect.top += m_margin; draw_rect.bottom -= m_margin; } int width; if (m_use_log_scale) //使用对数比例(y=ln(x+1)) { range = std::log(range + 1); width = static_cast(range*draw_rect.Width() / std::log(1000 + 1)); } else //使用线性比例(y=x) { width = static_cast(range*draw_rect.Width() / 1000); } draw_rect.right = draw_rect.left + width; draw_double_buffer.GetMemDC()->FillSolidRect(draw_rect, m_item_rage_data[nmcd.dwItemSpec].color); } //当前列绘制完成后将绘图区域设置为左边的区域,防止当前列的区域被覆盖 CRect rect1{ item_rect }; rect1.left = 0; rect1.right = item_rect.left; CDrawCommon::SetDrawRect(pDC, rect1); } *pResult = CDRF_DODEFAULT; break; } } } ================================================ FILE: TrafficMonitor/HistoryTrafficListCtrl.h ================================================ #pragma once #include "afxcmn.h" #include "DrawCommon.h" class CHistoryTrafficListCtrl : public CListCtrl { DECLARE_DYNAMIC(CHistoryTrafficListCtrl) public: CHistoryTrafficListCtrl(); ~CHistoryTrafficListCtrl(); void EnableDrawItemRange(bool draw = true) { m_draw_item_range = draw; } //ǷҪijһеԪлƱʾֵСľ void SetDrawItemRangeRow(int row) { m_draw_item_range_row = row; } //ҪƱʾֵСľεУעбΪұߵУ򣬴ұߵн޷ʾ void SetDrawItemRangeData(int item, double range, COLORREF color); //ijһеĿݴСȡֵΪ1~1000ɫ void SetDrawItemRangMargin(int margin) { m_margin = margin; } //ûƻƵľεıԵԪ߿ľΣֵԽƵľԽϸDzܳбоһ void SetDrawItemRangInLogScale(bool log_scale); //ҪƱʾֵСľʱǷʹöʹԱ protected: struct ItemData { double data_value; //ҪƵľαʾֵСΧΪ0~1000 COLORREF color; //ҪƵľεɫ }; bool m_draw_item_range{ false }; //ǷҪijһеԪлƱʾֵСľ int m_draw_item_range_row{}; //ҪƱʾֵСľε int m_margin{}; vector m_item_rage_data; //ڱʾÿһҪƵݴСͻͼɫ bool m_use_log_scale{ false }; //ΪtrueʹöƾΣʹԱ DECLARE_MESSAGE_MAP() afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult); }; ================================================ FILE: TrafficMonitor/HistoryTrafficListDlg.cpp ================================================ // HistoryTrafficList.cpp: 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "HistoryTrafficListDlg.h" #include "afxdialogex.h" #include "CalendarHelper.h" // CHistoryTrafficListDlgDlg 对话框 IMPLEMENT_DYNAMIC(CHistoryTrafficListDlg, CTabDlg) CHistoryTrafficListDlg::CHistoryTrafficListDlg(deque& history_traffics, CWnd* pParent /*=nullptr*/) : CTabDlg(IDD_HISTORY_TRAFFIC_LIST_DIALOG, pParent), m_history_traffics(history_traffics) { } CHistoryTrafficListDlg::~CHistoryTrafficListDlg() { } bool CHistoryTrafficListDlg::CalculateColumeWidth(std::vector& widths) { if (!IsWindow(m_history_list.GetSafeHwnd())) return false; CRect rect; m_history_list.GetWindowRect(rect); if (rect.Width() <= 0) return false; const int MAX_COLUME{ 5 }; int width_date; //“日期”列的宽度 int width0; //“上传”、“下载”、“总流量”列的宽度 int width1; //“图表”列的宽度 width_date = rect.Width() * 3 / 11; width0 = rect.Width() * 2 / 11; if (width_date > theApp.DPI(150)) width_date = theApp.DPI(150); if (width0 > theApp.DPI(120)) width0 = theApp.DPI(120); width1 = rect.Width() - (MAX_COLUME - 2) * width0 - width_date - theApp.DPI(20) - 1; widths.resize(MAX_COLUME); widths[0] = width_date; widths[1] = widths[2] = widths[3] = width0; widths[4] = width1; return true; } void CHistoryTrafficListDlg::AddListRow(const ListRowData& data, unsigned __int64 max_traffic) { unsigned __int64 total_kbytes = data.up_kBytes + data.down_kBytes; int index = m_history_list.GetItemCount(); m_history_list.InsertItem(index, data.str); if (data.mixed) { m_history_list.SetItemText(index, 1, _T("-")); m_history_list.SetItemText(index, 2, _T("-")); } else { m_history_list.SetItemText(index, 1, CCommon::KBytesToString(data.up_kBytes)); m_history_list.SetItemText(index, 2, CCommon::KBytesToString(data.down_kBytes)); } m_history_list.SetItemText(index, 3, CCommon::KBytesToString(total_kbytes)); double range = static_cast(total_kbytes) * 1000 / max_traffic; COLORREF color; if (total_kbytes < 1024 * 1024) //流量小于1GB时绘制蓝色 color = TRAFFIC_COLOR_BLUE; else if (total_kbytes < 10 * 1024 * 1024) //流量小于10GB时绘制绿色 color = TRAFFIC_COLOR_GREEN; else if (total_kbytes < 100 * 1024 * 1024) //流量小于100GB时绘制黄色 color = TRAFFIC_COLOR_YELLOE; else if (total_kbytes < 1024 * 1024 * 1024) //流量小于1TB时绘制红色 color = TRAFFIC_COLOR_RED; else //流量超过1TB时显示深红色 color = TRAFFIC_COLOR_DARK_RED; m_history_list.SetDrawItemRangeData(index, range, color); } void CHistoryTrafficListDlg::ShowListData() { m_history_list.DeleteAllItems(); //显示日视图 if(theApp.m_cfg_data.m_view_type == HistoryTrafficViewType::HV_DAY) { //获取历史流量列表中流量的最大值 unsigned __int64 max_traffic{}; for (const auto& traffic : m_history_traffics) { if (traffic.kBytes() > max_traffic) max_traffic = traffic.kBytes(); } for (size_t i{}; i < m_history_traffics.size(); i++) { CString date_str; //CString k_bytes_str; date_str.Format(_T("%.4d/%.2d/%.2d ("), m_history_traffics[i].year, m_history_traffics[i].month, m_history_traffics[i].day); int week_day = CCalendarHelper::CaculateWeekDay(m_history_traffics[i].year, m_history_traffics[i].month, m_history_traffics[i].day); switch (week_day) { case 0: date_str += CCommon::LoadText(IDS_SUNDAY); break; case 1: date_str += CCommon::LoadText(IDS_MONDAY); break; case 2: date_str += CCommon::LoadText(IDS_TUESDAY); break; case 3: date_str += CCommon::LoadText(IDS_WEDNESDAY); break; case 4: date_str += CCommon::LoadText(IDS_THURSDAY); break; case 5: date_str += CCommon::LoadText(IDS_FRIDAY); break; case 6: date_str += CCommon::LoadText(IDS_SATURDAY); break; default: break; } date_str += _T(')'); ListRowData data; data.str = date_str; data.up_kBytes = m_history_traffics[i].up_kBytes; data.down_kBytes = m_history_traffics[i].down_kBytes; data.mixed = m_history_traffics[i].mixed; AddListRow(data, max_traffic); } } //显示月/季/年视图 else { std::vector list_data; unsigned __int64 max_traffic{}; for (const auto& traffic : m_history_traffics) { CString date_str; if (theApp.m_cfg_data.m_view_type == HistoryTrafficViewType::HV_WEEK) { date_str.Format(_T("%.4d/"), traffic.year); date_str += CCommon::LoadTextFormat(IDS_WEEK_NUM, { traffic.week() }); } else if (theApp.m_cfg_data.m_view_type == HistoryTrafficViewType::HV_MONTH) //月视图 { date_str.Format(_T("%.4d/%.2d"), traffic.year, traffic.month); } else if (theApp.m_cfg_data.m_view_type == HistoryTrafficViewType::HV_QUARTER) //季视图 { date_str.Format(_T("%.4d/"), traffic.year); if (traffic.month <= 3) date_str += _T("Q1"); else if (traffic.month <= 6) date_str += _T("Q2"); else if (traffic.month <= 9) date_str += _T("Q3"); else date_str += _T("Q4"); } else //年视图 { date_str.Format(_T("%.4d"), traffic.year); } if (list_data.empty() || list_data.back().str != date_str) { if(!list_data.empty()) { unsigned __int64 cur_traffic{ list_data.back().up_kBytes + list_data.back().down_kBytes }; if (cur_traffic > max_traffic) max_traffic = cur_traffic; } ListRowData data; data.str = date_str; data.up_kBytes = traffic.up_kBytes; data.down_kBytes = traffic.down_kBytes; list_data.push_back(data); } else { list_data.back().up_kBytes += traffic.up_kBytes; list_data.back().down_kBytes += traffic.down_kBytes; } } for (const auto& data : list_data) { AddListRow(data, max_traffic); } } } void CHistoryTrafficListDlg::DoDataExchange(CDataExchange* pDX) { CTabDlg::DoDataExchange(pDX); DDX_Control(pDX, IDC_HISTORY_INFO_LIST, m_history_list); DDX_Control(pDX, IDC_VIEW_TYPE_COMBO, m_view_type_combo); DDX_Control(pDX, IDC_VIEW_SCALE_COMBO, m_view_scale_combo); } BEGIN_MESSAGE_MAP(CHistoryTrafficListDlg, CTabDlg) ON_WM_INITMENU() ON_COMMAND(ID_USE_LINEAR_SCALE, &CHistoryTrafficListDlg::OnUseLinearScale) ON_COMMAND(ID_USE_LOG_SCALE, &CHistoryTrafficListDlg::OnUseLogScale) ON_WM_SIZE() ON_CBN_SELCHANGE(IDC_VIEW_TYPE_COMBO, &CHistoryTrafficListDlg::OnCbnSelchangeViewTypeCombo) ON_CBN_SELCHANGE(IDC_VIEW_SCALE_COMBO, &CHistoryTrafficListDlg::OnCbnSelchangeViewScaleCombo) END_MESSAGE_MAP() // CHistoryTrafficListDlgDlg 消息处理程序 BOOL CHistoryTrafficListDlg::OnInitDialog() { CTabDlg::OnInitDialog(); // TODO: 在此添加额外的初始化 //初始化列表控件 m_history_list.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP); std::vector widths; CalculateColumeWidth(widths); m_history_list.InsertColumn(0, CCommon::LoadText(IDS_DATE), LVCFMT_LEFT, widths[0]); m_history_list.InsertColumn(1, CCommon::LoadText(IDS_UPLOAD), LVCFMT_RIGHT, widths[1]); m_history_list.InsertColumn(2, CCommon::LoadText(IDS_DOWNLOAD), LVCFMT_RIGHT, widths[2]); m_history_list.InsertColumn(3, CCommon::LoadText(IDS_TRAFFIC_USED), LVCFMT_RIGHT, widths[3]); m_history_list.InsertColumn(4, CCommon::LoadText(IDS_FIGURE), LVCFMT_LEFT, widths[4]); m_history_list.EnableDrawItemRange(); m_history_list.SetDrawItemRangeRow(4); m_history_list.SetDrawItemRangMargin(theApp.DPI(4)); m_history_list.SetDrawItemRangInLogScale(theApp.m_cfg_data.m_use_log_scale); //初始化控件 m_view_type_combo.AddString(CCommon::LoadText(IDS_DAY_VIEW)); m_view_type_combo.AddString(CCommon::LoadText(IDS_WEEK_VIEW)); m_view_type_combo.AddString(CCommon::LoadText(IDS_MONTH_VIEW)); m_view_type_combo.AddString(CCommon::LoadText(IDS_QUARTER_VIEW)); m_view_type_combo.AddString(CCommon::LoadText(IDS_YEAR_VIEW)); m_view_type_combo.SetCurSel(static_cast(theApp.m_cfg_data.m_view_type)); m_view_scale_combo.AddString(CCommon::LoadText(IDS_LINEAR_SCALE)); m_view_scale_combo.AddString(CCommon::LoadText(IDS_LOG_SCALE)); m_view_scale_combo.SetCurSel(theApp.m_cfg_data.m_use_log_scale ? 1 : 0); //显示列表数据 ShowListData(); m_menu.LoadMenu(IDR_HISTORY_TRAFFIC_MENU); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } BOOL CHistoryTrafficListDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { // TODO: 在此添加专用代码和/或调用基类 LPNMHDR lpnmhdr = (LPNMHDR)lParam; if (lpnmhdr->code == NM_RCLICK) { CPoint point; GetCursorPos(&point);//获得光标的位置 m_history_list.ScreenToClient(&point);//获得list控件在窗口上的坐标 CWnd* pWnd = m_history_list.ChildWindowFromPoint(point); CHeaderCtrl* pHeader = m_history_list.GetHeaderCtrl();//获取列表视图控件的标题控件 CRect item_rect; pHeader->GetItemRect(4, item_rect); //获取列表标题控件第2列的矩形区域,只有光标在第4列点击时才弹出右键菜单 if (pWnd && (pWnd->GetSafeHwnd() == pHeader->GetSafeHwnd()) && item_rect.PtInRect(point)) { HDHITTESTINFO info{}; info.pt = point; pHeader->SendMessage(HDM_HITTEST, 0, (LPARAM)&info); CMenu * pMenu = m_menu.GetSubMenu(0); GetCursorPos(&point); pMenu->TrackPopupMenu(TPM_RIGHTBUTTON, point.x, point.y, this); } } return CTabDlg::OnNotify(wParam, lParam, pResult); } void CHistoryTrafficListDlg::OnInitMenu(CMenu* pMenu) { CTabDlg::OnInitMenu(pMenu); // TODO: 在此处添加消息处理程序代码 if (theApp.m_cfg_data.m_use_log_scale) pMenu->CheckMenuRadioItem(ID_USE_LINEAR_SCALE, ID_USE_LOG_SCALE, ID_USE_LOG_SCALE, MF_BYCOMMAND | MF_CHECKED); else pMenu->CheckMenuRadioItem(ID_USE_LINEAR_SCALE, ID_USE_LOG_SCALE, ID_USE_LINEAR_SCALE, MF_BYCOMMAND | MF_CHECKED); } void CHistoryTrafficListDlg::OnUseLinearScale() { // TODO: 在此添加命令处理程序代码 theApp.m_cfg_data.m_use_log_scale = false; m_history_list.SetDrawItemRangInLogScale(theApp.m_cfg_data.m_use_log_scale); } void CHistoryTrafficListDlg::OnUseLogScale() { // TODO: 在此添加命令处理程序代码 theApp.m_cfg_data.m_use_log_scale = true; m_history_list.SetDrawItemRangInLogScale(theApp.m_cfg_data.m_use_log_scale); } void CHistoryTrafficListDlg::OnSize(UINT nType, int cx, int cy) { CTabDlg::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 if (nType != SIZE_MINIMIZED) { std::vector widths; if(CalculateColumeWidth(widths)) { for (size_t i{}; i < widths.size(); i++) { m_history_list.SetColumnWidth(i, widths[i]); } } } } void CHistoryTrafficListDlg::OnCbnSelchangeViewTypeCombo() { // TODO: 在此添加控件通知处理程序代码 theApp.m_cfg_data.m_view_type = static_cast(m_view_type_combo.GetCurSel()); ShowListData(); } void CHistoryTrafficListDlg::OnCbnSelchangeViewScaleCombo() { // TODO: 在此添加控件通知处理程序代码 theApp.m_cfg_data.m_use_log_scale = (m_view_scale_combo.GetCurSel() != 0); m_history_list.SetDrawItemRangInLogScale(theApp.m_cfg_data.m_use_log_scale); } ================================================ FILE: TrafficMonitor/IconSelectDlg.cpp ================================================ // IconSelectDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "IconSelectDlg.h" #include "afxdialogex.h" // CIconSelectDlg 对话框 IMPLEMENT_DYNAMIC(CIconSelectDlg, CBaseDialog) CIconSelectDlg::CIconSelectDlg(int icon_selected, CWnd* pParent /*=NULL*/) : CBaseDialog(IDD_ICON_SELECT_DIALOG, pParent), m_icon_selected{ icon_selected } { } CIconSelectDlg::~CIconSelectDlg() { } int CIconSelectDlg::GetIconSelected() const { if (m_icon_selected < 0 || m_icon_selected >= MAX_NOTIFY_ICON) return 0; return m_icon_selected; } void CIconSelectDlg::SetAutoAdaptNotifyIcon(bool val) { m_atuo_adapt_notify_icon = val; } bool CIconSelectDlg::AutoAdaptNotifyIcon() const { return m_atuo_adapt_notify_icon; } void CIconSelectDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_ICON_PREVIEW, m_preview_pic); DDX_Control(pDX, IDC_COMBO1, m_icon_select_combo); DDX_Control(pDX, IDC_AUTO_ADAPT_CHECK, m_auto_adapt_chk); } void CIconSelectDlg::DrawPreviewIcon(CDC* pDC) { //pDC->FillSolidRect(CRect(CPoint(ICON_X, ICON_Y), CSize(theApp.DPI(16), theApp.DPI(16))), RGB(0, 0, 0)); //pDC->DrawIcon(ICON_X, ICON_Y, m_icons[m_icon_selected]); ::DrawIconEx(pDC->m_hDC, ICON_X, ICON_Y, theApp.m_notify_icons[GetIconSelected()], theApp.DPI(16), theApp.DPI(16), 0, NULL, DI_NORMAL); } BEGIN_MESSAGE_MAP(CIconSelectDlg, CBaseDialog) //ON_WM_TIMER() ON_CBN_SELCHANGE(IDC_COMBO1, &CIconSelectDlg::OnCbnSelchangeCombo1) ON_MESSAGE(WM_CONTROL_REPAINT, &CIconSelectDlg::OnControlRepaint) ON_BN_CLICKED(IDC_AUTO_ADAPT_CHECK, &CIconSelectDlg::OnBnClickedAutoAdaptCheck) END_MESSAGE_MAP() // CIconSelectDlg 消息处理程序 BOOL CIconSelectDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetWindowText(CCommon::LoadText(IDS_TITLE_CHANGE_ICON)); //设置预览图大小 m_preview_pic.SetWindowPos(nullptr, 0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT, SWP_NOZORDER | SWP_NOMOVE); if (m_icon_selected == 4 || m_icon_selected == 5) m_preview_pic.SetPicture((HBITMAP)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_NOTIFY_ICON_PREVIEW_LIGHT), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR | LR_CREATEDIBSECTION)); else m_preview_pic.SetPicture((HBITMAP)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_NOTIFY_ICON_PREVIEW), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR | LR_CREATEDIBSECTION)); //初始化下拉列表 m_icon_select_combo.AddString(CCommon::LoadText(IDS_DEFAULT_ICON)); m_icon_select_combo.AddString(CCommon::LoadText(IDS_ICON, _T(" 1"))); m_icon_select_combo.AddString(CCommon::LoadText(IDS_ICON, _T(" 2"))); m_icon_select_combo.AddString(CCommon::LoadText(IDS_ICON, _T(" 3"))); m_icon_select_combo.AddString(CCommon::LoadText(IDS_ICON, _T(" 4"))); m_icon_select_combo.AddString(CCommon::LoadText(IDS_ICON, _T(" 5"))); m_icon_select_combo.SetCurSel(m_icon_selected); m_auto_adapt_chk.SetCheck(m_atuo_adapt_notify_icon); m_auto_adapt_chk.EnableWindow(theApp.m_win_version.GetMajorVersion() >= 10); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CIconSelectDlg::OnCbnSelchangeCombo1() { // TODO: 在此添加控件通知处理程序代码 m_icon_selected = m_icon_select_combo.GetCurSel(); if (m_icon_selected == 4 || m_icon_selected == 5) m_preview_pic.SetPicture((HBITMAP)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_NOTIFY_ICON_PREVIEW_LIGHT), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR | LR_CREATEDIBSECTION)); else m_preview_pic.SetPicture((HBITMAP)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_NOTIFY_ICON_PREVIEW), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR | LR_CREATEDIBSECTION)); DrawPreviewIcon(m_preview_pic.GetDC()); } afx_msg LRESULT CIconSelectDlg::OnControlRepaint(WPARAM wParam, LPARAM lParam) { CWnd* pControl = (CWnd*)wParam; CDC* pDC = (CDC*)lParam; if (pControl == &m_preview_pic) { //当收到m_preview_pic控件的重绘消息时,同时重绘图标 DrawPreviewIcon(pDC); } return 0; } void CIconSelectDlg::OnBnClickedAutoAdaptCheck() { // TODO: 在此添加控件通知处理程序代码 m_atuo_adapt_notify_icon = (m_auto_adapt_chk.GetCheck() != 0); } CString CIconSelectDlg::GetDialogName() const { return _T(""); } ================================================ FILE: TrafficMonitor/IconSelectDlg.h ================================================ #pragma once #include "afxwin.h" #include "PictureStatic.h" #include "BaseDialog.h" // CIconSelectDlg 对话框 class CIconSelectDlg : public CBaseDialog { DECLARE_DYNAMIC(CIconSelectDlg) public: CIconSelectDlg(int icon_selected, CWnd* pParent = NULL); // 标准构造函数 virtual ~CIconSelectDlg(); int GetIconSelected() const; void SetAutoAdaptNotifyIcon(bool val); bool AutoAdaptNotifyIcon() const; // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ICON_SELECT_DIALOG }; #endif #define PREVIEW_WIDTH theApp.DPI(200) //预览图的宽高 #define PREVIEW_HEIGHT theApp.DPI(40) #define ICON_X theApp.DPI(46) //预览图中图标的位置 #define ICON_Y theApp.DPI(12) protected: CPictureStatic m_preview_pic; CComboBox m_icon_select_combo; CButton m_auto_adapt_chk; int m_icon_selected{}; bool m_atuo_adapt_notify_icon; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 virtual CString GetDialogName() const override; void DrawPreviewIcon(CDC* pDC); DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); //afx_msg void OnTimer(UINT_PTR nIDEvent); afx_msg void OnCbnSelchangeCombo1(); protected: afx_msg LRESULT OnControlRepaint(WPARAM wParam, LPARAM lParam); public: afx_msg void OnBnClickedAutoAdaptCheck(); }; ================================================ FILE: TrafficMonitor/IniHelper.cpp ================================================ #include "stdafx.h" #include "IniHelper.h" #include "TrafficMonitor.h" CIniHelper::CIniHelper(const wstring& file_path) { m_file_path = file_path; ifstream file_stream{ file_path }; if (file_stream.fail()) { return; } //读取文件内容 string ini_str; while (!file_stream.eof()) { ini_str.push_back(file_stream.get()); } ini_str.pop_back(); if (!ini_str.empty() && ini_str.back() != L'\n') //确保文件末尾有回车符 ini_str.push_back(L'\n'); //判断文件是否是utf8编码 bool is_utf8; if (ini_str.size() >= 3 && ini_str[0] == -17 && ini_str[1] == -69 && ini_str[2] == -65) { //如果有UTF8的BOM,则删除BOM is_utf8 = true; ini_str = ini_str.substr(3); } else { is_utf8 = false; } //转换成Unicode m_ini_str = CCommon::StrToUnicode(ini_str.c_str(), is_utf8); } CIniHelper::~CIniHelper() { } void CIniHelper::SetSaveAsUTF8(bool utf8) { m_save_as_utf8 = utf8; } void CIniHelper::WriteString(const wchar_t * AppName, const wchar_t * KeyName, const wstring& str) { wstring write_str{ str }; if (!write_str.empty() && (write_str[0] == L' ' || write_str.back() == L' ')) //如果字符串前后含有空格,则在字符串前后添加引号 { write_str = DEF_CH + write_str; write_str.push_back(DEF_CH); } _WriteString(AppName, KeyName, write_str); } wstring CIniHelper::GetString(const wchar_t * AppName, const wchar_t * KeyName, const wchar_t* default_str) const { wstring rtn{_GetString(AppName, KeyName, default_str)}; //如果读取的字符串前后有指定的字符,则删除它 if (!rtn.empty() && (rtn.front() == L'$' || rtn.front() == DEF_CH)) rtn = rtn.substr(1); if (!rtn.empty() && (rtn.back() == L'$' || rtn.back() == DEF_CH)) rtn.pop_back(); return rtn; } void CIniHelper::WriteInt(const wchar_t * AppName, const wchar_t * KeyName, int value) { wchar_t buff[16]{}; _itow_s(value, buff, 10); _WriteString(AppName, KeyName, wstring(buff)); } int CIniHelper::GetInt(const wchar_t * AppName, const wchar_t * KeyName, int default_value) const { wchar_t default_str_buff[16]{}; _itow_s(default_value, default_str_buff, 10); wstring rtn{ _GetString(AppName, KeyName, default_str_buff) }; return _ttoi(rtn.c_str()); } void CIniHelper::WriteBool(const wchar_t * AppName, const wchar_t * KeyName, bool value) { if(value) _WriteString(AppName, KeyName, wstring(L"true")); else _WriteString(AppName, KeyName, wstring(L"false")); } bool CIniHelper::GetBool(const wchar_t * AppName, const wchar_t * KeyName, bool default_value) const { wstring rtn{ _GetString(AppName, KeyName, (default_value ? L"true" : L"false")) }; if (rtn == L"true") return true; else if (rtn == L"false") return false; else return (_ttoi(rtn.c_str()) != 0); } void CIniHelper::WriteIntArray(const wchar_t * AppName, const wchar_t * KeyName, const int * values, int size) { CString str, tmp; for (int i{}; i < size; i++) { tmp.Format(_T("%d,"), values[i]); str += tmp; } _WriteString(AppName, KeyName, wstring(str)); } void CIniHelper::GetIntArray(const wchar_t * AppName, const wchar_t * KeyName, int * values, int size, int default_value) const { CString default_str; default_str.Format(_T("%d"), default_value); wstring str; str = _GetString(AppName, KeyName, default_str); std::vector split_result; CCommon::StringSplit(str, L',', split_result); for (int i = 0; i < size; i++) { if (i < split_result.size()) values[i] = _wtoi(split_result[i].c_str()); else if (i > 0) values[i] = values[i - 1]; else values[i] = default_value; } } void CIniHelper::WriteBoolArray(const wchar_t * AppName, const wchar_t * KeyName, const bool * values, int size) { int value{}; for (int i{}; i < size; i++) { if (values[i]) value |= (1 << i); } return WriteInt(AppName, KeyName, value); } void CIniHelper::GetBoolArray(const wchar_t * AppName, const wchar_t * KeyName, bool * values, int size, bool default_value) const { int value = GetInt(AppName, KeyName, 0); for (int i{}; i < size; i++) { values[i] = ((value >> i) % 2 != 0); } } void CIniHelper::WriteStringList(const wchar_t* AppName, const wchar_t* KeyName, const vector& values) { wstring str_write = MergeStringList(values); _WriteString(AppName, KeyName, str_write); } void CIniHelper::GetStringList(const wchar_t* AppName, const wchar_t* KeyName, vector& values, const vector& default_value) const { wstring default_str = MergeStringList(default_value); wstring str_value = _GetString(AppName, KeyName, default_str.c_str()); SplitStringList(values, str_value); } void CIniHelper::SaveFontData(const wchar_t * AppName, const FontInfo & font) { WriteString(AppName, L"font_name", wstring(font.name)); WriteInt(AppName, L"font_size", font.size); bool style[4]; style[0] = font.bold; style[1] = font.italic; style[2] = font.underline; style[3] = font.strike_out; WriteBoolArray(AppName, L"font_style", style, 4); } bool CIniHelper::Save() { ofstream file_stream{ m_file_path }; if(file_stream.fail()) return false; string ini_str{ CCommon::UnicodeToStr(m_ini_str.c_str(), m_save_as_utf8) }; if (m_save_as_utf8) //如果以UTF8编码保存,先插入BOM { string utf8_bom; utf8_bom.push_back(-17); utf8_bom.push_back(-69); utf8_bom.push_back(-65); file_stream << utf8_bom; } file_stream << ini_str; return true; } void CIniHelper::LoadFontData(const wchar_t * AppName, FontInfo & font, const FontInfo& default_font) const { font.name = GetString(AppName, L"font_name", default_font.name).c_str(); font.size = GetInt(AppName, L"font_size", default_font.size); bool style[4]; GetBoolArray(AppName, L"font_style", style, 4); font.bold = style[0]; font.italic = style[1]; font.underline = style[2]; font.strike_out = style[3]; } void CIniHelper::LoadMainWndColors(const wchar_t * AppName, const wchar_t * KeyName, std::map& text_colors, COLORREF default_color) { CString default_str; default_str.Format(_T("%d"), default_color); wstring str; str = _GetString(AppName, KeyName, default_str); std::vector split_result; CCommon::StringSplit(str, L',', split_result); size_t index = 0; for (auto iter = theApp.m_plugins.AllDisplayItemsWithPlugins().begin(); iter != theApp.m_plugins.AllDisplayItemsWithPlugins().end(); ++iter) { if (index < split_result.size()) text_colors[*iter] = _wtoi(split_result[index].c_str()); else if (!split_result.empty()) text_colors[*iter] = _wtoi(split_result[0].c_str()); else text_colors[*iter] = default_color; index++; } } void CIniHelper::SaveMainWndColors(const wchar_t * AppName, const wchar_t * KeyName, const std::map& text_colors) { CString str; for (auto iter = text_colors.begin(); iter != text_colors.end(); ++iter) { CString tmp; tmp.Format(_T("%d,"), iter->second); str += tmp; } _WriteString(AppName, KeyName, wstring(str)); } void CIniHelper::LoadTaskbarWndColors(const wchar_t * AppName, const wchar_t * KeyName, std::map& text_colors, COLORREF default_color) { CString default_str; default_str.Format(_T("%d"), default_color); wstring str; str = _GetString(AppName, KeyName, default_str); std::vector split_result; CCommon::StringSplit(str, L',', split_result); size_t index = 0; for (auto iter = theApp.m_plugins.AllDisplayItemsWithPlugins().begin(); iter != theApp.m_plugins.AllDisplayItemsWithPlugins().end(); ++iter) { if (index < split_result.size()) text_colors[*iter].label = _wtoi(split_result[index].c_str()); else if (!split_result.empty()) text_colors[*iter].label = _wtoi(split_result[0].c_str()); else text_colors[*iter].label = default_color; if (index + 1 < split_result.size()) text_colors[*iter].value = _wtoi(split_result[index + 1].c_str()); else if (split_result.size() > 1) text_colors[*iter].value = _wtoi(split_result[1].c_str()); else text_colors[*iter].value = default_color; index += 2; } } void CIniHelper::SaveTaskbarWndColors(const wchar_t * AppName, const wchar_t * KeyName, const std::map& text_colors) { CString str; for (auto iter = text_colors.begin(); iter != text_colors.end(); ++iter) { CString tmp; tmp.Format(_T("%d,%d,"), iter->second.label, iter->second.value); str += tmp; } _WriteString(AppName, KeyName, wstring(str)); } void CIniHelper::LoadPluginDisplayStr(bool is_main_window) { DispStrings& disp_str{ is_main_window ? theApp.m_main_wnd_data.disp_str : theApp.m_taskbar_data.disp_str }; std::wstring app_name{ is_main_window ? L"plugin_display_str_main_window" : L"plugin_display_str_taskbar_window" }; for (const auto& plugin : theApp.m_plugins.GetPluginItems()) { disp_str.Load(plugin->GetItemId(), GetString(app_name.c_str(), plugin->GetItemId(), plugin->GetItemLableText())); } } void CIniHelper::SavePluginDisplayStr(bool is_main_window) { DispStrings& disp_str{ is_main_window ? theApp.m_main_wnd_data.disp_str : theApp.m_taskbar_data.disp_str }; std::wstring app_name{ is_main_window ? L"plugin_display_str_main_window" : L"plugin_display_str_taskbar_window" }; for (const auto& plugin : theApp.m_plugins.GetPluginItems()) { WriteString(app_name.c_str(), plugin->GetItemId(), disp_str.Get(plugin)); } } void CIniHelper::_WriteString(const wchar_t * AppName, const wchar_t * KeyName, const wstring & str) { wstring app_str{ L"[" }; app_str.append(AppName).append(L"]"); size_t app_pos{}, app_end_pos, key_pos; app_pos = m_ini_str.find(app_str); if (app_pos == wstring::npos) //找不到AppName,则在最后面添加 { if (!m_ini_str.empty() && m_ini_str.back() != L'\n') m_ini_str += L"\n"; app_pos = m_ini_str.size(); m_ini_str += app_str; m_ini_str += L"\n"; } app_end_pos = m_ini_str.find(L"\n[", app_pos + 2); if (app_end_pos != wstring::npos) app_end_pos++; key_pos = m_ini_str.find(wstring(L"\n") + KeyName + L' ', app_pos); //查找“\nkey_name ” if (key_pos >= app_end_pos) //如果找不到“\nkey_name ”,则查找“\nkey_name=” key_pos = m_ini_str.find(wstring(L"\n") + KeyName + L'=', app_pos); if (key_pos >= app_end_pos) //找不到KeyName,则插入一个 { //wchar_t buff[256]; //swprintf_s(buff, L"%s = %s\n", KeyName, str.c_str()); std::wstring str_temp = KeyName; str_temp += L" = "; str_temp += str; str_temp += L"\n"; if (app_end_pos == wstring::npos) m_ini_str += str_temp; else m_ini_str.insert(app_end_pos, str_temp); } else //找到了KeyName,将等号到换行符之间的文本替换 { size_t str_pos; str_pos = m_ini_str.find(L'=', key_pos + 2); size_t line_end_pos = m_ini_str.find(L'\n', key_pos + 2); if (str_pos > line_end_pos) //所在行没有等号,则插入一个等号 { m_ini_str.insert(key_pos + wcslen(KeyName) + 1, L" ="); str_pos = key_pos + wcslen(KeyName) + 2; } else { str_pos++; } size_t str_end_pos; str_end_pos = m_ini_str.find(L"\n", str_pos); m_ini_str.replace(str_pos, str_end_pos - str_pos, L" " + str); } } wstring CIniHelper::_GetString(const wchar_t * AppName, const wchar_t * KeyName, const wchar_t* default_str) const { wstring app_str{ L"[" }; app_str.append(AppName).append(L"]"); size_t app_pos{}, app_end_pos, key_pos; app_pos = m_ini_str.find(app_str); if (app_pos == wstring::npos) //找不到AppName,返回默认字符串 return default_str; app_end_pos = m_ini_str.find(L"\n[", app_pos + 2); if (app_end_pos != wstring::npos) app_end_pos++; key_pos = m_ini_str.find(wstring(L"\n") + KeyName + L' ', app_pos); //查找“\nkey_name ” if (key_pos >= app_end_pos) //如果找不到“\nkey_name ”,则查找“\nkey_name=” key_pos = m_ini_str.find(wstring(L"\n") + KeyName + L'=', app_pos); if (key_pos >= app_end_pos) //找不到KeyName,返回默认字符串 { return default_str; } else //找到了KeyName,获取等号到换行符之间的文本 { size_t str_pos; str_pos = m_ini_str.find(L'=', key_pos + 2); size_t line_end_pos = m_ini_str.find(L'\n', key_pos + 2); if (str_pos > line_end_pos) //所在行没有等号,返回默认字符串 { return default_str; } else { str_pos++; } size_t str_end_pos; str_end_pos = m_ini_str.find(L"\n", str_pos); //获取文本 wstring return_str{ m_ini_str.substr(str_pos, str_end_pos - str_pos) }; //如果前后有空格,则将其删除 CCommon::StringNormalize(return_str); return return_str; } } wstring CIniHelper::MergeStringList(const vector& values) { wstring str_merge; int index = 0; //在每个字符串前后加上引号,再将它们用逗号连接起来 for (const wstring& str : values) { if (index > 0) str_merge.push_back(L','); str_merge.push_back(L'\"'); str_merge += str; str_merge.push_back(L'\"'); index++; } return str_merge; } void CIniHelper::SplitStringList(vector& values, wstring str_value) { CCommon::StringSplit(str_value, wstring(L"\",\""), values); if (!values.empty()) { //结果中第一项前面和最后一项的后面各还有一个引号,将它们删除 values.front() = values.front().substr(1); values.back().pop_back(); } } ================================================ FILE: TrafficMonitor/IniHelper.h ================================================ //ini读写类 //使用时将ini文件路径通过构造函数参数传递 //在向ini文件写入数据时,需要在最后调用Save()函数以将更改保存到文件 //默认以UTF8_BOM编码保存,如果要以ANSI保存,请调用SetSaveAsUTF8(false); #pragma once #include "CommonData.h" #include "Common.h" class CIniHelper { public: CIniHelper(const wstring& file_path); ~CIniHelper(); void SetSaveAsUTF8(bool utf8); void WriteString(const wchar_t* AppName, const wchar_t* KeyName, const wstring& str); wstring GetString(const wchar_t* AppName, const wchar_t* KeyName, const wchar_t* default_str) const; void WriteInt(const wchar_t * AppName, const wchar_t * KeyName, int value); int GetInt(const wchar_t * AppName, const wchar_t * KeyName, int default_value) const; void WriteBool(const wchar_t * AppName, const wchar_t * KeyName, bool value); bool GetBool(const wchar_t * AppName, const wchar_t * KeyName, bool default_value) const; void WriteIntArray(const wchar_t * AppName, const wchar_t * KeyName, const int* values, int size); //写入一个int数组,元素个数为size void GetIntArray(const wchar_t * AppName, const wchar_t * KeyName, int* values, int size, int default_value = 0) const; //读取一个int数组,储存到values,元素个数为size void WriteBoolArray(const wchar_t * AppName, const wchar_t * KeyName, const bool* values, int size); void GetBoolArray(const wchar_t * AppName, const wchar_t * KeyName, bool* values, int size, bool default_value = false) const; void WriteStringList(const wchar_t* AppName, const wchar_t* KeyName, const vector& values); //写入一个字符串列表,由于保存到ini文件中时字符串前后会加上引号,所以字符串中不能包含引号 void GetStringList(const wchar_t* AppName, const wchar_t* KeyName, vector& values, const vector& default_value) const; void SaveFontData(const wchar_t * AppName, const FontInfo& font); void LoadFontData(const wchar_t * AppName, FontInfo& font, const FontInfo& default_font) const; void LoadMainWndColors(const wchar_t * AppName, const wchar_t * KeyName, std::map& text_colors, COLORREF default_color); void SaveMainWndColors(const wchar_t * AppName, const wchar_t * KeyName, const std::map& text_colors); void LoadTaskbarWndColors(const wchar_t * AppName, const wchar_t * KeyName, std::map& text_colors, COLORREF default_color); void SaveTaskbarWndColors(const wchar_t * AppName, const wchar_t * KeyName, const std::map& text_colors); void LoadPluginDisplayStr(bool is_main_window); void SavePluginDisplayStr(bool is_main_window); bool Save(); //将ini文件保存到文件,成功返回true protected: wstring m_file_path; wstring m_ini_str; bool m_save_as_utf8{ true }; //是否以及UTF8编码保存 void _WriteString(const wchar_t* AppName, const wchar_t* KeyName, const wstring& str); wstring _GetString(const wchar_t* AppName, const wchar_t* KeyName, const wchar_t* default_str) const; static wstring MergeStringList(const vector& values); static void SplitStringList(vector& values, wstring str_value); }; ================================================ FILE: TrafficMonitor/ListCtrlEx.cpp ================================================ #include "stdafx.h" #include "ListCtrlEx.h" IMPLEMENT_DYNAMIC(CListCtrlEx, CListCtrl) CListCtrlEx::CListCtrlEx() { } CListCtrlEx::~CListCtrlEx() { } void CListCtrlEx::Edit(int row, int col) { EnsureVisible(row, FALSE); //༭һʱȷпɼ m_editing = true; m_edit_row = row; m_edit_col = col; CRect item_rect; GetSubItemRect(row, col, LVIR_LABEL, item_rect); //ȡľ CString text = GetItemText(row, col); //ȡ m_item_edit.SetWindowText(text); //ʾ༭ m_item_edit.ShowWindow(SW_SHOW); //ʾ༭ m_item_edit.MoveWindow(item_rect); //༭ƶ棬 m_item_edit.SetFocus(); //ʹ༭ȡý m_item_edit.SetSel(0, -1); } void CListCtrlEx::SetEditColMethod(eEditColMethod method) { m_edit_col_method = method; } void CListCtrlEx::SetEditableCol(const std::initializer_list& paras) { m_edit_cols = paras; } void CListCtrlEx::EndEdit() { if (m_editing) { if (m_edit_row >= 0 && m_edit_row < GetItemCount()) { CString str; m_item_edit.GetWindowText(str); //ȡñ༭ SetItemText(m_edit_row, m_edit_col, str); //ݸµCListCtrl } m_item_edit.ShowWindow(SW_HIDE);//ر༭ m_editing = false; } } BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl) ON_EN_KILLFOCUS(IDC_ITEM_EDITBOX, &CListCtrlEx::OnEnKillfocusEdit1) ON_NOTIFY_REFLECT(NM_DBLCLK, &CListCtrlEx::OnNMDblclk) ON_NOTIFY_REFLECT(LVN_BEGINSCROLL, &CListCtrlEx::OnLvnBeginScroll) END_MESSAGE_MAP() void CListCtrlEx::OnEnKillfocusEdit1() { //ı༭ؼؼʧȥʱӦ EndEdit(); } void CListCtrlEx::PreSubclassWindow() { // TODO: ڴרô/û m_item_edit.Create(WS_BORDER | ES_AUTOHSCROLL, CRect(), this, IDC_ITEM_EDITBOX); m_item_edit.SetFont(GetFont()); CListCtrl::PreSubclassWindow(); } void CListCtrlEx::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: ڴӿؼ֪ͨ //˫Ҫ༭ if (m_edit_col_method == EC_ALL || (m_edit_col_method == EC_SPECIFIED && m_edit_cols.find(pNMItemActivate->iSubItem) != m_edit_cols.end())) { Edit(pNMItemActivate->iItem, pNMItemActivate->iSubItem); } *pResult = 0; } void CListCtrlEx::OnLvnBeginScroll(NMHDR *pNMHDR, LRESULT *pResult) { // ˹Ҫ Internet Explorer 5.5 ߰汾 // _WIN32_IE >= 0x0560 LPNMLVSCROLL pStateChanged = reinterpret_cast(pNMHDR); // TODO: ڴӿؼ֪ͨ EndEdit(); *pResult = 0; } ================================================ FILE: TrafficMonitor/ListCtrlEx.h ================================================ #pragma once #include "afxcmn.h" #include "DrawCommon.h" #include #define IDC_ITEM_EDITBOX 1991 class CListCtrlEx : public CListCtrl { DECLARE_DYNAMIC(CListCtrlEx) public: CListCtrlEx(); ~CListCtrlEx(); void Edit(int row, int col); //༭ָԪ enum eEditColMethod //Ҫ༭еķʽ { EC_NONE, // EC_ALL, //ȫ EC_SPECIFIED //ָ }; void SetEditColMethod(eEditColMethod method); void SetEditableCol(const std::initializer_list& paras); //༭ private: CEdit m_item_edit; int m_edit_row{}; int m_edit_col{}; bool m_editing{}; eEditColMethod m_edit_col_method{ EC_NONE }; std::set m_edit_cols; protected: void EndEdit(); DECLARE_MESSAGE_MAP() afx_msg void OnEnKillfocusEdit1(); virtual void PreSubclassWindow(); afx_msg void OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult); afx_msg void OnLvnBeginScroll(NMHDR *pNMHDR, LRESULT *pResult); }; ================================================ FILE: TrafficMonitor/MainWndColorDlg.cpp ================================================ // MainWndColorDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "MainWndColorDlg.h" #include "afxdialogex.h" #include "CMFCColorDialogEx.h" // CMainWndColorDlg 对话框 IMPLEMENT_DYNAMIC(CMainWndColorDlg, CBaseDialog) CMainWndColorDlg::CMainWndColorDlg(const std::map& colors, CWnd* pParent /*=NULL*/) : CBaseDialog(IDD_MAIN_COLOR_DIALOG, pParent), m_colors(colors) { } CMainWndColorDlg::~CMainWndColorDlg() { } CString CMainWndColorDlg::GetDialogName() const { return _T("MainWndColorDlg"); } void CMainWndColorDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST1, m_list_ctrl); } BEGIN_MESSAGE_MAP(CMainWndColorDlg, CBaseDialog) ON_NOTIFY(NM_DBLCLK, IDC_LIST1, &CMainWndColorDlg::OnNMDblclkList1) END_MESSAGE_MAP() // CMainWndColorDlg 消息处理程序 BOOL CMainWndColorDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetIcon(theApp.GetMenuIcon(IDI_MAIN_WINDOW), FALSE); // 设置小图标 //初始化列表控件 CRect rect; m_list_ctrl.GetClientRect(rect); m_list_ctrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP); int width0, width1; width0 = rect.Width() * 2 / 3; width1 = rect.Width() - width0 - theApp.DPI(20) - 1; m_list_ctrl.InsertColumn(0, CCommon::LoadText(IDS_ITEM), LVCFMT_LEFT, width0); //插入第0列 m_list_ctrl.InsertColumn(1, CCommon::LoadText(IDS_COLOR), LVCFMT_LEFT, width1); //插入第1列 m_list_ctrl.SetDrawItemRangMargin(theApp.DPI(2)); //向列表中插入行 for (auto iter = theApp.m_plugins.AllDisplayItemsWithPlugins().begin(); iter != theApp.m_plugins.AllDisplayItemsWithPlugins().end(); ++iter) { CString item_name = iter->GetItemName(); if (!item_name.IsEmpty()) { int index = m_list_ctrl.GetItemCount(); m_list_ctrl.InsertItem(index, item_name); m_list_ctrl.SetItemColor(index, 1, m_colors[*iter]); m_list_ctrl.SetItemData(index, (DWORD_PTR)&(*iter)); } } return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CMainWndColorDlg::OnNMDblclkList1(NMHDR *pNMHDR, LRESULT *pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 int index = pNMItemActivate->iItem; COLORREF color = m_list_ctrl.GetItemColor(index, 1); CMFCColorDialogEx colorDlg(color, 0, this); if (colorDlg.DoModal() == IDOK) { color = colorDlg.GetColor(); m_list_ctrl.SetItemColor(index, 1, color); CommonDisplayItem* item = (CommonDisplayItem*)(m_list_ctrl.GetItemData(index)); m_colors[*item] = color; } *pResult = 0; } ================================================ FILE: TrafficMonitor/MainWndColorDlg.h ================================================ #pragma once #include "ColorStatic.h" #include "afxwin.h" #include "ColorSettingListCtrl.h" #include "BaseDialog.h" // CMainWndColorDlg 对话框 class CMainWndColorDlg : public CBaseDialog { DECLARE_DYNAMIC(CMainWndColorDlg) public: CMainWndColorDlg(const std::map& colors, CWnd* pParent = NULL); // 标准构造函数 virtual ~CMainWndColorDlg(); const std::map& GetColors() const { return m_colors; } // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_MAIN_COLOR_DIALOG }; #endif protected: std::map m_colors; CColorSettingListCtrl m_list_ctrl; virtual CString GetDialogName() const override; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnNMDblclkList1(NMHDR *pNMHDR, LRESULT *pResult); }; ================================================ FILE: TrafficMonitor/MainWndSettingsDlg.cpp ================================================ // MainWndSettingsDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "MainWndSettingsDlg.h" #include "afxdialogex.h" #include "CMFCColorDialogEx.h" #include "DisplayTextSettingDlg.h" // CMainWndSettingsDlg 对话框 IMPLEMENT_DYNAMIC(CMainWndSettingsDlg, CTabDlg) CMainWndSettingsDlg::CMainWndSettingsDlg(CWnd* pParent /*=NULL*/) : CTabDlg(IDD_MAIN_WND_SETTINGS_DIALOG, pParent) { } CMainWndSettingsDlg::~CMainWndSettingsDlg() { } void CMainWndSettingsDlg::SetControlMouseWheelEnable(bool enable) { m_unit_combo.SetMouseWheelEnable(enable); m_double_click_combo.SetMouseWheelEnable(enable); m_font_size_edit.SetMouseWheelEnable(enable); m_memory_display_combo.SetMouseWheelEnable(enable); } void CMainWndSettingsDlg::DrawStaticColor() { //CCommon::FillStaticColor(m_color_static, m_data.text_color); if (m_data.text_colors.empty()) return; if (m_data.specify_each_item_color) { int color_num{}; #ifdef WITHOUT_TEMPERATURE color_num = 4; #else color_num = 8; #endif m_color_static.SetColorNum(color_num); int index{}; for (const auto& item : m_data.text_colors) { m_color_static.SetFillColor(index, item.second); index++; } m_color_static.Invalidate(); } else { m_color_static.SetFillColor(m_data.text_colors.begin()->second); } } void CMainWndSettingsDlg::IniUnitCombo() { m_unit_combo.ResetContent(); m_unit_combo.AddString(CCommon::LoadText(IDS_AUTO)); if (m_data.unit_byte) { m_unit_combo.AddString(CCommon::LoadText(IDS_FIXED_AS, _T(" KB/s"))); m_unit_combo.AddString(CCommon::LoadText(IDS_FIXED_AS, _T(" MB/s"))); } else { m_unit_combo.AddString(CCommon::LoadText(IDS_FIXED_AS, _T(" Kb/s"))); m_unit_combo.AddString(CCommon::LoadText(IDS_FIXED_AS, _T(" Mb/s"))); } m_unit_combo.SetCurSel(static_cast(m_data.speed_unit)); } void CMainWndSettingsDlg::EnableControl() { bool exe_path_enable = (m_data.double_click_action == DoubleClickAction::SEPCIFIC_APP); CWnd* pWnd{}; pWnd = GetDlgItem(IDC_EXE_PATH_STATIC); if (pWnd != nullptr) pWnd->ShowWindow(exe_path_enable ? SW_SHOW : SW_HIDE); pWnd = GetDlgItem(IDC_EXE_PATH_EDIT); if (pWnd != nullptr) pWnd->ShowWindow(exe_path_enable ? SW_SHOW : SW_HIDE); pWnd = GetDlgItem(IDC_BROWSE_BUTTON); if (pWnd != nullptr) pWnd->ShowWindow(exe_path_enable ? SW_SHOW : SW_HIDE); } void CMainWndSettingsDlg::DoDataExchange(CDataExchange* pDX) { DDX_Control(pDX, IDC_TEXT_COLOR_STATIC, m_color_static); CTabDlg::DoDataExchange(pDX); DDX_Control(pDX, IDC_HIDE_UNIT_CHECK, m_hide_unit_chk); DDX_Control(pDX, IDC_UNIT_COMBO, m_unit_combo); DDX_Control(pDX, IDC_FONT_SIZE_EDIT, m_font_size_edit); DDX_Control(pDX, IDC_DOUBLE_CLICK_COMBO, m_double_click_combo); DDX_Control(pDX, IDC_MEMORY_DISPLAY_COMBO, m_memory_display_combo); } BEGIN_MESSAGE_MAP(CMainWndSettingsDlg, CTabDlg) //ON_EN_CHANGE(IDC_UPLOAD_EDIT, &CMainWndSettingsDlg::OnEnChangeUploadEdit) //ON_EN_CHANGE(IDC_DOWNLOAD_EDIT, &CMainWndSettingsDlg::OnEnChangeDownloadEdit) //ON_EN_CHANGE(IDC_CPU_EDIT, &CMainWndSettingsDlg::OnEnChangeCpuEdit) //ON_EN_CHANGE(IDC_MEMORY_EDIT, &CMainWndSettingsDlg::OnEnChangeMemoryEdit) //ON_BN_CLICKED(IDC_SET_COLOR_BUTTON1, &CMainWndSettingsDlg::OnBnClickedSetColorButton1) //ON_BN_CLICKED(IDC_SET_DEFAULT_BUTTON, &CMainWndSettingsDlg::OnBnClickedSetDefaultButton) ON_BN_CLICKED(IDC_SET_FONT_BUTTON, &CMainWndSettingsDlg::OnBnClickedSetFontButton) ON_BN_CLICKED(IDC_SWITCH_UP_DOWN_CHECK, &CMainWndSettingsDlg::OnBnClickedSwitchUpDownCheck) ON_BN_CLICKED(IDC_FULLSCREEN_HIDE_CHECK, &CMainWndSettingsDlg::OnBnClickedFullscreenHideCheck) ON_BN_CLICKED(IDC_SPEED_SHORT_MODE_CHECK2, &CMainWndSettingsDlg::OnBnClickedSpeedShortModeCheck2) ON_CBN_SELCHANGE(IDC_UNIT_COMBO, &CMainWndSettingsDlg::OnCbnSelchangeUnitCombo) ON_BN_CLICKED(IDC_HIDE_UNIT_CHECK, &CMainWndSettingsDlg::OnBnClickedHideUnitCheck) ON_BN_CLICKED(IDC_HIDE_PERCENTAGE_CHECK, &CMainWndSettingsDlg::OnBnClickedHidePercentageCheck) ON_MESSAGE(WM_STATIC_CLICKED, &CMainWndSettingsDlg::OnStaticClicked) ON_BN_CLICKED(IDC_SPECIFY_EACH_ITEM_COLOR_CHECK, &CMainWndSettingsDlg::OnBnClickedSpecifyEachItemColorCheck) ON_CBN_SELCHANGE(IDC_DOUBLE_CLICK_COMBO, &CMainWndSettingsDlg::OnCbnSelchangeDoubleClickCombo) ON_BN_CLICKED(IDC_SEPARATE_VALUE_UNIT_CHECK, &CMainWndSettingsDlg::OnBnClickedSeparateValueUnitCheck) ON_BN_CLICKED(IDC_UNIT_BYTE_RADIO, &CMainWndSettingsDlg::OnBnClickedUnitByteRadio) ON_BN_CLICKED(IDC_UNIT_BIT_RADIO, &CMainWndSettingsDlg::OnBnClickedUnitBitRadio) ON_BN_CLICKED(IDC_SHOW_TOOL_TIP_CHK, &CMainWndSettingsDlg::OnBnClickedShowToolTipChk) ON_BN_CLICKED(IDC_BROWSE_BUTTON, &CMainWndSettingsDlg::OnBnClickedBrowseButton) ON_BN_CLICKED(IDC_DISPLAY_TEXT_SETTING_BUTTON, &CMainWndSettingsDlg::OnBnClickedDisplayTextSettingButton) ON_CBN_SELCHANGE(IDC_MEMORY_DISPLAY_COMBO, &CMainWndSettingsDlg::OnCbnSelchangeMemoryDisplayCombo) ON_BN_CLICKED(IDC_ALWAYS_ON_TOP_CHECK, &CMainWndSettingsDlg::OnBnClickedAlwaysOnTopCheck) ON_BN_CLICKED(IDC_MOUSE_PENETRATE_CHECK, &CMainWndSettingsDlg::OnBnClickedMousePenetrateCheck) ON_BN_CLICKED(IDC_LOCK_WINDOW_POS_CHECK, &CMainWndSettingsDlg::OnBnClickedLockWindowPosCheck) ON_BN_CLICKED(IDC_ALOW_OUT_OF_BORDER_CHECK, &CMainWndSettingsDlg::OnBnClickedAlowOutOfBorderCheck) END_MESSAGE_MAP() // CMainWndSettingsDlg 消息处理程序 BOOL CMainWndSettingsDlg::OnInitDialog() { CTabDlg::OnInitDialog(); // TODO: 在此添加额外的初始化 //初始化各控件状态 SetDlgItemText(IDC_FONT_NAME_EDIT, m_data.font.name); //wchar_t buff[16]; //swprintf_s(buff, L"%d", m_data.font_size); //SetDlgItemText(IDC_FONT_SIZE_EDIT, buff); m_font_size_edit.SetRange(5, 72); m_font_size_edit.SetValue(m_data.font.size); //SetDlgItemText(IDC_UPLOAD_EDIT, m_data.disp_str.Get(TDI_UP).c_str()); //SetDlgItemText(IDC_DOWNLOAD_EDIT, m_data.disp_str.Get(TDI_DOWN).c_str()); //SetDlgItemText(IDC_CPU_EDIT, m_data.disp_str.Get(TDI_CPU).c_str()); //SetDlgItemText(IDC_MEMORY_EDIT, m_data.disp_str.Get(TDI_MEMORY).c_str()); ((CButton*)GetDlgItem(IDC_SWITCH_UP_DOWN_CHECK))->SetCheck(m_data.swap_up_down); ((CButton*)GetDlgItem(IDC_FULLSCREEN_HIDE_CHECK))->SetCheck(m_data.hide_main_wnd_when_fullscreen); ((CButton*)GetDlgItem(IDC_SPEED_SHORT_MODE_CHECK2))->SetCheck(m_data.speed_short_mode); ((CButton*)GetDlgItem(IDC_SEPARATE_VALUE_UNIT_CHECK))->SetCheck(m_data.separate_value_unit_with_space); ((CButton*)GetDlgItem(IDC_SHOW_TOOL_TIP_CHK))->SetCheck(m_data.show_tool_tip); m_color_static.SetLinkCursor(); DrawStaticColor(); m_toolTip.Create(this); m_toolTip.SetMaxTipWidth(theApp.DPI(300)); m_toolTip.AddTool(GetDlgItem(IDC_SPEED_SHORT_MODE_CHECK2), CCommon::LoadText(IDS_SPEED_SHORT_MODE_TIP)); if (m_data.unit_byte) ((CButton*)GetDlgItem(IDC_UNIT_BYTE_RADIO))->SetCheck(TRUE); else ((CButton*)GetDlgItem(IDC_UNIT_BIT_RADIO))->SetCheck(TRUE); IniUnitCombo(); m_hide_unit_chk.SetCheck(m_data.hide_unit); if (m_data.speed_unit == SpeedUnit::AUTO) { m_hide_unit_chk.SetCheck(FALSE); m_data.hide_unit = false; m_hide_unit_chk.EnableWindow(FALSE); } ((CButton*)GetDlgItem(IDC_HIDE_PERCENTAGE_CHECK))->SetCheck(m_data.hide_percent); if (m_text_disable) { //GetDlgItem(IDC_UPLOAD_EDIT)->EnableWindow(FALSE); //GetDlgItem(IDC_DOWNLOAD_EDIT)->EnableWindow(FALSE); //GetDlgItem(IDC_CPU_EDIT)->EnableWindow(FALSE); //GetDlgItem(IDC_MEMORY_EDIT)->EnableWindow(FALSE); EnableDlgCtrl(IDC_DISPLAY_TEXT_SETTING_BUTTON, false); m_data.swap_up_down = false; ((CButton*)GetDlgItem(IDC_SWITCH_UP_DOWN_CHECK))->SetCheck(FALSE); GetDlgItem(IDC_SWITCH_UP_DOWN_CHECK)->EnableWindow(FALSE); //GetDlgItem(IDC_SET_DEFAULT_BUTTON)->EnableWindow(FALSE); } CheckDlgButton(IDC_SPECIFY_EACH_ITEM_COLOR_CHECK, m_data.specify_each_item_color); m_double_click_combo.AddString(CCommon::LoadText(IDS_OPEN_CONNECTION_DETIAL)); m_double_click_combo.AddString(CCommon::LoadText(IDS_OPEN_HISTORICAL_TRAFFIC)); m_double_click_combo.AddString(CCommon::LoadText(IDS_SHOW_HIDE_MORE_INFO)); m_double_click_combo.AddString(CCommon::LoadText(IDS_OPEN_OPTION_SETTINGS)); m_double_click_combo.AddString(CCommon::LoadText(IDS_OPEN_TASK_MANAGER)); m_double_click_combo.AddString(CCommon::LoadText(IDS_SPECIFIC_APP)); m_double_click_combo.AddString(CCommon::LoadText(IDS_CHANGE_SKIN)); m_double_click_combo.AddString(CCommon::LoadText(IDS_NONE)); m_double_click_combo.SetCurSel(static_cast(m_data.double_click_action)); SetDlgItemText(IDC_EXE_PATH_EDIT, m_data.double_click_exe.c_str()); EnableControl(); //初始化内存显示方式下拉列表 m_memory_display_combo.AddString(CCommon::LoadText(IDS_USAGE_PERCENTAGE)); m_memory_display_combo.AddString(CCommon::LoadText(IDS_MEMORY_USED)); m_memory_display_combo.AddString(CCommon::LoadText(IDS_MEMORY_AVAILABLE)); m_memory_display_combo.SetCurSel(static_cast(m_data.memory_display)); CheckDlgButton(IDC_ALWAYS_ON_TOP_CHECK, m_data.m_always_on_top); CheckDlgButton(IDC_MOUSE_PENETRATE_CHECK, m_data.m_mouse_penetrate); CheckDlgButton(IDC_LOCK_WINDOW_POS_CHECK, m_data.m_lock_window_pos); CheckDlgButton(IDC_ALOW_OUT_OF_BORDER_CHECK, m_data.m_alow_out_of_border); ////设置控件不响应鼠标滚轮消息 //m_unit_combo.SetMouseWheelEnable(false); //m_double_click_combo.SetMouseWheelEnable(false); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } //void CMainWndSettingsDlg::OnEnChangeUploadEdit() //{ // // TODO: 如果该控件是 RICHEDIT 控件,它将不 // // 发送此通知,除非重写 CTabDlg::OnInitDialog() // // 函数并调用 CRichEditCtrl().SetEventMask(), // // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // // // TODO: 在此添加控件通知处理程序代码 // CString tmp; // GetDlgItemText(IDC_UPLOAD_EDIT, tmp); // m_data.disp_str.Get(TDI_UP) = tmp; //} // // //void CMainWndSettingsDlg::OnEnChangeDownloadEdit() //{ // // TODO: 如果该控件是 RICHEDIT 控件,它将不 // // 发送此通知,除非重写 CTabDlg::OnInitDialog() // // 函数并调用 CRichEditCtrl().SetEventMask(), // // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // // // TODO: 在此添加控件通知处理程序代码 // CString tmp; // GetDlgItemText(IDC_DOWNLOAD_EDIT, tmp); // m_data.disp_str.Get(TDI_DOWN) = tmp; //} // // //void CMainWndSettingsDlg::OnEnChangeCpuEdit() //{ // // TODO: 如果该控件是 RICHEDIT 控件,它将不 // // 发送此通知,除非重写 CTabDlg::OnInitDialog() // // 函数并调用 CRichEditCtrl().SetEventMask(), // // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // // // TODO: 在此添加控件通知处理程序代码 // CString tmp; // GetDlgItemText(IDC_CPU_EDIT, tmp); // m_data.disp_str.Get(TDI_CPU) = tmp; //} // // //void CMainWndSettingsDlg::OnEnChangeMemoryEdit() //{ // // TODO: 如果该控件是 RICHEDIT 控件,它将不 // // 发送此通知,除非重写 CTabDlg::OnInitDialog() // // 函数并调用 CRichEditCtrl().SetEventMask(), // // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // // // TODO: 在此添加控件通知处理程序代码 // CString tmp; // GetDlgItemText(IDC_MEMORY_EDIT, tmp); // m_data.disp_str.Get(TDI_MEMORY) = tmp; //} //void CMainWndSettingsDlg::OnBnClickedSetDefaultButton() //{ // // TODO: 在此添加控件通知处理程序代码 // m_data.disp_str.Get(TDI_UP) = CCommon::LoadText(IDS_UPLOAD_DISP, _T(": ")); // m_data.disp_str.Get(TDI_DOWN) = CCommon::LoadText(IDS_DOWNLOAD_DISP, _T(": ")); // m_data.disp_str.Get(TDI_CPU) = L"CPU: "; // m_data.disp_str.Get(TDI_MEMORY) = CCommon::LoadText(IDS_MEMORY_DISP, _T(": ")); // SetDlgItemText(IDC_UPLOAD_EDIT, m_data.disp_str.Get(TDI_UP).c_str()); // SetDlgItemText(IDC_DOWNLOAD_EDIT, m_data.disp_str.Get(TDI_DOWN).c_str()); // SetDlgItemText(IDC_CPU_EDIT, m_data.disp_str.Get(TDI_CPU).c_str()); // SetDlgItemText(IDC_MEMORY_EDIT, m_data.disp_str.Get(TDI_MEMORY).c_str()); //} void CMainWndSettingsDlg::OnBnClickedSetFontButton() { // TODO: 在此添加控件通知处理程序代码 LOGFONT lf{}; lf.lfHeight = FontSizeToLfHeight(m_data.font.size); lf.lfWeight = (m_data.font.bold ? FW_BOLD : FW_NORMAL); lf.lfItalic = m_data.font.italic; lf.lfUnderline = m_data.font.underline; lf.lfStrikeOut = m_data.font.strike_out; lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS; //wcsncpy_s(lf.lfFaceName, m_data.font.name.GetString(), 32); CCommon::WStringCopy(lf.lfFaceName, 32, m_data.font.name.GetString()); CCommon::NormalizeFont(lf); CFontDialog fontDlg(&lf); //构造字体对话框,初始选择字体为之前字体 if (IDOK == fontDlg.DoModal()) // 显示字体对话框 { //获取字体信息 m_data.font.name = fontDlg.GetFaceName(); m_data.font.size = fontDlg.GetSize() / 10; m_data.font.bold = (fontDlg.IsBold() != FALSE); m_data.font.italic = (fontDlg.IsItalic() != FALSE); m_data.font.underline = (fontDlg.IsUnderline() != FALSE); m_data.font.strike_out = (fontDlg.IsStrikeOut() != FALSE); //将字体信息显示出来 SetDlgItemText(IDC_FONT_NAME_EDIT, m_data.font.name); wchar_t buff[16]; swprintf_s(buff, L"%d", m_data.font.size); SetDlgItemText(IDC_FONT_SIZE_EDIT, buff); } } void CMainWndSettingsDlg::OnBnClickedSwitchUpDownCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.swap_up_down = (((CButton*)GetDlgItem(IDC_SWITCH_UP_DOWN_CHECK))->GetCheck() != 0); } void CMainWndSettingsDlg::OnBnClickedFullscreenHideCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.hide_main_wnd_when_fullscreen = (((CButton*)GetDlgItem(IDC_FULLSCREEN_HIDE_CHECK))->GetCheck() != 0); } void CMainWndSettingsDlg::OnBnClickedSpeedShortModeCheck2() { // TODO: 在此添加控件通知处理程序代码 m_data.speed_short_mode = (((CButton*)GetDlgItem(IDC_SPEED_SHORT_MODE_CHECK2))->GetCheck() != 0); } void CMainWndSettingsDlg::OnCbnSelchangeUnitCombo() { // TODO: 在此添加控件通知处理程序代码 m_data.speed_unit = static_cast(m_unit_combo.GetCurSel()); if (m_data.speed_unit == SpeedUnit::AUTO) { m_hide_unit_chk.SetCheck(FALSE); m_data.hide_unit = false; m_hide_unit_chk.EnableWindow(FALSE); } else { m_hide_unit_chk.EnableWindow(TRUE); } } void CMainWndSettingsDlg::OnBnClickedHideUnitCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.hide_unit = (m_hide_unit_chk.GetCheck() != 0); } BOOL CMainWndSettingsDlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 if (pMsg->message == WM_MOUSEMOVE) m_toolTip.RelayEvent(pMsg); return CTabDlg::PreTranslateMessage(pMsg); } void CMainWndSettingsDlg::OnOK() { // TODO: 在此添加专用代码和/或调用基类 //获取字体设置 int font_size; font_size = m_font_size_edit.GetValue(); if (font_size > MAX_FONT_SIZE || font_size < MIN_FONT_SIZE) { CString info; info.Format(CCommon::LoadText(IDS_FONT_SIZE_WARNING), MIN_FONT_SIZE, MAX_FONT_SIZE); MessageBox(info, NULL, MB_OK | MB_ICONWARNING); } else { m_data.font.size = font_size; } GetDlgItemText(IDC_FONT_NAME_EDIT, m_data.font.name); CTabDlg::OnOK(); } void CMainWndSettingsDlg::OnBnClickedHidePercentageCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.hide_percent = (((CButton*)GetDlgItem(IDC_HIDE_PERCENTAGE_CHECK))->GetCheck() != 0); } afx_msg LRESULT CMainWndSettingsDlg::OnStaticClicked(WPARAM wParam, LPARAM lParam) { switch (::GetDlgCtrlID(((CWnd*)wParam)->m_hWnd)) { case IDC_TEXT_COLOR_STATIC: { //设置文本颜色 if (m_data.specify_each_item_color) { CMainWndColorDlg colorDlg(m_data.text_colors); if (colorDlg.DoModal() == IDOK) { m_data.text_colors = colorDlg.GetColors(); DrawStaticColor(); } } else if (!m_data.text_colors.empty()) { CMFCColorDialogEx colorDlg(m_data.text_colors.begin()->second, 0, this); if (colorDlg.DoModal() == IDOK) { m_data.text_colors.begin()->second = colorDlg.GetColor(); DrawStaticColor(); } } break; } default: break; } return 0; } void CMainWndSettingsDlg::OnBnClickedSpecifyEachItemColorCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.specify_each_item_color = (((CButton*)GetDlgItem(IDC_SPECIFY_EACH_ITEM_COLOR_CHECK))->GetCheck() != 0); DrawStaticColor(); } void CMainWndSettingsDlg::OnCbnSelchangeDoubleClickCombo() { // TODO: 在此添加控件通知处理程序代码 m_data.double_click_action = static_cast(m_double_click_combo.GetCurSel()); EnableControl(); } void CMainWndSettingsDlg::OnBnClickedSeparateValueUnitCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.separate_value_unit_with_space = (((CButton*)GetDlgItem(IDC_SEPARATE_VALUE_UNIT_CHECK))->GetCheck() != 0); } void CMainWndSettingsDlg::OnBnClickedUnitByteRadio() { // TODO: 在此添加控件通知处理程序代码 m_data.unit_byte = true; IniUnitCombo(); } void CMainWndSettingsDlg::OnBnClickedUnitBitRadio() { // TODO: 在此添加控件通知处理程序代码 m_data.unit_byte = false; IniUnitCombo(); } void CMainWndSettingsDlg::OnBnClickedShowToolTipChk() { // TODO: 在此添加控件通知处理程序代码 m_data.show_tool_tip = (((CButton*)GetDlgItem(IDC_SHOW_TOOL_TIP_CHK))->GetCheck() != 0); } void CMainWndSettingsDlg::OnBnClickedBrowseButton() { // TODO: 在此添加控件通知处理程序代码 CString szFilter = CCommon::LoadText(IDS_EXE_FILTER); CFileDialog fileDlg(TRUE, NULL, NULL, 0, szFilter, this); if (IDOK == fileDlg.DoModal()) { m_data.double_click_exe = fileDlg.GetPathName(); SetDlgItemText(IDC_EXE_PATH_EDIT, m_data.double_click_exe.c_str()); } } void CMainWndSettingsDlg::OnBnClickedDisplayTextSettingButton() { // TODO: 在此添加控件通知处理程序代码 CDisplayTextSettingDlg dlg(m_data.disp_str, true); dlg.DoModal(); } void CMainWndSettingsDlg::OnCbnSelchangeMemoryDisplayCombo() { // TODO: 在此添加控件通知处理程序代码 m_data.memory_display = static_cast(m_memory_display_combo.GetCurSel()); } void CMainWndSettingsDlg::OnBnClickedAlwaysOnTopCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.m_always_on_top = IsDlgButtonChecked(IDC_ALWAYS_ON_TOP_CHECK) != 0; } void CMainWndSettingsDlg::OnBnClickedMousePenetrateCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.m_mouse_penetrate = IsDlgButtonChecked(IDC_MOUSE_PENETRATE_CHECK) != 0; } void CMainWndSettingsDlg::OnBnClickedLockWindowPosCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.m_lock_window_pos = IsDlgButtonChecked(IDC_LOCK_WINDOW_POS_CHECK) != 0; } void CMainWndSettingsDlg::OnBnClickedAlowOutOfBorderCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.m_alow_out_of_border = IsDlgButtonChecked(IDC_ALOW_OUT_OF_BORDER_CHECK) != 0; } ================================================ FILE: TrafficMonitor/MainWndSettingsDlg.h ================================================ #pragma once #include "ColorStatic.h" #include "afxwin.h" #include "SpinEdit.h" #include "TabDlg.h" #include "MainWndColorDlg.h" #include "ComboBox2.h" // CMainWndSettingsDlg 对话框 class CMainWndSettingsDlg : public CTabDlg { DECLARE_DYNAMIC(CMainWndSettingsDlg) public: CMainWndSettingsDlg(CWnd* pParent = NULL); // 标准构造函数 virtual ~CMainWndSettingsDlg(); //选项设置数据 MainWndSettingData m_data; bool m_text_disable{ false }; //如果为true,则不允许设置“显示文本”,并不允许交换上传和下载的位置 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_MAIN_WND_SETTINGS_DIALOG }; #endif protected: //控件变量 CColorStatic m_color_static; CToolTipCtrl m_toolTip; CComboBox2 m_unit_combo; CButton m_hide_unit_chk; CSpinEdit m_font_size_edit; CComboBox2 m_double_click_combo; CComboBox2 m_memory_display_combo; protected: void DrawStaticColor(); void IniUnitCombo(); void EnableControl(); virtual void SetControlMouseWheelEnable(bool enable) override; virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); //afx_msg void OnEnChangeUploadEdit(); //afx_msg void OnEnChangeDownloadEdit(); //afx_msg void OnEnChangeCpuEdit(); //afx_msg void OnEnChangeMemoryEdit(); //afx_msg void OnBnClickedSetDefaultButton(); afx_msg void OnBnClickedSetFontButton(); afx_msg void OnBnClickedSwitchUpDownCheck(); afx_msg void OnBnClickedFullscreenHideCheck(); afx_msg void OnBnClickedSpeedShortModeCheck2(); afx_msg void OnCbnSelchangeUnitCombo(); afx_msg void OnBnClickedHideUnitCheck(); virtual BOOL PreTranslateMessage(MSG* pMsg); virtual void OnOK(); afx_msg void OnBnClickedHidePercentageCheck(); protected: afx_msg LRESULT OnStaticClicked(WPARAM wParam, LPARAM lParam); public: afx_msg void OnBnClickedSpecifyEachItemColorCheck(); afx_msg void OnCbnSelchangeDoubleClickCombo(); afx_msg void OnBnClickedSeparateValueUnitCheck(); afx_msg void OnBnClickedUnitByteRadio(); afx_msg void OnBnClickedUnitBitRadio(); afx_msg void OnBnClickedShowToolTipChk(); afx_msg void OnBnClickedBrowseButton(); afx_msg void OnBnClickedDisplayTextSettingButton(); afx_msg void OnCbnSelchangeMemoryDisplayCombo(); afx_msg void OnBnClickedAlwaysOnTopCheck(); afx_msg void OnBnClickedMousePenetrateCheck(); afx_msg void OnBnClickedLockWindowPosCheck(); afx_msg void OnBnClickedAlowOutOfBorderCheck(); }; ================================================ FILE: TrafficMonitor/MessageDlg.cpp ================================================ // HelpDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "MessageDlg.h" #include "DrawCommon.h" // CMessageDlg 对话框 #define MESSAGE_DLG_ICON_SIZE (theApp.DPI(32)) IMPLEMENT_DYNAMIC(CMessageDlg, CDialog) CMessageDlg::CMessageDlg(CWnd* pParent /*=NULL*/) : CDialog(IDD_MESSAGE_DIALOG, pParent) { } CMessageDlg::~CMessageDlg() { } void CMessageDlg::SetWindowTitle(LPCTSTR str) { m_title = str; } void CMessageDlg::SetInfoText(LPCTSTR str) { m_info = str; } void CMessageDlg::SetMessageText(LPCTSTR str) { m_message = str; } //void CMessageDlg::SetLinkInfo(LPCTSTR text, LPCTSTR url) //{ // m_link_text = text; // m_link_url = url; //} void CMessageDlg::SetMessageIcon(HICON hIcon) { m_icon = hIcon; } void CMessageDlg::SetInfoStaticSize(int cx) { if (m_icon != NULL && m_info_static.GetSafeHwnd() != NULL) { CRect rc_info{ m_rc_info }; rc_info.left = m_rc_info.left + MESSAGE_DLG_ICON_SIZE + theApp.DPI(8); if (cx > 0) rc_info.right = cx; m_info_static.MoveWindow(rc_info); } } void CMessageDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_HELP_EDIT, m_message_edit); DDX_Control(pDX, IDC_INFO_STATIC, m_info_static); } BEGIN_MESSAGE_MAP(CMessageDlg, CDialog) ON_WM_GETMINMAXINFO() //ON_NOTIFY(NM_CLICK, IDC_SYSLINK1, &CMessageDlg::OnNMClickSyslink1) ON_WM_PAINT() ON_WM_SIZE() END_MESSAGE_MAP() // CMessageDlg 消息处理程序 BOOL CMessageDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetIcon(AfxGetApp()->LoadIcon(IDR_MAINFRAME), FALSE); // 设置小图标 //获取初始时窗口的大小 CRect rect; GetWindowRect(rect); m_min_size.cx = rect.Width(); m_min_size.cy = rect.Height(); SetWindowText(m_title); m_info_static.SetWindowText(m_info); m_message_edit.SetWindowText(m_message); //CWnd* pLinkCtrl = GetDlgItem(IDC_SYSLINK1); //if (pLinkCtrl != nullptr) //{ // pLinkCtrl->ShowWindow(m_show_link_ctrl); // pLinkCtrl->SetWindowText(_T("") + m_link_text + _T("")); //} //设置图标的位置 if (m_icon != NULL) { CRect rc_edit; m_message_edit.GetWindowRect(rc_edit); ScreenToClient(rc_edit); m_icon_pos.x = rc_edit.left; m_icon_pos.y = (rc_edit.top - MESSAGE_DLG_ICON_SIZE) / 2; m_info_static.GetWindowRect(m_rc_info); ScreenToClient(m_rc_info); SetInfoStaticSize(0); } return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CMessageDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //限制窗口最小大小 lpMMI->ptMinTrackSize.x = m_min_size.cx; //设置最小宽度 lpMMI->ptMinTrackSize.y = m_min_size.cy; //设置最小高度 CDialog::OnGetMinMaxInfo(lpMMI); } //void CMessageDlg::OnNMClickSyslink1(NMHDR *pNMHDR, LRESULT *pResult) //{ // // TODO: 在此添加控件通知处理程序代码 // if(!m_link_url.IsEmpty()) // ShellExecute(NULL, _T("open"), m_link_url, NULL, NULL, SW_SHOW); //打开超链接 // // *pResult = 0; //} void CMessageDlg::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CDialog::OnPaint() CDrawCommon draw; draw.Create(&dc, this); draw.DrawIcon(m_icon, m_icon_pos, CSize(MESSAGE_DLG_ICON_SIZE, MESSAGE_DLG_ICON_SIZE)); } void CMessageDlg::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 SetInfoStaticSize(cx); } ================================================ FILE: TrafficMonitor/MessageDlg.h ================================================ #pragma once #include "afxwin.h" // CMessageDlg 对话框 class CMessageDlg : public CDialog { DECLARE_DYNAMIC(CMessageDlg) public: CMessageDlg(CWnd* pParent = NULL); // 标准构造函数 virtual ~CMessageDlg(); void SetWindowTitle(LPCTSTR str); void SetInfoText(LPCTSTR str); void SetMessageText(LPCTSTR str); //void ShowLinkStatic(bool show = true) { m_show_link_ctrl = show; } //void SetLinkInfo(LPCTSTR text, LPCTSTR url); void SetMessageIcon(HICON hIcon); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_MESSAGE_DIALOG }; #endif protected: CEdit m_message_edit; CSize m_min_size; //窗口的最小大小 CStatic m_info_static; CString m_title; CString m_info; CString m_message; //CString m_link_text; //CString m_link_url; HICON m_icon{}; CPoint m_icon_pos{}; //图标的位置 CRect m_rc_info{}; //错误信息Static控件的初始区域 //bool m_show_link_ctrl{ false }; protected: void SetInfoStaticSize(int cx); //如果设置了图标,则需要将错误信息Static控件向右移动一些 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI); //afx_msg void OnNMClickSyslink1(NMHDR *pNMHDR, LRESULT *pResult); afx_msg void OnPaint(); afx_msg void OnSize(UINT nType, int cx, int cy); }; ================================================ FILE: TrafficMonitor/NetworkInfoDlg.cpp ================================================ // CNetworkInfoDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "NetworkInfoDlg.h" #include "afxdialogex.h" // CNetworkInfoDlg 对话框 IMPLEMENT_DYNAMIC(CNetworkInfoDlg, CBaseDialog) CNetworkInfoDlg::CNetworkInfoDlg(vector& adapters, MIB_IFROW* pIfRow, int connection_selected, CWnd* pParent /*=NULL*/) : CBaseDialog(IDD_NETWORK_INFO_DIALOG, pParent), m_connections(adapters), m_pIfRow(pIfRow), m_connection_selected(connection_selected) { m_current_connection = connection_selected; } CNetworkInfoDlg::~CNetworkInfoDlg() { } void CNetworkInfoDlg::ShowInfo() { CString temp; MIB_IFROW& network_info = GetConnectIfTable(m_connection_selected); //接口名 m_info_list.SetItemText(0, 1, network_info.wszName); //接口描述 m_info_list.SetItemText(1, 1, CCommon::StrToUnicode((const char*)network_info.bDescr).c_str()); //连接类型 switch (network_info.dwType) { case IF_TYPE_OTHER: temp = CCommon::LoadText(IDS_IF_TYPE_OTHER); break; case IF_TYPE_ETHERNET_CSMACD: temp = CCommon::LoadText(IDS_IF_TYPE_ETHERNET_CSMACD); break; case IF_TYPE_ISO88025_TOKENRING: temp = CCommon::LoadText(IDS_IF_TYPE_ISO88025_TOKENRING); break; case IF_TYPE_FDDI: temp = CCommon::LoadText(IDS_IF_TYPE_FDDI); break; case IF_TYPE_PPP: temp = CCommon::LoadText(IDS_IF_TYPE_PPP); break; case IF_TYPE_SOFTWARE_LOOPBACK: temp = CCommon::LoadText(IDS_IF_TYPE_SOFTWARE_LOOPBACK); break; case IF_TYPE_ATM: temp = CCommon::LoadText(IDS_IF_TYPE_ATM); break; case IF_TYPE_IEEE80211: temp = CCommon::LoadText(IDS_IF_TYPE_IEEE80211); break; case IF_TYPE_TUNNEL: temp = CCommon::LoadText(IDS_IF_TYPE_TUNNEL); break; case IF_TYPE_IEEE1394: temp = CCommon::LoadText(IDS_IF_TYPE_IEEE1394); break; case IF_TYPE_IEEE80216_WMAN: temp = CCommon::LoadText(IDS_IF_TYPE_IEEE80216_WMAN); break; case IF_TYPE_WWANPP: temp = CCommon::LoadText(IDS_IF_TYPE_WWANPP); break; case IF_TYPE_WWANPP2: temp = CCommon::LoadText(IDS_IF_TYPE_WWANPP2); break; default: temp = CCommon::LoadText(IDS_UNKNOW_CONNECTION); break; } m_info_list.SetItemText(2, 1, temp); //速度 temp.Format(_T("%dMbps"), network_info.dwSpeed / 1000000); m_info_list.SetItemText(3, 1, temp); //适配器物理地址 temp = _T(""); char buff[3]; for (size_t i{}; i < network_info.dwPhysAddrLen; i++) { sprintf_s(buff, "%.2x", network_info.bPhysAddr[i]); temp += buff; if (i != network_info.dwPhysAddrLen - 1) temp += _T('-'); } m_info_list.SetItemText(4, 1, temp); //IP地址 m_info_list.SetItemText(5, 1, GetConnection(m_connection_selected).ip_address.c_str()); //子网掩码 m_info_list.SetItemText(6, 1, GetConnection(m_connection_selected).subnet_mask.c_str()); //默认网关 m_info_list.SetItemText(7, 1, GetConnection(m_connection_selected).default_gateway.c_str()); //连接状态 switch (network_info.dwOperStatus) { case IF_OPER_STATUS_NON_OPERATIONAL: temp = CCommon::LoadText(IDS_IF_OPER_STATUS_NON_OPERATIONAL); break; case IF_OPER_STATUS_UNREACHABLE: temp = CCommon::LoadText(IDS_IF_OPER_STATUS_UNREACHABLE); break; case IF_OPER_STATUS_DISCONNECTED: temp = CCommon::LoadText(IDS_IF_OPER_STATUS_DISCONNECTED); break; case IF_OPER_STATUS_CONNECTING: temp = CCommon::LoadText(IDS_IF_OPER_STATUS_CONNECTING); break; case IF_OPER_STATUS_CONNECTED: temp = CCommon::LoadText(IDS_IF_OPER_STATUS_CONNECTED); break; case IF_OPER_STATUS_OPERATIONAL: temp = CCommon::LoadText(IDS_IF_OPER_STATUS_OPERATIONAL); break; //case IfOperStatusUp: // temp = CCommon::LoadText(IDS_IF_OPER_STATUS_UP); // break; //case IfOperStatusDown: //case IfOperStatusNotPresent: //case IfOperStatusLowerLayerDown: // temp = CCommon::LoadText(IDS_IF_OPER_STATUS_DOWN); // break; //case IfOperStatusTesting: //case IfOperStatusUnknown: // temp = CCommon::LoadText(IDS_UNKNOW_STATUS); // break; //case IfOperStatusDormant: // temp = CCommon::LoadText(IDS_IF_OPER_STATUS_DORMANT); //break; default: temp = CCommon::LoadText(IDS_UNKNOW_STATUS); break; } m_info_list.SetItemText(8, 1, temp); //已接收字节数 temp.Format(_T("%s (%s)"), CCommon::IntToString(network_info.dwInOctets, true, true), CCommon::DataSizeToString(network_info.dwInOctets)); m_info_list.SetItemText(9, 1, temp); //已发送字节数 temp.Format(_T("%s (%s)"), CCommon::IntToString(network_info.dwOutOctets, true, true), CCommon::DataSizeToString(network_info.dwOutOctets)); m_info_list.SetItemText(10, 1, temp); //自程序启动以来已接收字节数 unsigned __int64 in_bytes_since_start; in_bytes_since_start = network_info.dwInOctets - GetConnection(m_connection_selected).in_bytes; temp.Format(_T("%s (%s)"), CCommon::IntToString(in_bytes_since_start, true, true), CCommon::DataSizeToString(in_bytes_since_start)); m_info_list.SetItemText(11, 1, temp); //自程序启动以来已发送字节数 unsigned __int64 out_bytes_since_start; out_bytes_since_start = network_info.dwOutOctets - GetConnection(m_connection_selected).out_bytes; temp.Format(_T("%s (%s)"), CCommon::IntToString(out_bytes_since_start, true, true), CCommon::DataSizeToString(out_bytes_since_start)); m_info_list.SetItemText(12, 1, temp); //显示当前选择指示 CString str; str.Format(_T("%d/%d"), m_connection_selected + 1, m_connections.size()); SetDlgItemText(IDC_INDEX_STATIC, str); CFont* font = GetFont(); CWnd* index_static = GetDlgItem(IDC_INDEX_STATIC); if (m_current_connection == m_connection_selected && !theApp.m_cfg_data.m_select_all) index_static->SetFont(&m_font_bold); else index_static->SetFont(font); } void CNetworkInfoDlg::GetProgramElapsedTime() { //程序已运行时间 SYSTEMTIME current_time, time; GetLocalTime(¤t_time); time = CCommon::CompareSystemTime(current_time, m_start_time); CString temp; temp.Format(CCommon::LoadText(IDS_HOUR_MINUTE_SECOND), time.wHour, time.wMinute, time.wSecond); m_info_list.SetItemText(13, 1, temp); } MIB_IFROW& CNetworkInfoDlg::GetConnectIfTable(int connection_index) { static MIB_IFROW nouse{}; if (connection_index >= 0 && connection_index < static_cast(m_connections.size())) { int index = m_connections[connection_index].index; if (m_pIfRow != nullptr) return m_pIfRow[index]; } return nouse; } NetWorkConection CNetworkInfoDlg::GetConnection(int connection_index) { if (connection_index >= 0 && connection_index < static_cast(m_connections.size())) return m_connections[connection_index]; else return NetWorkConection(); } UINT CNetworkInfoDlg::GetInternetIPThreadFunc(LPVOID lpParam) { CCommon::SetThreadLanguage(theApp.m_general_data.language); //设置线程语言 CNetworkInfoDlg* p_instance = (CNetworkInfoDlg*)lpParam; wstring ip_address, ip_location; //IPV4 CCommon::GetInternetIp2(ip_address, ip_location, false); //获取外网IP地址, if (!IsWindow(p_instance->GetSafeHwnd())) //如果当前对话框已经销毁,则退出线程 return 0; if (!ip_address.empty()) { CString info; if (ip_location.empty()) info = ip_address.c_str(); else info.Format(_T("%s (%s)"), ip_address.c_str(), ip_location.c_str()); p_instance->m_info_list.SetItemText(14, 1, info); } else { p_instance->m_info_list.SetItemText(14, 1, CCommon::LoadText(IDS_GET_FAILED)); } //IPV6 wstring ipv6_address, ipv6_location; CCommon::GetInternetIp2(ip_address, ip_location, true); //获取外网IP地址, if (!IsWindow(p_instance->GetSafeHwnd())) //如果当前对话框已经销毁,则退出线程 return 0; if (!ip_address.empty()) { CString info; if (ip_location.empty()) info = ip_address.c_str(); else info.Format(_T("%s (%s)"), ip_address.c_str(), ip_location.c_str()); p_instance->m_info_list.SetItemText(15, 1, info); } else { p_instance->m_info_list.SetItemText(15, 1, CCommon::LoadText(IDS_GET_FAILED)); } p_instance->m_ip_acquired = true; return 0; } CString CNetworkInfoDlg::GetDialogName() const { return _T("NetworkInfoDlg"); } void CNetworkInfoDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_INFO_LIST1, m_info_list); } BEGIN_MESSAGE_MAP(CNetworkInfoDlg, CBaseDialog) ON_COMMAND(ID_COPY_TEXT, &CNetworkInfoDlg::OnCopyText) ON_NOTIFY(NM_RCLICK, IDC_INFO_LIST1, &CNetworkInfoDlg::OnNMRClickInfoList1) ON_WM_CLOSE() ON_BN_CLICKED(IDC_PREVIOUS_BUTTON, &CNetworkInfoDlg::OnBnClickedPreviousButton) ON_BN_CLICKED(IDC_NEXT_BUTTON, &CNetworkInfoDlg::OnBnClickedNextButton) ON_WM_TIMER() ON_WM_MOUSEWHEEL() ON_NOTIFY(NM_DBLCLK, IDC_INFO_LIST1, &CNetworkInfoDlg::OnNMDblclkInfoList1) END_MESSAGE_MAP() // CNetworkInfoDlg 消息处理程序 BOOL CNetworkInfoDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetWindowText(CCommon::LoadText(IDS_TITLE_CONNECTION_DETIAL)); SetIcon(theApp.GetMenuIcon(IDI_INFO), FALSE); // 设置小图标 //重新获取IP地址 CAdapterCommon::RefreshIpAddress(m_connections); //初始化列表控件 CRect rect; m_info_list.GetClientRect(rect); m_info_list.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP); int width0, width1; width0 = rect.Width() / 4; width1 = rect.Width() - width0 - theApp.DPI(20) - 1; m_info_list.InsertColumn(0, CCommon::LoadText(IDS_ITEM), LVCFMT_LEFT, width0); //插入第0列 m_info_list.InsertColumn(1, CCommon::LoadText(IDS_VALUE), LVCFMT_LEFT, width1); //插入第1列 //向列表中插入行 m_info_list.InsertItem(0, CCommon::LoadText(IDS_INTERFACE_NAME)); m_info_list.InsertItem(1, CCommon::LoadText(IDS_INTERFACE_DESCRIPTION)); m_info_list.InsertItem(2, CCommon::LoadText(IDS_CONNECTION_TYPE)); m_info_list.InsertItem(3, CCommon::LoadText(IDS_SPEED)); m_info_list.InsertItem(4, CCommon::LoadText(IDS_ADAPTER_PHYSICAL_ADDRESS)); m_info_list.InsertItem(5, CCommon::LoadText(IDS_IP_ADDRESS)); m_info_list.InsertItem(6, CCommon::LoadText(IDS_SUBNET_MASK)); m_info_list.InsertItem(7, CCommon::LoadText(IDS_DEFAULT_GATEWAY)); m_info_list.InsertItem(8, CCommon::LoadText(IDS_OPERATIONAL_STATUS)); m_info_list.InsertItem(9, CCommon::LoadText(IDS_BYTES_RECEIVED)); m_info_list.InsertItem(10, CCommon::LoadText(IDS_BYTES_SENT)); m_info_list.InsertItem(11, CCommon::LoadText(IDS_BYTES_RECEIVED_SINCE_START)); m_info_list.InsertItem(12, CCommon::LoadText(IDS_BYTES_SENT_SINCE_START)); m_info_list.InsertItem(13, CCommon::LoadText(IDS_PROGRAM_ELAPSED_TIME)); m_info_list.InsertItem(14, CCommon::LoadText(IDS_INTERNET_IP_ADDRESS, _T(" (ipv4)"))); m_info_list.InsertItem(15, CCommon::LoadText(IDS_INTERNET_IP_ADDRESS, _T(" (ipv6)"))); //if (theApp.m_cfg_data.m_show_internet_ip) //{ // m_info_list.SetItemText(14, 1, CCommon::LoadText(IDS_ACQUIRING, _T("..."))); // m_info_list.SetItemText(15, 1, CCommon::LoadText(IDS_ACQUIRING, _T("..."))); //} //else //{ m_info_list.SetItemText(14, 1, CCommon::LoadText(IDS_DOUBLE_CLICK_TO_ACQUIRE)); m_info_list.SetItemText(15, 1, CCommon::LoadText(IDS_DOUBLE_CLICK_TO_ACQUIRE)); //} //显示列表中的信息 LOGFONT lf{}; GetFont()->GetLogFont(&lf); lf.lfWeight = FW_BOLD; m_font_bold.CreateFontIndirect(&lf); ShowInfo(); GetProgramElapsedTime(); //CCommon::GetInternetIp(); //if (theApp.m_cfg_data.m_show_internet_ip) // m_pGetIPThread = AfxBeginThread(GetInternetIPThreadFunc, this); //启动获取外网IP的线程 //SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); //取消置顶 m_info_list.GetToolTips()->SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); m_menu.LoadMenu(IDR_INFO_MENU); //装载右键菜单 SetTimer(CONNECTION_DETAIL_TIMER, 1000, NULL); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CNetworkInfoDlg::OnCopyText() { // TODO: 在此添加命令处理程序代码 if (!CCommon::CopyStringToClipboard(wstring(m_selected_string))) MessageBox(CCommon::LoadText(IDS_COPY_TO_CLIPBOARD_FAILED), NULL, MB_ICONWARNING); } void CNetworkInfoDlg::OnNMRClickInfoList1(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 //获取鼠标点击处的文本 int item, sub_item; item = pNMItemActivate->iItem; sub_item = pNMItemActivate->iSubItem; m_selected_string = m_info_list.GetItemText(item, sub_item); //弹出右键菜单 CMenu* pContextMenu = m_menu.GetSubMenu(0); //获取第一个弹出菜单 CPoint point1; //定义一个用于确定光标位置的位置 GetCursorPos(&point1); //获取当前光标的位置,以便使得菜单可以跟随光标 pContextMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, this); //在指定位置显示弹出菜单 *pResult = 0; } void CNetworkInfoDlg::OnClose() { // TODO: 在此添加消息处理程序代码和/或调用默认值 //对话框关闭时强制结束获取IP地址的线程 //if(theApp.m_cfg_data.m_show_internet_ip) // TerminateThread(m_pGetIPThread->m_hThread, 0); CBaseDialog::OnClose(); } void CNetworkInfoDlg::OnBnClickedPreviousButton() { // TODO: 在此添加控件通知处理程序代码 if (m_connections.size() > 1 && m_connection_selected > 0) { m_connection_selected--; ShowInfo(); } } void CNetworkInfoDlg::OnBnClickedNextButton() { // TODO: 在此添加控件通知处理程序代码 if (m_connections.size() > 1 && m_connection_selected < m_connections.size() - 1) { m_connection_selected++; ShowInfo(); } } BOOL CNetworkInfoDlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 if (pMsg->message == WM_KEYDOWN) { if (pMsg->wParam == VK_LEFT) { OnBnClickedPreviousButton(); return TRUE; } if (pMsg->wParam == VK_RIGHT) { OnBnClickedNextButton(); return TRUE; } } return CBaseDialog::PreTranslateMessage(pMsg); } void CNetworkInfoDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (nIDEvent == CONNECTION_DETAIL_TIMER) { GetProgramElapsedTime(); } CBaseDialog::OnTimer(nIDEvent); } BOOL CNetworkInfoDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //通过鼠标滚轮翻页 if (zDelta > 0) { OnBnClickedPreviousButton(); } if (zDelta < 0) { OnBnClickedNextButton(); } return CBaseDialog::OnMouseWheel(nFlags, zDelta, pt); } void CNetworkInfoDlg::OnNMDblclkInfoList1(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 if (/*!theApp.m_cfg_data.m_show_internet_ip && */!m_ip_acquired && (pNMItemActivate->iItem == 14 || pNMItemActivate->iItem == 15)) //双击了IP地址一行时 { m_info_list.SetItemText(14, 1, CCommon::LoadText(IDS_ACQUIRING, _T("..."))); m_info_list.SetItemText(15, 1, CCommon::LoadText(IDS_ACQUIRING, _T("..."))); m_pGetIPThread = AfxBeginThread(GetInternetIPThreadFunc, this); } *pResult = 0; } ================================================ FILE: TrafficMonitor/NetworkInfoDlg.h ================================================ #pragma once #include"Common.h" #include "afxcmn.h" #include "AdapterCommon.h" #include "BaseDialog.h" // CNetworkInfoDlg 对话框 class CNetworkInfoDlg : public CBaseDialog { DECLARE_DYNAMIC(CNetworkInfoDlg) public: CNetworkInfoDlg(vector& adapters, MIB_IFROW* pIfRow, int connection_selected, CWnd* pParent = NULL); // 标准构造函数 virtual ~CNetworkInfoDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_NETWORK_INFO_DIALOG }; #endif SYSTEMTIME m_start_time; //程序启动的时间 protected: vector& m_connections; MIB_IFROW* m_pIfRow; int m_connection_selected; //当前对话框显示的连接 int m_current_connection; //初始选择的连接 CListCtrl m_info_list; CMenu m_menu; CString m_selected_string; CFont m_font_bold; //默认字体的粗体 CWinThread* m_pGetIPThread; //获取外网IP的线程 bool m_ip_acquired{ false }; //如果已获取外网ip地址,则为true //void GetIPAddress(); //获取IP地址 void ShowInfo(); void GetProgramElapsedTime(); MIB_IFROW& GetConnectIfTable(int connection_index); //获取当前选择的网络连接的MIB_IFROW对象。connection_index为m_connections中的索引 NetWorkConection GetConnection(int connection_index); //获取当前选择的网络连接的NetWorkConection对象。connection_index为m_connections中的索引 //获取外网IP的线程函数 static UINT GetInternetIPThreadFunc(LPVOID lpParam); virtual CString GetDialogName() const override; virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() virtual BOOL OnInitDialog(); public: afx_msg void OnCopyText(); afx_msg void OnNMRClickInfoList1(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnClose(); afx_msg void OnBnClickedPreviousButton(); afx_msg void OnBnClickedNextButton(); virtual BOOL PreTranslateMessage(MSG* pMsg); afx_msg void OnTimer(UINT_PTR nIDEvent); afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); afx_msg void OnNMDblclkInfoList1(NMHDR* pNMHDR, LRESULT* pResult); }; ================================================ FILE: TrafficMonitor/OptionsDlg.cpp ================================================ // OptionsDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "OptionsDlg.h" #include "afxdialogex.h" // COptionsDlg 对话框 IMPLEMENT_DYNAMIC(COptionsDlg, CBaseDialog) COptionsDlg::COptionsDlg(int tab, CWnd* pParent /*=NULL*/) : CBaseDialog(IDD_OPTIONS_DIALOG, pParent), m_tab_selected{ tab } { } COptionsDlg::~COptionsDlg() { } CString COptionsDlg::GetDialogName() const { return OPTION_DLG_NAME; } void COptionsDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_TAB1, m_tab); } BEGIN_MESSAGE_MAP(COptionsDlg, CBaseDialog) ON_WM_SIZE() ON_BN_CLICKED(IDC_APPLY_BUTTON, &COptionsDlg::OnBnClickedApplyButton) END_MESSAGE_MAP() // COptionsDlg 消息处理程序 BOOL COptionsDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetWindowText(CCommon::LoadText(IDS_TITLE_OPTION)); SetIcon(theApp.GetMenuIcon(IDI_SETTINGS), FALSE); // 设置小图标 //创建子对话框 m_tab1_dlg.Create(IDD_MAIN_WND_SETTINGS_DIALOG, &m_tab); m_tab2_dlg.Create(IDD_TASKBAR_SETTINGS_DIALOG, &m_tab); m_tab3_dlg.Create(IDD_GENERAL_SETTINGS_DIALOG, &m_tab); //保存子对话框 m_tab_vect.push_back(&m_tab1_dlg); m_tab_vect.push_back(&m_tab2_dlg); m_tab_vect.push_back(&m_tab3_dlg); //获取子对话框的初始高度 for (const auto* pDlg : m_tab_vect) { CRect rect; pDlg->GetWindowRect(rect); m_tab_height.push_back(rect.Height()); } //添加对话框 m_tab.AddWindow(&m_tab1_dlg, CCommon::LoadText(IDS_MAIN_WINDOW_SETTINGS)); m_tab.AddWindow(&m_tab2_dlg, CCommon::LoadText(IDS_TASKBAR_WINDOW_SETTINGS)); m_tab.AddWindow(&m_tab3_dlg, CCommon::LoadText(IDS_GENERAL_SETTINGS)); //为每个子窗口设置滚动信息 for (size_t i = 0; i < m_tab_vect.size(); i++) { m_tab_vect[i]->SetScrollbarInfo(m_tab.m_tab_rect.Height(), m_tab_height[i]); } //设置默认选中的标签 if (m_tab_selected < 0 || m_tab_selected >= m_tab.GetItemCount()) m_tab_selected = 0; m_tab.SetCurTab(m_tab_selected); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void COptionsDlg::OnOK() { // TODO: 在此添加专用代码和/或调用基类 m_tab1_dlg.OnOK(); m_tab2_dlg.OnOK(); m_tab3_dlg.OnOK(); CBaseDialog::OnOK(); } void COptionsDlg::OnSize(UINT nType, int cx, int cy) { CBaseDialog::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 if (nType != SIZE_MINIMIZED) { //为每个子窗口设置滚动信息 for (size_t i = 0; i < m_tab_vect.size(); i++) { m_tab_vect[i]->ResetScroll(); m_tab_vect[i]->SetScrollbarInfo(m_tab.m_tab_rect.Height(), m_tab_height[i]); } } } void COptionsDlg::OnCancel() { // TODO: 在此添加专用代码和/或调用基类 m_tab3_dlg.OnCancel(); CBaseDialog::OnCancel(); } void COptionsDlg::OnBnClickedApplyButton() { m_tab2_dlg.SaveColorSettingToDefaultStyle(); ::SendMessage(theApp.m_pMainWnd->GetSafeHwnd(), WM_SETTINGS_APPLIED, (WPARAM)this, 0); } ================================================ FILE: TrafficMonitor/OptionsDlg.h ================================================ #pragma once #include "MainWndSettingsDlg.h" #include "TaskBarSettingsDlg.h" #include "GeneralSettingsDlg.h" #include "afxcmn.h" #include "CTabCtrlEx.h" #include "BaseDialog.h" // COptionsDlg 对话框 #define OPTION_DLG_NAME _T("OptionsDlg") class COptionsDlg : public CBaseDialog { DECLARE_DYNAMIC(COptionsDlg) public: COptionsDlg(int tab = 0, CWnd* pParent = NULL); // 标准构造函数 virtual ~COptionsDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_OPTIONS_DIALOG }; #endif CMainWndSettingsDlg m_tab1_dlg{ this }; CTaskBarSettingsDlg m_tab2_dlg{ this }; CGeneralSettingsDlg m_tab3_dlg{ this }; protected: CTabCtrlEx m_tab; int m_tab_selected; std::vector m_tab_vect; std::vector m_tab_height; virtual CString GetDialogName() const override; virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); virtual void OnOK(); afx_msg void OnSize(UINT nType, int cx, int cy); virtual void OnCancel(); afx_msg void OnBnClickedApplyButton(); }; ================================================ FILE: TrafficMonitor/PictureStatic.cpp ================================================ #include "stdafx.h" #include "PictureStatic.h" CPictureStatic::CPictureStatic() { } CPictureStatic::~CPictureStatic() { m_memDC.DeleteDC(); m_bitmap.Detach(); } void CPictureStatic::SetPicture(UINT pic_id) { m_memDC.DeleteDC(); if (!m_bitmap.LoadBitmap(pic_id)) //λͼ return; //ȡͼʵʴС GetObject(m_bitmap, sizeof(BITMAP), &m_bm); CDC* pDC = GetDC(); m_memDC.CreateCompatibleDC(pDC); m_memDC.SelectObject(&m_bitmap); //ȡؼС GetClientRect(m_rect); //ֶػ Invalidate(); } void CPictureStatic::SetPicture(HBITMAP hBitmap) { m_memDC.DeleteDC(); m_bitmap.Detach(); if (!m_bitmap.Attach(hBitmap)) return; //ȡͼʵʴС GetObject(m_bitmap, sizeof(BITMAP), &m_bm); CDC* pDC = GetDC(); m_memDC.CreateCompatibleDC(pDC); m_memDC.SelectObject(&m_bitmap); //ȡؼС GetClientRect(m_rect); //ֶػ Invalidate(); } BEGIN_MESSAGE_MAP(CPictureStatic, CStatic) ON_WM_PAINT() END_MESSAGE_MAP() void CPictureStatic::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: ڴ˴Ϣ // ΪͼϢ CStatic::OnPaint() if (m_bitmap.m_hObject != NULL) { // бͼƬʧ dc.SetStretchBltMode(HALFTONE); dc.SetBrushOrg(0, 0); //ƽڴDCеͼ dc.StretchBlt(0, 0, m_rect.Width(), m_rect.Height(), &m_memDC, 0, 0, m_bm.bmWidth, m_bm.bmHeight, SRCCOPY); //򸸴ڷػϢ CWnd* pParent{ GetParent() }; if (pParent != nullptr) pParent->SendMessage(WM_CONTROL_REPAINT, (WPARAM)this, LPARAM(&dc)); } } ================================================ FILE: TrafficMonitor/PictureStatic.h ================================================ /*һʾͼƬľ̬ؼ ҪʱSetPicture()þ̬ͼƬ ؼػʱ򸸴ڷWM_CONTROL_REPAINTϢ ͨwParamݵǰؼCWndָ룬ͨlParamCDCָ */ #pragma once #define WM_CONTROL_REPAINT (WM_USER + 1003) //ؼػϢ class CPictureStatic : public CStatic { public: CPictureStatic(); ~CPictureStatic(); void SetPicture(UINT pic_id); void SetPicture(HBITMAP hBitmap); protected: CDC m_memDC; CBitmap m_bitmap; CRect m_rect; BITMAP m_bm; public: DECLARE_MESSAGE_MAP() afx_msg void OnPaint(); }; ================================================ FILE: TrafficMonitor/PluginInfoDlg.cpp ================================================ // PluginInfoDlg.cpp: 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "PluginInfoDlg.h" #include "FilePathHelper.h" // CPluginInfoDlg 对话框 IMPLEMENT_DYNAMIC(CPluginInfoDlg, CBaseDialog) CPluginInfoDlg::CPluginInfoDlg(int plugin_index, CWnd* pParent /*=nullptr*/) : CBaseDialog(IDD_NETWORK_INFO_DIALOG, pParent), m_cur_index(plugin_index) { if (m_cur_index < 0 || m_cur_index >= static_cast(theApp.m_plugins.GetPlugins().size())) m_cur_index = 0; } CPluginInfoDlg::~CPluginInfoDlg() { } void CPluginInfoDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_INFO_LIST1, m_info_list); } void CPluginInfoDlg::ShowInfo() { if (m_cur_index >= 0 && m_cur_index < static_cast(theApp.m_plugins.GetPlugins().size())) { auto& plugin_info = theApp.m_plugins.GetPlugins()[m_cur_index]; m_info_list.SetItemText(RI_NAME, 1, plugin_info.Property(ITMPlugin::TMI_NAME).c_str()); m_info_list.SetItemText(RI_DESCRIPTION, 1, plugin_info.Property(ITMPlugin::TMI_DESCRIPTION).c_str()); m_info_list.SetItemText(RI_FILE_NAME, 1, CFilePathHelper(plugin_info.file_path).GetFileName().c_str()); m_info_list.SetItemText(RI_FILE_PATH, 1, plugin_info.file_path.c_str()); m_info_list.SetItemText(RI_ITEM_NUM, 1, std::to_wstring(plugin_info.plugin_items.size()).c_str()); wstring item_names; wstring item_id; for (const auto& item : plugin_info.plugin_items) { item_names += item->GetItemName(); item_names += L";"; item_id += item->GetItemId(); item_id += L";"; } if (!plugin_info.plugin_items.empty()) { item_names.pop_back(); item_id.pop_back(); } m_info_list.SetItemText(RI_ITEM_NAMES, 1, item_names.c_str()); m_info_list.SetItemText(RI_ITEM_ID, 1, item_id.c_str()); m_info_list.SetItemText(RI_AUTHOR, 1, plugin_info.Property(ITMPlugin::TMI_AUTHOR).c_str()); m_info_list.SetItemText(RI_COPYRIGHT, 1, plugin_info.Property(ITMPlugin::TMI_COPYRIGHT).c_str()); m_info_list.SetItemText(RI_URL, 1, plugin_info.Property(ITMPlugin::TMI_URL).c_str()); m_info_list.SetItemText(RI_VERSION, 1, plugin_info.Property(ITMPlugin::TMI_VERSION).c_str()); if (plugin_info.plugin != nullptr) m_info_list.SetItemText(RI_API_VERSION, 1, std::to_wstring(plugin_info.plugin->GetAPIVersion()).c_str()); } //显示当前选择指示 CString str; str.Format(_T("%d/%d"), m_cur_index + 1, theApp.m_plugins.GetPlugins().size()); SetDlgItemText(IDC_INDEX_STATIC, str); } BEGIN_MESSAGE_MAP(CPluginInfoDlg, CBaseDialog) ON_COMMAND(ID_COPY_TEXT, &CPluginInfoDlg::OnCopyText) ON_NOTIFY(NM_RCLICK, IDC_INFO_LIST1, &CPluginInfoDlg::OnNMRClickInfoList1) ON_BN_CLICKED(IDC_PREVIOUS_BUTTON, &CPluginInfoDlg::OnBnClickedPreviousButton) ON_BN_CLICKED(IDC_NEXT_BUTTON, &CPluginInfoDlg::OnBnClickedNextButton) ON_WM_MOUSEWHEEL() END_MESSAGE_MAP() // CPluginInfoDlg 消息处理程序 BOOL CPluginInfoDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetWindowText(CCommon::LoadText(IDS_PLUGIN_INFO)); SetIcon(theApp.GetMenuIcon(IDI_PLUGINS), FALSE); // 设置小图标 //初始化列表控件 CRect rect; m_info_list.GetClientRect(rect); m_info_list.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP); int width0, width1; width0 = rect.Width() / 4; width1 = rect.Width() - width0 - theApp.DPI(20) - 1; m_info_list.InsertColumn(0, CCommon::LoadText(IDS_ITEM), LVCFMT_LEFT, width0); m_info_list.InsertColumn(1, CCommon::LoadText(IDS_VALUE), LVCFMT_LEFT, width1); //向列表中插入行 for (int i = 0; i < RI_MAX; i++) { m_info_list.InsertItem(i, GetRowName(i)); } //显示列表中的信息 ShowInfo(); m_info_list.GetToolTips()->SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); m_menu.LoadMenu(IDR_INFO_MENU); //装载右键菜单 return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } CString CPluginInfoDlg::GetDialogName() const { return _T("PluginInfoDlg"); } void CPluginInfoDlg::OnCopyText() { if (!CCommon::CopyStringToClipboard(wstring(m_selected_string))) MessageBox(CCommon::LoadText(IDS_COPY_TO_CLIPBOARD_FAILED), NULL, MB_ICONWARNING); } void CPluginInfoDlg::OnNMRClickInfoList1(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 //获取鼠标点击处的文本 int item, sub_item; item = pNMItemActivate->iItem; sub_item = pNMItemActivate->iSubItem; m_selected_string = m_info_list.GetItemText(item, sub_item); //弹出右键菜单 CMenu* pContextMenu = m_menu.GetSubMenu(0); //获取第一个弹出菜单 CPoint point1; //定义一个用于确定光标位置的位置 GetCursorPos(&point1); //获取当前光标的位置,以便使得菜单可以跟随光标 pContextMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, this); //在指定位置显示弹出菜单 *pResult = 0; } void CPluginInfoDlg::OnBnClickedPreviousButton() { if (m_cur_index > 0) { m_cur_index--; ShowInfo(); } } void CPluginInfoDlg::OnBnClickedNextButton() { if (m_cur_index < static_cast(theApp.m_plugins.GetPlugins().size() - 1)) { m_cur_index++; ShowInfo(); } } BOOL CPluginInfoDlg::PreTranslateMessage(MSG* pMsg) { if (pMsg->message == WM_KEYDOWN) { if (pMsg->wParam == VK_LEFT) { OnBnClickedPreviousButton(); return TRUE; } if (pMsg->wParam == VK_RIGHT) { OnBnClickedNextButton(); return TRUE; } } return CBaseDialog::PreTranslateMessage(pMsg); } BOOL CPluginInfoDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { //通过鼠标滚轮翻页 if (zDelta > 0) { OnBnClickedPreviousButton(); } if (zDelta < 0) { OnBnClickedNextButton(); } return CBaseDialog::OnMouseWheel(nFlags, zDelta, pt); } CString CPluginInfoDlg::GetRowName(int row_index) { switch (row_index) { case CPluginInfoDlg::RI_NAME: return CCommon::LoadText(IDS_NAME); case CPluginInfoDlg::RI_DESCRIPTION: return CCommon::LoadText(IDS_DESCRIPTION); case CPluginInfoDlg::RI_FILE_NAME: return CCommon::LoadText(IDS_FILE_NAME); case CPluginInfoDlg::RI_FILE_PATH: return CCommon::LoadText(IDS_FILE_PATH); case CPluginInfoDlg::RI_ITEM_NUM: return CCommon::LoadText(IDS_ITEM_NUM); case CPluginInfoDlg::RI_ITEM_NAMES: return CCommon::LoadText(IDS_ITEM_NAMES); case CPluginInfoDlg::RI_ITEM_ID: return CCommon::LoadText(IDS_DISP_ITEM_ID); case CPluginInfoDlg::RI_AUTHOR: return CCommon::LoadText(IDS_AUTHOR); case CPluginInfoDlg::RI_COPYRIGHT: return CCommon::LoadText(IDS_COPYRIGHT); case CPluginInfoDlg::RI_URL: return CCommon::LoadText(IDS_URL); case CPluginInfoDlg::RI_VERSION: return CCommon::LoadText(IDS_VERSION); case CPluginInfoDlg::RI_API_VERSION: return CCommon::LoadText(IDS_PLUGIN_API_VERSION); default: break; } return CString(); } ================================================ FILE: TrafficMonitor/PluginInfoDlg.h ================================================ #pragma once #include "BaseDialog.h" // CPluginInfoDlg 对话框 class CPluginInfoDlg : public CBaseDialog { DECLARE_DYNAMIC(CPluginInfoDlg) public: CPluginInfoDlg(int plugin_index, CWnd* pParent = nullptr); // 标准构造函数 virtual ~CPluginInfoDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_NETWORK_INFO_DIALOG }; #endif private: int m_cur_index; //初始显示的插件索引 CListCtrl m_info_list; CMenu m_menu; CString m_selected_string; //列表中的列 enum RowIndex { RI_FILE_NAME, RI_FILE_PATH, RI_NAME, RI_DESCRIPTION, RI_ITEM_NUM, RI_ITEM_NAMES, RI_ITEM_ID, RI_AUTHOR, RI_COPYRIGHT, RI_URL, RI_VERSION, RI_API_VERSION, RI_MAX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 void ShowInfo(); static CString GetRowName(int row_index); //获取行的名称 // 通过 CBaseDialog 继承 virtual CString GetDialogName() const override; DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnCopyText(); afx_msg void OnNMRClickInfoList1(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnBnClickedPreviousButton(); afx_msg void OnBnClickedNextButton(); virtual BOOL PreTranslateMessage(MSG* pMsg); afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); }; ================================================ FILE: TrafficMonitor/PluginManager.cpp ================================================ #include "stdafx.h" #include "PluginManager.h" #include "Common.h" #include "TrafficMonitor.h" #define PLUGIN_UNSUPPORT_VERSION 0 //不被支持的插件版本 CPluginManager::CPluginManager() { } CPluginManager::~CPluginManager() { //卸载插件 for (const auto& m : m_modules) FreeLibrary(m.plugin_module); } static wstring WcharArrayToWString(const wchar_t* str) { if (str == nullptr) return wstring(); else return wstring(str); } void CPluginManager::LoadPlugins() { //从plugins目录下加载插件 wstring plugin_dir; plugin_dir = CCommon::GetModuleDir() + L"plugins"; vector plugin_files; CCommon::GetFiles((plugin_dir + L"\\*.dll").c_str(), plugin_files); //获取Plugins目录下所有的dll文件的文件名 for (const auto& file : plugin_files) { //插件信息 m_modules.push_back(PluginInfo()); PluginInfo& plugin_info{ m_modules.back() }; //插件dll的路径 plugin_info.file_path = plugin_dir + file; //插件文件名 std::wstring file_name{ file }; if (!file_name.empty() && (file_name[0] == L'\\' || file_name[0] == L'/')) file_name = file_name.substr(1); //如果插件被禁用,则不加载插件 if (theApp.m_cfg_data.plugin_disabled.Contains(file_name)) { plugin_info.state = PluginState::PS_DISABLE; continue; } //载入dll plugin_info.plugin_module = LoadLibrary(plugin_info.file_path.c_str()); if (plugin_info.plugin_module == NULL) { plugin_info.state = PluginState::PS_MUDULE_LOAD_FAILED; plugin_info.error_code = GetLastError(); continue; } //获取函数的入口地址 pfTMPluginGetInstance TMPluginGetInstance = (pfTMPluginGetInstance)::GetProcAddress(plugin_info.plugin_module, "TMPluginGetInstance"); if (TMPluginGetInstance == NULL) { plugin_info.state = PluginState::PS_FUNCTION_GET_FAILED; plugin_info.error_code = GetLastError(); continue; } //创建插件对象 plugin_info.plugin = TMPluginGetInstance(); if (plugin_info.plugin == nullptr) continue; //检查插件版本 int version = plugin_info.plugin->GetAPIVersion(); if (version <= PLUGIN_UNSUPPORT_VERSION) { plugin_info.state = PluginState::PS_VERSION_NOT_SUPPORT; continue; } //获取插件信息 for (int i{}; i < ITMPlugin::TMI_MAX; i++) { ITMPlugin::PluginInfoIndex index{ static_cast(i) }; plugin_info.properties[index] = WcharArrayToWString(plugin_info.plugin->GetInfo(index)); } //获取插件显示项目 int index = 0; while (true) { IPluginItem* item = plugin_info.plugin->GetItem(index); if (item == nullptr) break; plugin_info.plugin_items.push_back(item); m_plugins.push_back(item); m_plguin_item_map[item] = plugin_info.plugin; index++; } } //初始化所有任务栏显示项目 for (const auto& display_item : AllDisplayItems) { m_all_display_items_with_plugins.insert(display_item); } for (const auto& display_item : m_plugins) { m_all_display_items_with_plugins.insert(display_item); } } const std::vector& CPluginManager::GetPluginItems() const { return m_plugins; } const std::vector& CPluginManager::GetPlugins() const { return m_modules; } IPluginItem* CPluginManager::GetItemById(const std::wstring& item_id) { for (const auto& item : m_plugins) { if (item->GetItemId() == item_id) return item; } return nullptr; } IPluginItem* CPluginManager::GetItemByIndex(int index) { if (index >= 0 && index < static_cast(m_plugins.size())) return m_plugins[index]; return nullptr; } int CPluginManager::GetItemIndex(IPluginItem* item) const { for (auto iter = m_plugins.begin(); iter != m_plugins.end(); ++iter) { if (*iter == item) return iter - m_plugins.begin(); } return -1; } ITMPlugin* CPluginManager::GetPluginByItem(IPluginItem* pItem) { if (pItem == nullptr) return nullptr; return m_plguin_item_map[pItem]; } void CPluginManager::EnumPlugin(std::function func) const { for (const auto& item : m_modules) { if (item.plugin != nullptr) { func(item.plugin); } } } void CPluginManager::EnumPluginItem(std::function func) const { for (const auto& item : m_plugins) { if (item != nullptr) { func(item); } } } const std::set& CPluginManager::AllDisplayItemsWithPlugins() { return m_all_display_items_with_plugins; } int CPluginManager::GetItemWidth(IPluginItem* pItem, CDC* pDC) { int width = 0; ITMPlugin* plugin = GetPluginByItem(pItem); if (plugin != nullptr && plugin->GetAPIVersion() >= 3) { width = pItem->GetItemWidthEx(pDC->GetSafeHdc()); //优先使用GetItemWidthEx接口获取宽度 } if (width == 0) { width = theApp.DPI(pItem->GetItemWidth()); } return width; } std::wstring CPluginManager::PluginInfo::Property(ITMPlugin::PluginInfoIndex index) const { auto iter = properties.find(index); if (iter != properties.end()) return iter->second; return wstring(); } ================================================ FILE: TrafficMonitor/PluginManager.h ================================================ #pragma once #include "PluginInterface.h" #include #include "TaskbarItemOrderHelper.h" #include typedef ITMPlugin* (*pfTMPluginGetInstance)(); //用于加载和管理插件 class CPluginManager { public: //插件的状态 enum class PluginState { PS_SUCCEED, //载入成功 PS_MUDULE_LOAD_FAILED, //dll加载失败 PS_FUNCTION_GET_FAILED, //插件函数获取失败 PS_VERSION_NOT_SUPPORT, //插件版本不被支持 PS_DISABLE //已禁用 }; //插件信息 struct PluginInfo { wstring file_path; //文件路径 HMODULE plugin_module{}; //dll module ITMPlugin* plugin{}; //插件对象 std::vector plugin_items; //插件提供的所有显示项目 PluginState state{}; //插件的状态 DWORD error_code{}; //错误代码(GetLastError的返回值) std::map properties; //插件属性 std::wstring Property(ITMPlugin::PluginInfoIndex) const; }; CPluginManager(); ~CPluginManager(); void LoadPlugins(); const std::vector& GetPluginItems() const; const std::vector& GetPlugins() const; IPluginItem* GetItemById(const std::wstring& item_id); IPluginItem* GetItemByIndex(int index); int GetItemIndex(IPluginItem* item) const; ITMPlugin* GetPluginByItem(IPluginItem* pItem); //遍历所有插件 //func: 参数为遍历到的ITMPlugin对象 void EnumPlugin(std::function func) const; //遍历所有插件项目 //func: 参数为遍历到的IPluginItem对象 void EnumPluginItem(std::function func) const; const std::set& AllDisplayItemsWithPlugins(); int GetItemWidth(IPluginItem* pItem, CDC* pDC); private: std::vector m_plugins; std::vector m_modules; std::set m_all_display_items_with_plugins; //包含插件在内的所有任务栏显示项目 std::map m_plguin_item_map; //用于根据插件项目查找对应插件的map }; ================================================ FILE: TrafficMonitor/PluginManagerDlg.cpp ================================================ // PluginManagerDlg.cpp: 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "PluginManagerDlg.h" #include "FilePathHelper.h" #include "PluginInfoDlg.h" // CPluginManagerDlg 对话框 IMPLEMENT_DYNAMIC(CPluginManagerDlg, CBaseDialog) CPluginManagerDlg::CPluginManagerDlg(CWnd* pParent /*=nullptr*/) : CBaseDialog(IDD_PLUGIN_MANAGER_DIALOG, pParent) { } CPluginManagerDlg::~CPluginManagerDlg() { } void CPluginManagerDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST1, m_list_ctrl); DDX_Control(pDX, IDC_PLUGIN_DOWNLOAD_STATIC, m_plugin_download_lnk); DDX_Control(pDX, IDC_PLUGIN_DEV_GUID_STATIC, m_plugin_dev_guide_lnk); DDX_Control(pDX, IDC_OPEN_PLUGIN_DIR_STATIC, m_open_plugin_dir_lnk); } void CPluginManagerDlg::EnableControl() { bool enable{ IsSelectedPluginEnable() }; EnableDlgCtrl(IDC_OPTINS_BUTTON, enable); EnableDlgCtrl(IDC_PLUGIN_INFO_BUTTON, enable); } bool CPluginManagerDlg::IsSelectedValid() { return m_item_selected >= 0 && m_item_selected < static_cast(theApp.m_plugins.GetPlugins().size()); } bool CPluginManagerDlg::IsSelectedPluginEnable() { CPluginManager::PluginInfo plugin_info{}; bool plugin_loaded{ false }; if (IsSelectedValid()) { plugin_info = theApp.m_plugins.GetPlugins()[m_item_selected]; plugin_loaded = (plugin_info.state == CPluginManager::PluginState::PS_SUCCEED); } return plugin_loaded; } CString CPluginManagerDlg::GetDialogName() const { return _T("PluginManagerDlg"); } BEGIN_MESSAGE_MAP(CPluginManagerDlg, CBaseDialog) ON_NOTIFY(NM_RCLICK, IDC_LIST1, &CPluginManagerDlg::OnNMRClickList1) ON_NOTIFY(NM_CLICK, IDC_LIST1, &CPluginManagerDlg::OnNMClickList1) ON_BN_CLICKED(IDC_OPTINS_BUTTON, &CPluginManagerDlg::OnBnClickedOptinsButton) ON_BN_CLICKED(IDC_PLUGIN_INFO_BUTTON, &CPluginManagerDlg::OnBnClickedPluginInfoButton) ON_NOTIFY(NM_DBLCLK, IDC_LIST1, &CPluginManagerDlg::OnNMDblclkList1) ON_WM_INITMENU() ON_COMMAND(ID_PLUGIN_DETAIL, &CPluginManagerDlg::OnPluginDetail) ON_COMMAND(ID_PLUGIN_OPTIONS, &CPluginManagerDlg::OnPluginOptions) ON_COMMAND(ID_PLUGIN_DISABLE, &CPluginManagerDlg::OnPluginDisable) ON_MESSAGE(WM_LINK_CLICKED, &CPluginManagerDlg::OnLinkClicked) END_MESSAGE_MAP() // CPluginManagerDlg 消息处理程序 BOOL CPluginManagerDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetIcon(theApp.GetMenuIcon(IDI_PLUGINS), FALSE); //初始化列表控件 CRect rect; m_list_ctrl.GetClientRect(rect); m_list_ctrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP); int width0, width1, width2; width0 = width1 = rect.Width() / 3; width2 = rect.Width() - width0 - width1 - theApp.DPI(20) - 1; m_list_ctrl.InsertColumn(0, CCommon::LoadText(IDS_FILE_NAME), LVCFMT_LEFT, width0); m_list_ctrl.InsertColumn(1, CCommon::LoadText(IDS_PLUGIN_NAME), LVCFMT_LEFT, width1); m_list_ctrl.InsertColumn(2, CCommon::LoadText(IDS_STATUS), LVCFMT_LEFT, width2); //向列表中插入行 for (const auto& plugin : theApp.m_plugins.GetPlugins()) { std::wstring file_name = CFilePathHelper(plugin.file_path).GetFileName(); CString status; switch (plugin.state) { case CPluginManager::PluginState::PS_SUCCEED: status = CCommon::LoadText(IDS_PLUGIN_LOAD_SUCCEED); break; case CPluginManager::PluginState::PS_MUDULE_LOAD_FAILED: status = CCommon::LoadTextFormat(IDS_PLUGIN_MODULE_LOAD_FAILED, { static_cast(plugin.error_code) }); break; case CPluginManager::PluginState::PS_FUNCTION_GET_FAILED: status = CCommon::LoadTextFormat(IDS_PLUGIN_FUNCTION_GET_FAILED, { static_cast(plugin.error_code) }); break; case CPluginManager::PluginState::PS_DISABLE: status = CCommon::LoadText(IDS_DISABLED); break; case CPluginManager::PluginState::PS_VERSION_NOT_SUPPORT: status = CCommon::LoadText(IDS_PLUGIN_VERSION_NOT_SUPPORT); break; default: break; } int index = m_list_ctrl.GetItemCount(); m_list_ctrl.InsertItem(index, file_name.c_str()); m_list_ctrl.SetItemText(index, 1, plugin.Property(ITMPlugin::TMI_NAME).c_str()); m_list_ctrl.SetItemText(index, 2, status); } m_plugin_download_lnk.SetURL(L"https://github.com/zhongyang219/TrafficMonitorPlugins/blob/main/download/plugin_download.md"); m_plugin_dev_guide_lnk.SetURL(L"https://github.com/zhongyang219/TrafficMonitor/wiki/%E6%8F%92%E4%BB%B6%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97"); m_open_plugin_dir_lnk.SetLinkIsURL(false); EnableControl(); m_menu.LoadMenu(IDR_PLUGIN_MANAGER_MENU); //装载右键菜单 return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CPluginManagerDlg::OnNMRClickList1(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 m_item_selected = pNMItemActivate->iItem; EnableControl(); //弹出右键菜单 CMenu* pContextMenu = m_menu.GetSubMenu(0); //获取第一个弹出菜单 CPoint point1; //定义一个用于确定光标位置的位置 GetCursorPos(&point1); //获取当前光标的位置,以便使得菜单可以跟随光标 pContextMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, this); //在指定位置显示弹出菜单 *pResult = 0; } void CPluginManagerDlg::OnNMClickList1(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 m_item_selected = pNMItemActivate->iItem; EnableControl(); *pResult = 0; } void CPluginManagerDlg::OnBnClickedOptinsButton() { // TODO: 在此添加控件通知处理程序代码 if (m_item_selected >= 0 && m_item_selected < static_cast(theApp.m_plugins.GetPlugins().size())) { auto plugin_info = theApp.m_plugins.GetPlugins()[m_item_selected]; if (plugin_info.plugin != nullptr) { ITMPlugin::OptionReturn rtn = plugin_info.plugin->ShowOptionsDialog(m_hWnd); if (rtn == ITMPlugin::OR_OPTION_NOT_PROVIDED) MessageBox(CCommon::LoadText(IDS_PLUGIN_NO_OPTIONS_INFO), nullptr, MB_ICONINFORMATION | MB_OK); //else if (rtn == ITMPlugin::OR_OPTION_CHANGED) // theApp.m_pMainWnd->SendMessage(WM_REOPEN_TASKBAR_WND); } } } void CPluginManagerDlg::OnBnClickedPluginInfoButton() { // TODO: 在此添加控件通知处理程序代码 if (IsSelectedPluginEnable()) { CPluginInfoDlg dlg(m_item_selected); dlg.DoModal(); } } void CPluginManagerDlg::OnNMDblclkList1(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 m_item_selected = pNMItemActivate->iItem; OnBnClickedPluginInfoButton(); *pResult = 0; } void CPluginManagerDlg::OnInitMenu(CMenu* pMenu) { CBaseDialog::OnInitMenu(pMenu); // TODO: 在此处添加消息处理程序代码 bool enable{ IsSelectedPluginEnable() }; pMenu->EnableMenuItem(ID_PLUGIN_DETAIL, MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED)); pMenu->EnableMenuItem(ID_PLUGIN_OPTIONS, MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED)); pMenu->EnableMenuItem(ID_PLUGIN_DISABLE, MF_BYCOMMAND | (IsSelectedValid() ? MF_ENABLED : MF_GRAYED)); bool disabled{}; CPluginManager::PluginInfo plugin_info; if (m_item_selected >= 0 && m_item_selected < static_cast(theApp.m_plugins.GetPlugins().size())) { plugin_info = theApp.m_plugins.GetPlugins()[m_item_selected]; std::wstring file_name = CFilePathHelper(plugin_info.file_path).GetFileName(); disabled = theApp.m_cfg_data.plugin_disabled.Contains(file_name); } pMenu->CheckMenuItem(ID_PLUGIN_DISABLE, MF_BYCOMMAND | (disabled ? MF_CHECKED : MF_UNCHECKED)); } void CPluginManagerDlg::OnPluginDetail() { OnBnClickedOptinsButton(); } void CPluginManagerDlg::OnPluginOptions() { OnBnClickedOptinsButton(); } void CPluginManagerDlg::OnPluginDisable() { if (m_item_selected >= 0 && m_item_selected < static_cast(theApp.m_plugins.GetPlugins().size())) { CPluginManager::PluginInfo plugin_info = theApp.m_plugins.GetPlugins()[m_item_selected]; std::wstring file_name = CFilePathHelper(plugin_info.file_path).GetFileName(); bool disabled = theApp.m_cfg_data.plugin_disabled.Contains(file_name); theApp.m_cfg_data.plugin_disabled.SetStrContained(file_name, !disabled); MessageBox(CCommon::LoadText(IDS_RESTART_TO_APPLY_CHANGE_INFO), nullptr, MB_OK | MB_ICONINFORMATION); } } afx_msg LRESULT CPluginManagerDlg::OnLinkClicked(WPARAM wParam, LPARAM lParam) { CWnd* pCtrl = (CWnd*)wParam; //点击了“打开插件目录” if (pCtrl == &m_open_plugin_dir_lnk) { wstring plugin_dir = CCommon::GetModuleDir() + L"plugins"; CreateDirectory(plugin_dir.c_str(), NULL); //如果plugins不存在,则创建它 ShellExecute(NULL, _T("open"), _T("explorer"), plugin_dir.c_str(), NULL, SW_SHOWNORMAL); } return 0; } ================================================ FILE: TrafficMonitor/PluginManagerDlg.h ================================================ #pragma once #include "BaseDialog.h" #include "LinkStatic.h" // CPluginManagerDlg 对话框 class CPluginManagerDlg : public CBaseDialog { DECLARE_DYNAMIC(CPluginManagerDlg) public: CPluginManagerDlg(CWnd* pParent = nullptr); // 标准构造函数 virtual ~CPluginManagerDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_PLUGIN_MANAGER_DIALOG }; #endif private: CListCtrl m_list_ctrl; int m_item_selected{ -1 }; CMenu m_menu; CLinkStatic m_plugin_download_lnk; CLinkStatic m_plugin_dev_guide_lnk; CLinkStatic m_open_plugin_dir_lnk; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 void EnableControl(); bool IsSelectedValid(); bool IsSelectedPluginEnable(); //选中插件是否可用 DECLARE_MESSAGE_MAP() // 通过 CBaseDialog 继承 virtual CString GetDialogName() const override; public: virtual BOOL OnInitDialog(); afx_msg void OnNMRClickList1(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnNMClickList1(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnBnClickedOptinsButton(); afx_msg void OnBnClickedPluginInfoButton(); afx_msg void OnNMDblclkList1(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnInitMenu(CMenu* pMenu); afx_msg void OnPluginDetail(); afx_msg void OnPluginOptions(); afx_msg void OnPluginDisable(); protected: afx_msg LRESULT OnLinkClicked(WPARAM wParam, LPARAM lParam); }; ================================================ FILE: TrafficMonitor/ReadMe.txt ================================================ ================================================================================ MICROSOFT 基础类库 : TrafficMonitor 项目概述 =============================================================================== 应用程序向导已为您创建了此 TrafficMonitor 应用程序。此应用程序不仅演示 Microsoft 基础类的基本使用方法,还可作为您编写应用程序的起点。 本文件概要介绍组成 TrafficMonitor 应用程序的每个文件的内容。 TrafficMonitor.vcxproj 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。 TrafficMonitor.vcxproj.filters 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。 TrafficMonitor.h 这是应用程序的主头文件。 其中包括其他项目特定的标头(包括 Resource.h),并声明 CTrafficMonitorApp 应用程序类。 TrafficMonitor.cpp 这是包含应用程序类 CTrafficMonitorApp 的主应用程序源文件。 TrafficMonitor.rc 这是程序使用的所有 Microsoft Windows 资源的列表。它包括 RES 子目录中存储的图标、位图和光标。此文件可以直接在 Microsoft Visual C++ 中进行编辑。项目资源包含在 2052 中。 res\TrafficMonitor.ico 这是用作应用程序图标的图标文件。此图标包括在主资源文件 TrafficMonitor.rc 中。 res\TrafficMonitor.rc2 此文件包含不在 Microsoft Visual C++ 中进行编辑的资源。您应该将不可由资源编辑器编辑的所有资源放在此文件中。 ///////////////////////////////////////////////////////////////////////////// 应用程序向导创建一个对话框类: TrafficMonitorDlg.h、TrafficMonitorDlg.cpp - 对话框 这些文件包含 CTrafficMonitorDlg 类。此类定义应用程序的主对话框的行为。对话框模板包含在 TrafficMonitor.rc 中,该文件可以在 Microsoft Visual C++ 中编辑。 ///////////////////////////////////////////////////////////////////////////// 其他功能: ActiveX 控件 该应用程序包含对使用 ActiveX 控件的支持。 ///////////////////////////////////////////////////////////////////////////// 其他标准文件: StdAfx.h, StdAfx.cpp 这些文件用于生成名为 TrafficMonitor.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。 Resource.h 这是标准头文件,可用于定义新的资源 ID。Microsoft Visual C++ 将读取并更新此文件。 TrafficMonitor.manifest Windows XP 使用应用程序清单文件来描述特定版本的并行程序集的应用程序依赖项。加载程序使用这些信息来从程序集缓存中加载相应的程序集,并保护其不被应用程序访问。应用程序清单可能会包含在内,以作为与应用程序可执行文件安装在同一文件夹中的外部 .manifest 文件进行重新分发,它还可能以资源的形式包含在可执行文件中。 ///////////////////////////////////////////////////////////////////////////// 其他注释: 应用程序向导使用“TODO:”来指示应添加或自定义的源代码部分。 如果应用程序使用共享 DLL 中的 MFC,您将需要重新分发 MFC DLL。如果应用程序所使用的语言与操作系统的区域设置不同,则还需要重新分发相应的本地化资源 mfc110XXX.DLL。 有关上述话题的更多信息,请参见 MSDN 文档中有关重新分发 Visual C++ 应用程序的部分。 ///////////////////////////////////////////////////////////////////////////// ================================================ FILE: TrafficMonitor/SelectConnectionsDlg.cpp ================================================ // SelectConnectionsDlg.cpp: 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "SelectConnectionsDlg.h" #include "afxdialogex.h" #include "AdapterCommon.h" // CSelectConnectionsDlg 对话框 IMPLEMENT_DYNAMIC(CSelectConnectionsDlg, CBaseDialog) CSelectConnectionsDlg::CSelectConnectionsDlg(const StringSet& connections_hide, CWnd* pParent /*=nullptr*/) : m_connections_hide(connections_hide), CBaseDialog(IDD_SELECT_CONNECTIONS_DIALOG, pParent) { std::vector connections; CAdapterCommon::GetAdapterInfo(connections); for (const auto& item : connections) m_all_connection_names.push_back(CCommon::StrToUnicode(item.description.c_str())); } CSelectConnectionsDlg::~CSelectConnectionsDlg() { } void CSelectConnectionsDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST1, m_list_ctrl); } CString CSelectConnectionsDlg::GetDialogName() const { //throw std::logic_error("The method or operation is not implemented."); return _T("SelectConnectionsDlg"); } BEGIN_MESSAGE_MAP(CSelectConnectionsDlg, CBaseDialog) END_MESSAGE_MAP() // CSelectConnectionsDlg 消息处理程序 BOOL CSelectConnectionsDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetIcon(theApp.GetMenuIcon(IDI_CONNECTION), FALSE); m_list_ctrl.SetItemHeight(0, theApp.DPI(20)); //向列表中添加项目 for (const auto& connection_name : m_all_connection_names) { m_list_ctrl.AddString(connection_name.c_str()); if (!m_connections_hide.Contains(connection_name)) m_list_ctrl.SetCheck(m_list_ctrl.GetCount() - 1, TRUE); else m_list_ctrl.SetCheck(m_list_ctrl.GetCount() - 1, FALSE); } return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CSelectConnectionsDlg::OnOK() { // TODO: 在此添加专用代码和/或调用基类 //保存每个项目的勾选状态 bool is_empty{ true }; for (int i = 0; i < static_cast(m_all_connection_names.size()); i++) { bool is_checked = (m_list_ctrl.GetCheck(i) != 0); if (is_checked) is_empty = false; m_connections_hide.SetStrContained(m_all_connection_names[i], !is_checked); } if (is_empty) { MessageBox(CCommon::LoadText(IDS_SELECT_AT_LEASE_ONE_WARNING), NULL, MB_ICONWARNING | MB_OK); return; } CBaseDialog::OnOK(); } ================================================ FILE: TrafficMonitor/SelectConnectionsDlg.h ================================================ #pragma once #include "CommonData.h" #include "BaseDialog.h" // CSelectConnectionsDlg 对话框 class CSelectConnectionsDlg : public CBaseDialog { DECLARE_DYNAMIC(CSelectConnectionsDlg) public: CSelectConnectionsDlg(const StringSet& connections_hide, CWnd* pParent = nullptr); // 标准构造函数 virtual ~CSelectConnectionsDlg(); const StringSet& GetData() const { return m_connections_hide; } // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_SELECT_CONNECTIONS_DIALOG }; #endif private: CCheckListBox m_list_ctrl; std::vector m_all_connection_names; StringSet m_connections_hide; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 virtual CString GetDialogName() const override; DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); virtual void OnOK(); }; ================================================ FILE: TrafficMonitor/SetItemOrderDlg.cpp ================================================ // SetItemOrderDlg.cpp: 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "SetItemOrderDlg.h" #include "afxdialogex.h" // CSetItemOrderDlg 对话框 IMPLEMENT_DYNAMIC(CSetItemOrderDlg, CBaseDialog) CSetItemOrderDlg::CSetItemOrderDlg(CWnd* pParent /*=nullptr*/) : CBaseDialog(IDD_SELECT_ORDER_DIALOG, pParent), m_item_order(true) { m_item_order.Init(); } CSetItemOrderDlg::~CSetItemOrderDlg() { } void CSetItemOrderDlg::SetItemOrder(const std::vector& item_order) { m_item_order.SetOrder(item_order); } const std::vector& CSetItemOrderDlg::GetItemOrder() const { return m_item_order.GetItemOrderConst(); } void CSetItemOrderDlg::SetDisplayItem(unsigned int display_item) { m_display_item = display_item; } unsigned int CSetItemOrderDlg::GetDisplayItem() const { return m_display_item; } void CSetItemOrderDlg::SetPluginDisplayItem(const StringSet& plugin_item) { m_plugin_item = plugin_item; } const StringSet& CSetItemOrderDlg::GetPluginDisplayItem() const { return m_plugin_item; } void CSetItemOrderDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST1, m_list_ctrl); } BEGIN_MESSAGE_MAP(CSetItemOrderDlg, CBaseDialog) ON_BN_CLICKED(IDC_MOVE_UP_BUTTON, &CSetItemOrderDlg::OnBnClickedMoveUpButton) ON_BN_CLICKED(IDC_MOVE_DOWN_BUTTON, &CSetItemOrderDlg::OnBnClickedMoveDownButton) ON_BN_CLICKED(IDC_RESTORE_DEFAULT_BUTTON, &CSetItemOrderDlg::OnBnClickedRestoreDefaultButton) ON_LBN_SELCHANGE(IDC_LIST1, &CSetItemOrderDlg::OnLbnSelchangeList1) ON_CLBN_CHKCHANGE(IDC_LIST1, &CSetItemOrderDlg::OnCheckChanged) END_MESSAGE_MAP() // CSetItemOrderDlg 消息处理程序 BOOL CSetItemOrderDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetIcon(theApp.GetMenuIcon(IDI_ITEM), FALSE); // 设置小图标 m_list_ctrl.SetItemHeight(0, theApp.DPI(20)); EnableCtrl(-1); ShowItem(); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CSetItemOrderDlg::ShowItem() { //向列表中添加项目 m_list_ctrl.ResetContent(); m_all_displayed_item = m_item_order.GetAllDisplayItemsWithOrder(); for (const auto& item : m_all_displayed_item) { m_list_ctrl.AddString(CTaskbarItemOrderHelper::GetItemDisplayName(item)); if (GetItemChecked(item)) m_list_ctrl.SetCheck(m_list_ctrl.GetCount() - 1, TRUE); else m_list_ctrl.SetCheck(m_list_ctrl.GetCount() - 1, FALSE); } } void CSetItemOrderDlg::EnableCtrl(int list_selected) { EnableDlgCtrl(IDC_MOVE_UP_BUTTON, list_selected > 0 && list_selected < static_cast(m_all_displayed_item.size())); EnableDlgCtrl(IDC_MOVE_DOWN_BUTTON, list_selected >= 0 && list_selected < static_cast(m_all_displayed_item.size()) - 1); } void CSetItemOrderDlg::EnableDlgCtrl(UINT id, bool enable) { CWnd* pCtrl = GetDlgItem(id); if (pCtrl != nullptr) pCtrl->EnableWindow(enable); } bool CSetItemOrderDlg::GetItemChecked(CommonDisplayItem item) { if (item.is_plugin) { if (item.plugin_item != nullptr) return m_plugin_item.Contains(item.plugin_item->GetItemId()); } else { return m_display_item & item.item_type; } return false; } void CSetItemOrderDlg::SaveItemChecked(CommonDisplayItem item, bool checked) { if (item.is_plugin) { if (item.plugin_item != nullptr) m_plugin_item.SetStrContained(item.plugin_item->GetItemId(), checked); } else { if (checked) m_display_item |= item.item_type; else m_display_item &= ~item.item_type; } } void CSetItemOrderDlg::OnBnClickedMoveUpButton() { // TODO: 在此添加控件通知处理程序代码 auto& item_list{ m_item_order.GetItemOrder() }; int cur_index{ m_list_ctrl.GetCurSel() }; int item_count{ static_cast(item_list.size()) }; if (cur_index > 0 && cur_index < item_count) { std::swap(item_list[cur_index], item_list[cur_index - 1]); ShowItem(); m_list_ctrl.SetCurSel(cur_index - 1); EnableCtrl(cur_index - 1); } } void CSetItemOrderDlg::OnBnClickedMoveDownButton() { // TODO: 在此添加控件通知处理程序代码 auto& item_list{ m_item_order.GetItemOrder() }; int cur_index{ m_list_ctrl.GetCurSel() }; int item_count{ static_cast(item_list.size()) }; if (cur_index >= 0 && cur_index < item_count - 1) { std::swap(item_list[cur_index], item_list[cur_index + 1]); ShowItem(); m_list_ctrl.SetCurSel(cur_index + 1); EnableCtrl(cur_index + 1); } } void CSetItemOrderDlg::OnBnClickedRestoreDefaultButton() { // TODO: 在此添加控件通知处理程序代码 auto item_list{ m_item_order.GetItemOrder() }; std::sort(item_list.begin(), item_list.end()); m_item_order.SetOrder(item_list); ShowItem(); } CString CSetItemOrderDlg::GetDialogName() const { return _T("SetItemOrderDlg"); } void CSetItemOrderDlg::OnLbnSelchangeList1() { // TODO: 在此添加控件通知处理程序代码 int cur_index{ m_list_ctrl.GetCurSel() }; EnableCtrl(cur_index); } void CSetItemOrderDlg::OnCheckChanged() { //当用户点击项目前面的复选框时保存该项目的勾选状态 int cur_index{ m_list_ctrl.GetCurSel() }; if (cur_index >= 0 && cur_index < static_cast(m_all_displayed_item.size())) { bool is_checked = (m_list_ctrl.GetCheck(cur_index) != 0); CommonDisplayItem item = m_all_displayed_item[cur_index]; SaveItemChecked(item, is_checked); } } void CSetItemOrderDlg::OnOK() { // TODO: 在此添加专用代码和/或调用基类 //保存每个项目的勾选状态 //auto item_list = m_item_order.GetAllDisplayItemsWithOrder(); //int i = 0; //for (; i < static_cast(item_list.size()); i++) //{ // bool is_checked = (m_list_ctrl.GetCheck(i) != 0); // CommonDisplayItem item = item_list[i]; // SaveItemChecked(item, is_checked); //} if (m_display_item == 0) m_display_item = TDI_UP; CBaseDialog::OnOK(); } ================================================ FILE: TrafficMonitor/SetItemOrderDlg.h ================================================ #pragma once #include "BaseDialog.h" // CSetItemOrderDlg 对话框 class CSetItemOrderDlg : public CBaseDialog { DECLARE_DYNAMIC(CSetItemOrderDlg) public: CSetItemOrderDlg(CWnd* pParent = nullptr); // 标准构造函数 virtual ~CSetItemOrderDlg(); //设置/获取显示顺序 void SetItemOrder(const std::vector& item_order); const std::vector& GetItemOrder() const; //设置/获取显示项目,使用unsigned int的每个bit表示对应项目是否显示 void SetDisplayItem(unsigned int display_item); unsigned int GetDisplayItem() const; void SetPluginDisplayItem(const StringSet& plugin_item); const StringSet& GetPluginDisplayItem() const; // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_SELECT_ORDER_DIALOG }; #endif private: CTaskbarItemOrderHelper m_item_order; //显示项目的顺序 CCheckListBox m_list_ctrl; unsigned int m_display_item; //使用每个bit位表示的要显示的内置项目 StringSet m_plugin_item; //要显示的插件项目 std::vector m_all_displayed_item; //在列表中显示的所有项目 protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 void ShowItem(); void EnableCtrl(int list_selected); void EnableDlgCtrl(UINT id, bool enable); bool GetItemChecked(CommonDisplayItem item); void SaveItemChecked(CommonDisplayItem item, bool checked); // 通过 CBaseDialog 继承 virtual CString GetDialogName() const override; DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnBnClickedMoveUpButton(); afx_msg void OnBnClickedMoveDownButton(); afx_msg void OnBnClickedRestoreDefaultButton(); afx_msg void OnLbnSelchangeList1(); afx_msg void OnCheckChanged(); virtual void OnOK(); }; ================================================ FILE: TrafficMonitor/SimpleXML.cpp ================================================ #include "stdafx.h" #include "SimpleXML.h" CSimpleXML::CSimpleXML(const wstring & xml_path) { ifstream file_stream{ xml_path }; if (file_stream.fail()) { return; } //ȡļ string xml_str; while (!file_stream.eof()) { xml_str.push_back(file_stream.get()); } xml_str.pop_back(); if (!xml_str.empty() && xml_str.back() != L'\n') //ȷļĩβлس xml_str.push_back(L'\n'); //жļǷutf8 bool is_utf8; if (xml_str.size() >= 3 && xml_str[0] == -17 && xml_str[1] == -69 && xml_str[2] == -65) { //UTF8BOMɾBOM is_utf8 = true; xml_str = xml_str.substr(3); } else { is_utf8 = false; } //תUnicode m_xml_content = CCommon::StrToUnicode(xml_str.c_str(), is_utf8); } CSimpleXML::CSimpleXML() { } CSimpleXML::~CSimpleXML() { } wstring CSimpleXML::GetNode(const wchar_t * node, const wchar_t * parent) const { wstring node_content = _GetNode(parent, m_xml_content); return _GetNode(node, node_content); } wstring CSimpleXML::GetNode(const wchar_t * node) const { return _GetNode(node, m_xml_content); } wstring CSimpleXML::_GetNode(const wchar_t * node, const wstring & content) { wstring result; wstring node_start{ L'<' }; wstring node_end{ L'<' }; node_start += node; node_start += L'>'; node_end += L'/'; node_end += node; node_end += L'>'; size_t index_start, index_end; index_start = content.find(node_start); index_end = content.find(node_end); if (index_start == wstring::npos || index_end == wstring::npos) return wstring(); result = content.substr(index_start + node_start.size(), index_end - index_start - node_start.size()); return result; } ================================================ FILE: TrafficMonitor/SimpleXML.h ================================================ //һ׵XML #pragma once #include "Common.h" class CSimpleXML { public: CSimpleXML(const wstring& xml_path); CSimpleXML(); ~CSimpleXML(); void LoadXMLContentDirect(const wstring& xml_content) { m_xml_content = xml_content; } wstring GetNode(const wchar_t* node, const wchar_t* parent) const; wstring GetNode(const wchar_t* node) const; static wstring _GetNode(const wchar_t* node, const wstring& content); protected: wstring m_xml_content; }; ================================================ FILE: TrafficMonitor/SkinDlg.cpp ================================================ // SkinDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "SkinDlg.h" #include "afxdialogex.h" // CSkinDlg 对话框 IMPLEMENT_DYNAMIC(CSkinDlg, CBaseDialog) CSkinDlg::CSkinDlg(CWnd* pParent /*=NULL*/) : CBaseDialog(IDD_SKIN_DIALOG, pParent) { } CSkinDlg::~CSkinDlg() { } CString CSkinDlg::GetDialogName() const { return _T("SkinDlg"); } void CSkinDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_COMBO1, m_select_box); DDX_Control(pDX, IDC_SKIN_COURSE_STATIC, m_skin_course); DDX_Control(pDX, IDC_SKIN_DOWNLOAD_STATIC, m_skin_download); DDX_Control(pDX, IDC_PREVIEW_GROUP_STATIC, m_preview_static); DDX_Control(pDX, IDC_NOTIFY_STATIC, m_notify_static); DDX_Control(pDX, IDC_OPEN_SKIN_DIR_STATIC, m_open_skin_dir_lnk); } void CSkinDlg::ShowPreview() { //载入布局数据 wstring cfg_path{ theApp.m_skin_path + m_skins[m_skin_selected] + L"\\skin.xml" }; if (!CCommon::FileExist(cfg_path.c_str())) cfg_path = theApp.m_skin_path + m_skins[m_skin_selected] + L"\\skin.ini"; m_skin_data.Load(cfg_path); //获取预览区大小 m_view->SetSize(m_skin_data.GetPreviewInfo().width, m_skin_data.GetPreviewInfo().height); //刷新预览图 m_view->Invalidate(); //显示皮肤作者 SetDlgItemText(IDC_SKIN_INFO, CCommon::LoadText(IDS_SKIN_AUTHOUR, m_skin_data.GetSkinInfo().skin_author.c_str())); //设置提示信息 bool cover_font_setting{ !m_skin_data.GetSkinInfo().font_info.name.IsEmpty() || (m_skin_data.GetSkinInfo().font_info.size >= MIN_FONT_SIZE && m_skin_data.GetSkinInfo().font_info.size <= MAX_FONT_SIZE) }; bool cover_str_setting{ !m_skin_data.GetSkinInfo().display_text.IsInvalid() }; cover_font_setting = cover_font_setting && theApp.m_general_data.allow_skin_cover_font; cover_str_setting = cover_str_setting && theApp.m_general_data.allow_skin_cover_text; if (cover_font_setting && cover_str_setting) m_notify_static.SetWindowTextEx(CCommon::LoadText(IDS_OVERWRITE_FONT_TEXT_WARNING)); else if (cover_font_setting) m_notify_static.SetWindowTextEx(CCommon::LoadText(IDS_OVERWRITE_FONT_WARNING)); else if (cover_str_setting) m_notify_static.SetWindowTextEx(CCommon::LoadText(IDS_OVERWRITE_TEXT_WARNING)); else m_notify_static.SetWindowTextEx(_T("")); } CRect CSkinDlg::CalculateViewRect() { CRect rect; m_preview_static.GetWindowRect(rect); //获取“预览” group box 的位置 ScreenToClient(&rect); CRect scroll_view_rect{ rect }; scroll_view_rect.DeflateRect(theApp.DPI(12), theApp.DPI(40)); scroll_view_rect.top = rect.top + theApp.DPI(28); return scroll_view_rect; } BEGIN_MESSAGE_MAP(CSkinDlg, CBaseDialog) ON_CBN_SELCHANGE(IDC_COMBO1, &CSkinDlg::OnCbnSelchangeCombo1) ON_WM_SIZE() ON_MESSAGE(WM_LINK_CLICKED, &CSkinDlg::OnLinkClicked) END_MESSAGE_MAP() // CSkinDlg 消息处理程序 BOOL CSkinDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetWindowText(CCommon::LoadText(IDS_TITLE_CHANGE_SKIN)); SetIcon(theApp.GetMenuIcon(IDI_SKIN), FALSE); // 设置小图标 //初始化选择框 for (const auto& skin_path : m_skins) { wstring skin_name; size_t index = skin_path.find_last_of(L'\\'); skin_name = skin_path.substr(index + 1); m_select_box.AddString(skin_name.c_str()); } m_select_box.SetCurSel(m_skin_selected); m_select_box.SetMinVisibleItems(9); //初始化预览视图 m_view = (CSkinPreviewView*)RUNTIME_CLASS(CSkinPreviewView)->CreateObject(); m_view->Create(NULL, NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL, CalculateViewRect(), this, 3000); m_view->InitialUpdate(); m_view->SetSkinData(&m_skin_data); m_view->SetFont(m_pFont); m_view->ShowWindow(SW_SHOW); //设置提示信息 m_notify_static.SetTextColor(RGB(252, 128, 45)); m_notify_static.SetBackColor(GetSysColor(COLOR_BTNFACE)); m_notify_static.SetWindowTextEx(_T("")); //显示预览图片 ShowPreview(); //设置超链接 m_skin_course.SetURL(_T("https://github.com/zhongyang219/TrafficMonitor/wiki/%E7%9A%AE%E8%82%A4%E5%88%B6%E4%BD%9C%E6%95%99%E7%A8%8B")); m_skin_download.SetURL(_T("https://github.com/zhongyang219/TrafficMonitorSkin/blob/master/皮肤下载.md")); m_open_skin_dir_lnk.SetLinkIsURL(false); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CSkinDlg::OnCbnSelchangeCombo1() { // TODO: 在此添加控件通知处理程序代码 m_skin_selected = m_select_box.GetCurSel(); ShowPreview(); } void CSkinDlg::OnSize(UINT nType, int cx, int cy) { CBaseDialog::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 if (m_preview_static.m_hWnd != NULL && nType != SIZE_MINIMIZED && m_view != nullptr) m_view->MoveWindow(CalculateViewRect()); } afx_msg LRESULT CSkinDlg::OnLinkClicked(WPARAM wParam, LPARAM lParam) { CWnd* pCtrl = (CWnd*)wParam; //点击了“打开皮肤目录” if (pCtrl == &m_open_skin_dir_lnk) { CreateDirectory(theApp.m_skin_path.c_str(), NULL); //如果皮肤目录不存在,则创建它 ShellExecute(NULL, _T("open"), _T("explorer"), theApp.m_skin_path.c_str(), NULL, SW_SHOWNORMAL); } return 0; } ================================================ FILE: TrafficMonitor/SkinDlg.h ================================================ #pragma once #include "afxwin.h" #include"StaticEx.h" #include "PictureStatic.h" #include "CSkinPreviewView.h" #include "LinkStatic.h" #include "BaseDialog.h" // CSkinDlg 对话框 class CSkinDlg : public CBaseDialog { DECLARE_DYNAMIC(CSkinDlg) public: CSkinDlg(CWnd* pParent = NULL); // 标准构造函数 virtual ~CSkinDlg(); vector m_skins; //皮肤文件的路径 int m_skin_selected; //选择的皮肤 CFont* m_pFont; //预览图的字体 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_SKIN_DIALOG }; #endif const CSkinFile& GetSkinData() const { return m_skin_data; } protected: virtual CString GetDialogName() const override; virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 protected: //控件变量 CComboBox m_select_box; //选择框 CLinkStatic m_skin_course; //“皮肤制作教程”超链接 CLinkStatic m_skin_download; //“更多皮肤下载”超链接 CLinkStatic m_open_skin_dir_lnk; CSkinPreviewView* m_view; //预览区视图类 CStatic m_preview_static; CStaticEx m_notify_static; //显示提示信息的static控件 CSkinFile m_skin_data; //皮肤数据 void ShowPreview(); //显示皮肤预览 CRect CalculateViewRect(); //根据窗口大小计算预览视图的大小 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnCbnSelchangeCombo1(); afx_msg void OnSize(UINT nType, int cx, int cy); protected: afx_msg LRESULT OnLinkClicked(WPARAM wParam, LPARAM lParam); }; ================================================ FILE: TrafficMonitor/SkinFile.cpp ================================================ #include "stdafx.h" #include "SkinFile.h" #include "Common.h" #include "FilePathHelper.h" #include "TrafficMonitor.h" #include "IniHelper.h" #include "DrawCommon.h" CSkinFile::CSkinFile() { } CSkinFile::~CSkinFile() { } static CSkinFile::LayoutItem LayoutItemFromXmlNode(tinyxml2::XMLElement* ele) { CSkinFile::LayoutItem layout_item; layout_item.x = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(ele, "x"))); layout_item.y = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(ele, "y"))); layout_item.width = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(ele, "width"))); layout_item.align = static_cast(atoi(CTinyXml2Helper::ElementAttribute(ele, "align"))); layout_item.show = CTinyXml2Helper::StringToBool(CTinyXml2Helper::ElementAttribute(ele, "show")); return layout_item; } CSkinFile::Layout CSkinFile::LayoutFromXmlNode(tinyxml2::XMLElement* ele) { CSkinFile::Layout layout; layout.width = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(ele, "width"))); layout.height = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(ele, "height"))); CTinyXml2Helper::IterateChildNode(ele, [&](tinyxml2::XMLElement* ele_layout_item) { string str_layout_item = CTinyXml2Helper::ElementName(ele_layout_item); for (auto display_item : AllDisplayItems) { if (str_layout_item == CSkinFile::GetDisplayItemXmlNodeName(display_item)) { layout.layout_items[display_item] = LayoutItemFromXmlNode(ele_layout_item); break; } } wstring plugin_id = CCommon::StrToUnicode(m_plugin_map[str_layout_item].c_str(), true); if (!plugin_id.empty()) { for (const auto& plugin_item : theApp.m_plugins.GetPluginItems()) { if (plugin_id == plugin_item->GetItemId()) { layout.layout_items[plugin_item] = LayoutItemFromXmlNode(ele_layout_item); break; } } } }); return layout; } void CSkinFile::DrawSkinText(CDrawCommon drawer, DrawStr draw_str, CRect rect, COLORREF color, Alignment align) { int text_width = drawer.GetDC()->GetTextExtent(draw_str.GetStr()).cx; //标签和数值两端对齐 if (align == Alignment::SIDE && text_width < rect.Width()) //只有文本宽度小于矩形的宽度时才使用两端对齐 { //绘制标签 drawer.DrawWindowText(rect, draw_str.label, color, Alignment::LEFT); //绘制数值 drawer.DrawWindowText(rect, draw_str.value, color, Alignment::RIGHT); } else { drawer.DrawWindowText(rect, draw_str.GetStr(), color, align); } } void CSkinFile::Load(const wstring& file_path) { CFilePathHelper file_path_helper{ file_path }; wstring ext = file_path_helper.GetFileExtension(); if (ext == L"ini") LoadFromIni(file_path); else LoadFromXml(file_path); if (m_font.m_hObject) m_font.DeleteObject(); //创建字体对象 m_skin_info.font_info.Create(m_font); //载入背景图片 wstring path_dir = file_path_helper.GetDir(); m_background_s.Destroy(); m_background_s.Load((path_dir + BACKGROUND_IMAGE_S).c_str()); m_background_l.Destroy(); m_background_l.Load((path_dir + BACKGROUND_IMAGE_L).c_str()); } void CSkinFile::LoadFromXml(const wstring& file_path) { m_skin_info = SkinInfo(); m_layout_info = LayoutInfo(); m_preview_info = PreviewInfo(); tinyxml2::XMLDocument doc; if (CTinyXml2Helper::LoadXmlFile(doc, file_path.c_str())) { CTinyXml2Helper::IterateChildNode(doc.FirstChildElement(), [this](tinyxml2::XMLElement* child) { string ele_name = CTinyXml2Helper::ElementName(child); //读取皮肤信息 if (ele_name == "skin") { CTinyXml2Helper::IterateChildNode(child, [this](tinyxml2::XMLElement* skin_item) { string skin_item_name = CTinyXml2Helper::ElementName(skin_item); //文本颜色 if (skin_item_name == "text_color") { string str_text_color = CTinyXml2Helper::ElementText(skin_item); std::vector split_result; CCommon::StringSplit(str_text_color, L',', split_result); for (const auto& str : split_result) { m_skin_info.text_color.push_back(atoi(str.c_str())); } } if (m_skin_info.text_color.size() < theApp.m_plugins.AllDisplayItemsWithPlugins().size()) { COLORREF default_color{}; if (!m_skin_info.text_color.empty()) default_color = m_skin_info.text_color.front(); m_skin_info.text_color.resize(theApp.m_plugins.AllDisplayItemsWithPlugins().size(), default_color); } //指定每个项目的颜色 else if (skin_item_name == "specify_each_item_color") { m_skin_info.specify_each_item_color = CTinyXml2Helper::StringToBool(CTinyXml2Helper::ElementText(skin_item)); } //皮肤作者 else if (skin_item_name == "skin_author") { m_skin_info.skin_author = CCommon::StrToUnicode(CTinyXml2Helper::ElementText(skin_item), true); } //字体 else if (skin_item_name == "font") { m_skin_info.font_info.name = CTinyXml2Helper::ElementAttribute(skin_item, "name"); m_skin_info.font_info.size = atoi(CTinyXml2Helper::ElementAttribute(skin_item, "size")); int font_style = atoi(CTinyXml2Helper::ElementAttribute(skin_item, "style")); m_skin_info.font_info.bold = CCommon::GetNumberBit(font_style, 0); m_skin_info.font_info.italic = CCommon::GetNumberBit(font_style, 1); m_skin_info.font_info.underline = CCommon::GetNumberBit(font_style, 2); m_skin_info.font_info.strike_out = CCommon::GetNumberBit(font_style, 3); } else if (skin_item_name == "display_text") { CTinyXml2Helper::IterateChildNode(skin_item, [this](tinyxml2::XMLElement* display_text_item) { string item_name = CTinyXml2Helper::ElementName(display_text_item); wstring item_text = CCommon::StrToUnicode(CTinyXml2Helper::ElementText(display_text_item), true); for (auto display_item : AllDisplayItems) { if (item_name == CSkinFile::GetDisplayItemXmlNodeName(display_item)) { m_skin_info.display_text.Get(display_item) = item_text; break; } } }); } }); } //布局信息 else if (ele_name == "layout") { m_layout_info.text_height = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(child, "text_height"))); m_layout_info.no_label = CTinyXml2Helper::StringToBool(CTinyXml2Helper::ElementAttribute(child, "no_label")); CTinyXml2Helper::IterateChildNode(child, [this](tinyxml2::XMLElement* ele_layout) { string str_layout = CTinyXml2Helper::ElementName(ele_layout); if (str_layout == "layout_l") m_layout_info.layout_l = LayoutFromXmlNode(ele_layout); else if (str_layout == "layout_s") m_layout_info.layout_s = LayoutFromXmlNode(ele_layout); }); } //预览图 else if (ele_name == "preview") { m_preview_info.width = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(child, "width"))); m_preview_info.height = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(child, "height"))); CTinyXml2Helper::IterateChildNode(child, [this](tinyxml2::XMLElement* ele_priview_item) { string str_item_name = CTinyXml2Helper::ElementName(ele_priview_item); if (str_item_name == "l") { m_preview_info.l_pos.x = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(ele_priview_item, "x"))); m_preview_info.l_pos.y = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(ele_priview_item, "y"))); } else if (str_item_name == "s") { m_preview_info.s_pos.x = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(ele_priview_item, "x"))); m_preview_info.s_pos.y = theApp.DPI(atoi(CTinyXml2Helper::ElementAttribute(ele_priview_item, "y"))); } }); } //插件名称映射 else if (ele_name == "plugin_map") { CTinyXml2Helper::IterateChildNode(child, [this](tinyxml2::XMLElement* plugin_item) { string ele_name = CTinyXml2Helper::ElementName(plugin_item); string ele_text = CTinyXml2Helper::ElementText(plugin_item); m_plugin_map[ele_name] = ele_text; }); } }); } } void CSkinFile::LoadFromIni(const wstring& file_path) { m_skin_info = SkinInfo(); m_layout_info = LayoutInfo(); m_preview_info = PreviewInfo(); //获取皮肤信息 CIniHelper ini(file_path); //获取当前皮肤的文字颜色 std::map text_colors{}; ini.LoadMainWndColors(_T("skin"), _T("text_color"), text_colors, 0); for (const auto& item : text_colors) { m_skin_info.text_color.push_back(item.second); } m_skin_info.specify_each_item_color = ini.GetBool(_T("skin"), _T("specify_each_item_color"), false); //获取当前皮肤的字体 FontInfo default_font{}; ini.LoadFontData(L"skin", m_skin_info.font_info, default_font); //获取皮肤作者 m_skin_info.skin_author = ini.GetString(_T("skin"), _T("skin_author"), _T("unknow")); //获取显示文本 m_skin_info.display_text.Get(TDI_UP) = ini.GetString(_T("skin"), _T("up_string"), NONE_STR); m_skin_info.display_text.Get(TDI_DOWN) = ini.GetString(_T("skin"), _T("down_string"), NONE_STR); m_skin_info.display_text.Get(TDI_CPU) = ini.GetString(_T("skin"), _T("cpu_string"), NONE_STR); m_skin_info.display_text.Get(TDI_MEMORY) = ini.GetString(_T("skin"), _T("memory_string"), NONE_STR); //获取预览区大小 m_preview_info.width = theApp.DPI(ini.GetInt(_T("layout"), _T("preview_width"), 238)); m_preview_info.height = theApp.DPI(ini.GetInt(_T("layout"), _T("preview_height"), 105)); //从ini文件读取皮肤布局,并根据DPI进行缩放 m_layout_info.text_height = theApp.DPI(ini.GetInt(_T("layout"), _T("text_height"), 20)); m_layout_info.no_label = ini.GetBool(_T("layout"), _T("no_text"), false); m_layout_info.layout_l.width = theApp.DPI(ini.GetInt(_T("layout"), _T("width_l"), 220)); m_layout_info.layout_l.height = theApp.DPI(ini.GetInt(_T("layout"), _T("height_l"), 43)); m_layout_info.layout_l.layout_items[TDI_UP].x = theApp.DPI(ini.GetInt(_T("layout"), _T("up_x_l"), 6)); m_layout_info.layout_l.layout_items[TDI_UP].y = theApp.DPI(ini.GetInt(_T("layout"), _T("up_y_l"), 2)); m_layout_info.layout_l.layout_items[TDI_UP].width = theApp.DPI(ini.GetInt(_T("layout"), _T("up_width_l"), 108)); m_layout_info.layout_l.layout_items[TDI_UP].align = static_cast(ini.GetInt(_T("layout"), _T("up_align_l"), 0)); m_layout_info.layout_l.layout_items[TDI_DOWN].x = theApp.DPI(ini.GetInt(_T("layout"), _T("down_x_l"), 114)); m_layout_info.layout_l.layout_items[TDI_DOWN].y = theApp.DPI(ini.GetInt(_T("layout"), _T("down_y_l"), 2)); m_layout_info.layout_l.layout_items[TDI_DOWN].width = theApp.DPI(ini.GetInt(_T("layout"), _T("down_width_l"), 110)); m_layout_info.layout_l.layout_items[TDI_DOWN].align = static_cast(ini.GetInt(_T("layout"), _T("down_align_l"), 0)); m_layout_info.layout_l.layout_items[TDI_CPU].x = theApp.DPI(ini.GetInt(_T("layout"), _T("cpu_x_l"), 6)); m_layout_info.layout_l.layout_items[TDI_CPU].y = theApp.DPI(ini.GetInt(_T("layout"), _T("cpu_y_l"), 21)); m_layout_info.layout_l.layout_items[TDI_CPU].width = theApp.DPI(ini.GetInt(_T("layout"), _T("cpu_width_l"), 108)); m_layout_info.layout_l.layout_items[TDI_CPU].align = static_cast(ini.GetInt(_T("layout"), _T("cpu_align_l"), 0)); m_layout_info.layout_l.layout_items[TDI_MEMORY].x = theApp.DPI(ini.GetInt(_T("layout"), _T("memory_x_l"), 114)); m_layout_info.layout_l.layout_items[TDI_MEMORY].y = theApp.DPI(ini.GetInt(_T("layout"), _T("memory_y_l"), 21)); m_layout_info.layout_l.layout_items[TDI_MEMORY].width = theApp.DPI(ini.GetInt(_T("layout"), _T("memory_width_l"), 110)); m_layout_info.layout_l.layout_items[TDI_MEMORY].align = static_cast(ini.GetInt(_T("layout"), _T("memory_align_l"), 0)); m_layout_info.layout_l.layout_items[TDI_UP].show = ini.GetBool(_T("layout"), _T("show_up_l"), true); m_layout_info.layout_l.layout_items[TDI_DOWN].show = ini.GetBool(_T("layout"), _T("show_down_l"), true); m_layout_info.layout_l.layout_items[TDI_CPU].show = ini.GetBool(_T("layout"), _T("show_cpu_l"), true); m_layout_info.layout_l.layout_items[TDI_MEMORY].show = ini.GetBool(_T("layout"), _T("show_memory_l"), true); m_preview_info.l_pos.x = theApp.DPI(ini.GetInt(_T("layout"), _T("preview_x_l"), 0)); m_preview_info.l_pos.y = theApp.DPI(ini.GetInt(_T("layout"), _T("preview_y_l"), 47)); m_layout_info.layout_s.width = theApp.DPI(ini.GetInt(_T("layout"), _T("width_s"), 220)); m_layout_info.layout_s.height = theApp.DPI(ini.GetInt(_T("layout"), _T("height_s"), 28)); m_layout_info.layout_s.layout_items[TDI_UP].x = theApp.DPI(ini.GetInt(_T("layout"), _T("up_x_s"), 6)); m_layout_info.layout_s.layout_items[TDI_UP].y = theApp.DPI(ini.GetInt(_T("layout"), _T("up_y_s"), 4)); m_layout_info.layout_s.layout_items[TDI_UP].width = theApp.DPI(ini.GetInt(_T("layout"), _T("up_width_s"), 108)); m_layout_info.layout_s.layout_items[TDI_UP].align = static_cast(ini.GetInt(_T("layout"), _T("up_align_s"), 0)); m_layout_info.layout_s.layout_items[TDI_DOWN].x = theApp.DPI(ini.GetInt(_T("layout"), _T("down_x_s"), 114)); m_layout_info.layout_s.layout_items[TDI_DOWN].y = theApp.DPI(ini.GetInt(_T("layout"), _T("down_y_s"), 4)); m_layout_info.layout_s.layout_items[TDI_DOWN].width = theApp.DPI(ini.GetInt(_T("layout"), _T("down_width_s"), 110)); m_layout_info.layout_s.layout_items[TDI_DOWN].align = static_cast(ini.GetInt(_T("layout"), _T("down_align_s"), 0)); m_layout_info.layout_s.layout_items[TDI_CPU].x = theApp.DPI(ini.GetInt(_T("layout"), _T("cpu_x_s"), 0)); m_layout_info.layout_s.layout_items[TDI_CPU].y = theApp.DPI(ini.GetInt(_T("layout"), _T("cpu_y_s"), 0)); m_layout_info.layout_s.layout_items[TDI_CPU].width = theApp.DPI(ini.GetInt(_T("layout"), _T("cpu_width_s"), 0)); m_layout_info.layout_s.layout_items[TDI_CPU].align = static_cast(ini.GetInt(_T("layout"), _T("cpu_align_s"), 0)); m_layout_info.layout_s.layout_items[TDI_MEMORY].x = theApp.DPI(ini.GetInt(_T("layout"), _T("memory_x_s"), 0)); m_layout_info.layout_s.layout_items[TDI_MEMORY].y = theApp.DPI(ini.GetInt(_T("layout"), _T("memory_y_s"), 0)); m_layout_info.layout_s.layout_items[TDI_MEMORY].width = theApp.DPI(ini.GetInt(_T("layout"), _T("memory_width_s"), 0)); m_layout_info.layout_s.layout_items[TDI_MEMORY].align = static_cast(ini.GetInt(_T("layout"), _T("memory_align_s"), 0)); m_layout_info.layout_s.layout_items[TDI_UP].show = ini.GetBool(_T("layout"), _T("show_up_s"), true); m_layout_info.layout_s.layout_items[TDI_DOWN].show = ini.GetBool(_T("layout"), _T("show_down_s"), true); m_layout_info.layout_s.layout_items[TDI_CPU].show = ini.GetBool(_T("layout"), _T("show_cpu_s"), false); m_layout_info.layout_s.layout_items[TDI_MEMORY].show = ini.GetBool(_T("layout"), _T("show_memory_s"), false); m_preview_info.s_pos.x = theApp.DPI(ini.GetInt(_T("layout"), _T("preview_x_s"), 0)); m_preview_info.s_pos.y = theApp.DPI(ini.GetInt(_T("layout"), _T("preview_y_s"), 0)); } void CSkinFile::DrawPreview(CDC* pDC, CRect rect) { CDrawCommon draw; draw.Create(pDC, nullptr); if (!m_skin_info.font_info.name.IsEmpty() && m_skin_info.font_info.size > 0) draw.SetFont(&m_font); else draw.SetFont(theApp.m_pMainWnd->GetFont()); draw.SetDrawRect(rect); draw.FillRect(rect, RGB(255, 255, 255)); //绘制背景 CRect rect_s(CPoint(m_preview_info.s_pos.x, m_preview_info.s_pos.y), CSize(m_layout_info.layout_s.width, m_layout_info.layout_s.height)); CRect rect_l(CPoint(m_preview_info.l_pos.x, m_preview_info.l_pos.y), CSize(m_layout_info.layout_l.width, m_layout_info.layout_l.height)); if (m_background_s.IsNull()) draw.FillRect(rect_s, RGB(230, 230, 230)); else draw.DrawBitmap(m_background_s, rect_s.TopLeft(), rect_s.Size()); if (m_background_l.IsNull()) draw.FillRect(rect_l, RGB(230, 230, 230)); draw.DrawBitmap(m_background_l, rect_l.TopLeft(), rect_l.Size()); //获取每个项目显示的文本 std::map map_str; for (auto iter = AllDisplayItems.begin(); iter != AllDisplayItems.end(); ++iter) { //wstring disp_text = m_skin_info.display_text.Get(*iter); //if (disp_text == NONE_STR) // disp_text = theApp.m_main_wnd_data.disp_str.Get(*iter); DrawStr draw_str; switch (*iter) { case TDI_UP: draw_str.value = _T("88.8 KB/s"); break; case TDI_DOWN: draw_str.value = _T("88.9 KB/s"); break; case TDI_TOTAL_SPEED: draw_str.value = _T("90 KB/s"); break; case TDI_CPU: draw_str.value = _T("50 %"); break; case TDI_MEMORY: draw_str.value = _T("51 %"); break; case TDI_CPU_TEMP: case TDI_GPU_TEMP: case TDI_HDD_TEMP: case TDI_MAIN_BOARD_TEMP: draw_str.value = _T("40 °C"); break; case TDI_CPU_FREQ: draw_str.value = _T("1.0 GHz"); break; default: draw_str.value = _T("99"); break; } if (m_skin_info.display_text.Get(*iter) == NONE_STR) m_skin_info.display_text.Get(*iter) = theApp.m_main_wnd_data.disp_str.Get(*iter); if (!m_layout_info.no_label) draw_str.label = m_skin_info.display_text.Get(*iter).c_str(); map_str[*iter] = draw_str; } //获取文本颜色 std::map text_colors{}; if (m_skin_info.specify_each_item_color) { int i{}; for (const auto& item : theApp.m_plugins.AllDisplayItemsWithPlugins()) { if (i < static_cast(m_skin_info.text_color.size())) text_colors[item] = m_skin_info.text_color[i]; i++; } } else if (!m_skin_info.text_color.empty()) { for (const auto& item : theApp.m_plugins.AllDisplayItemsWithPlugins()) { if (!m_skin_info.text_color.empty()) text_colors[item] = m_skin_info.text_color[0]; } } //绘制预览图文本 auto drawPreviewText = [&](Layout& layout, const PreviewInfo::Pos& pos) { for (auto iter = map_str.begin(); iter != map_str.end(); ++iter) { if (layout.layout_items[iter->first].show) { CPoint point; point.SetPoint(layout.layout_items[iter->first].x, layout.layout_items[iter->first].y); point.Offset(pos.x, pos.y); CRect rect(point, CSize(layout.layout_items[iter->first].width, m_layout_info.text_height)); COLORREF text_color{}; text_color = text_colors[iter->first]; DrawSkinText(draw, iter->second, rect, text_color, layout.layout_items[iter->first].align); } } //绘制插件项目 for (const auto& plugin_item : theApp.m_plugins.GetPluginItems()) { LayoutItem layout_item = layout.GetItem(plugin_item); if (layout_item.show) { COLORREF cl{}; auto iter = text_colors.find(plugin_item); if (iter != text_colors.end()) cl = iter->second; else if (!text_colors.empty()) cl = text_colors.begin()->second; //矩形区域 CPoint point; point.SetPoint(layout_item.x, layout_item.y); point.Offset(pos.x, pos.y); CRect rect(point, CSize(layout_item.width, m_layout_info.text_height)); if (plugin_item->IsCustomDraw()) { int brightness{ (GetRValue(cl) + GetGValue(cl) + GetBValue(cl)) / 2 }; ITMPlugin* plugin = theApp.m_plugins.GetPluginByItem(plugin_item); if (plugin != nullptr && plugin->GetAPIVersion() >= 2) { plugin->OnExtenedInfo(ITMPlugin::EI_VALUE_TEXT_COLOR, std::to_wstring(cl).c_str()); plugin->OnExtenedInfo(ITMPlugin::EI_DRAW_TASKBAR_WND, L"0"); } draw.GetDC()->SetTextColor(cl); plugin_item->DrawItem(draw.GetDC()->GetSafeHdc(), point.x, point.y, layout_item.width, m_layout_info.text_height, brightness >= 128); } else { //绘制文本 DrawStr draw_str; draw_str.label = plugin_item->GetItemLableText(); draw_str.value = plugin_item->GetItemValueSampleText(); DrawSkinText(draw, draw_str, rect, cl, layout_item.align); } } } }; //绘制小预览图文本 drawPreviewText(m_layout_info.layout_s, m_preview_info.s_pos); //绘制大预览图文本 drawPreviewText(m_layout_info.layout_l, m_preview_info.l_pos); } void CSkinFile::DrawInfo(CDC* pDC, bool show_more_info, CFont& font) { //绘制背景图 CImage& background_image{ show_more_info ? m_background_l : m_background_s }; Layout& layout{ show_more_info ? m_layout_info.layout_l : m_layout_info.layout_s }; CRect rect(CPoint(0, 0), CSize(layout.width, layout.height)); CDrawDoubleBuffer draw_double_buffer(pDC, rect); CDrawCommon draw; draw.Create(draw_double_buffer.GetMemDC(), nullptr); draw.DrawBitmap(background_image, CPoint(0, 0), CSize(layout.width, layout.height)); //获取每个项目显示的文本 std::map map_str; if (!m_layout_info.no_label) { map_str[TDI_UP].label = theApp.m_main_wnd_data.disp_str.Get(TDI_UP).c_str(); map_str[TDI_DOWN].label = theApp.m_main_wnd_data.disp_str.Get(TDI_DOWN).c_str(); map_str[TDI_TOTAL_SPEED].label = theApp.m_main_wnd_data.disp_str.Get(TDI_TOTAL_SPEED).c_str(); map_str[TDI_CPU].label = theApp.m_main_wnd_data.disp_str.Get(TDI_CPU).c_str(); map_str[TDI_MEMORY].label = theApp.m_main_wnd_data.disp_str.Get(TDI_MEMORY).c_str(); map_str[TDI_GPU_USAGE].label = theApp.m_main_wnd_data.disp_str.Get(TDI_GPU_USAGE).c_str(); map_str[TDI_HDD_USAGE].label = theApp.m_main_wnd_data.disp_str.Get(TDI_HDD_USAGE).c_str(); map_str[TDI_CPU_TEMP].label = theApp.m_main_wnd_data.disp_str.Get(TDI_CPU_TEMP).c_str(); map_str[TDI_CPU_FREQ].label = theApp.m_main_wnd_data.disp_str.Get(TDI_CPU_FREQ).c_str(); map_str[TDI_GPU_TEMP].label = theApp.m_main_wnd_data.disp_str.Get(TDI_GPU_TEMP).c_str(); map_str[TDI_HDD_TEMP].label = theApp.m_main_wnd_data.disp_str.Get(TDI_HDD_TEMP).c_str(); map_str[TDI_MAIN_BOARD_TEMP].label = theApp.m_main_wnd_data.disp_str.Get(TDI_MAIN_BOARD_TEMP).c_str(); } //上传/下载 CString in_speed = CCommon::DataSizeToString(theApp.m_in_speed, theApp.m_main_wnd_data); CString out_speed = CCommon::DataSizeToString(theApp.m_out_speed, theApp.m_main_wnd_data); CString total_speed = CCommon::DataSizeToString(theApp.m_in_speed + theApp.m_out_speed, theApp.m_main_wnd_data); if (!theApp.m_main_wnd_data.hide_unit || theApp.m_main_wnd_data.speed_unit == SpeedUnit::AUTO) { in_speed += _T("/s"); out_speed += _T("/s"); total_speed += _T("/s"); } map_str[TDI_UP].value = out_speed.GetString(); map_str[TDI_DOWN].value = in_speed.GetString(); map_str[TDI_TOTAL_SPEED].value = total_speed.GetString(); if (theApp.m_main_wnd_data.swap_up_down) //交换上传和下载位置 { std::swap(map_str[TDI_UP], map_str[TDI_DOWN]); } //CPU/内存/显卡利用率 map_str[TDI_CPU].value = CCommon::UsageToString(theApp.m_cpu_usage, theApp.m_main_wnd_data); map_str[TDI_CPU_FREQ].value = CCommon::FreqToString(theApp.m_cpu_freq, theApp.m_main_wnd_data); CString str_memory_value; if (theApp.m_main_wnd_data.memory_display == MemoryDisplay::MEMORY_USED) str_memory_value = CCommon::DataSizeToString(static_cast(theApp.m_used_memory) * 1024, theApp.m_main_wnd_data.separate_value_unit_with_space); else if (theApp.m_main_wnd_data.memory_display == MemoryDisplay::MEMORY_AVAILABLE) str_memory_value = CCommon::DataSizeToString((static_cast(theApp.m_total_memory) - static_cast(theApp.m_used_memory)) * 1024, theApp.m_main_wnd_data.separate_value_unit_with_space); else str_memory_value = CCommon::UsageToString(theApp.m_memory_usage, theApp.m_main_wnd_data); map_str[TDI_MEMORY].value = str_memory_value; map_str[TDI_GPU_USAGE].value = CCommon::UsageToString(theApp.m_gpu_usage, theApp.m_main_wnd_data); map_str[TDI_HDD_USAGE].value = CCommon::UsageToString(theApp.m_hdd_usage, theApp.m_main_wnd_data); //温度 auto getTemperatureStr = [&](DisplayItem display_item, float temperature) { map_str[display_item].value = CCommon::TemperatureToString(temperature, theApp.m_main_wnd_data); }; getTemperatureStr(TDI_CPU_TEMP, theApp.m_cpu_temperature); getTemperatureStr(TDI_GPU_TEMP, theApp.m_gpu_temperature); getTemperatureStr(TDI_HDD_TEMP, theApp.m_hdd_temperature); getTemperatureStr(TDI_MAIN_BOARD_TEMP, theApp.m_main_board_temperature); //获取文本颜色 std::map text_colors{}; if (theApp.m_main_wnd_data.specify_each_item_color) { text_colors = theApp.m_main_wnd_data.text_colors; } else if (!theApp.m_main_wnd_data.text_colors.empty()) { for (const auto& item : theApp.m_plugins.AllDisplayItemsWithPlugins()) { text_colors[item] = theApp.m_main_wnd_data.text_colors.begin()->second; } } //绘制文本 draw.SetFont(&font); //绘制文本 int index{}; for (auto iter = map_str.begin(); iter != map_str.end(); ++iter) { const auto& layout_item = layout.GetItem(iter->first); if (layout_item.show) { //矩形区域 CRect rect(CPoint(layout_item.x, layout_item.y), CSize(layout_item.width, m_layout_info.text_height)); //文本颜色 COLORREF text_color = text_colors[iter->first]; //绘制文本 DrawSkinText(draw, map_str[iter->first], rect, text_color, layout_item.align); } index++; } //绘制插件项目 for (const auto& plugin_item : theApp.m_plugins.GetPluginItems()) { const auto& layout_item = layout.GetItem(plugin_item); if (layout_item.show) { //插件项目自绘 COLORREF cl{}; auto iter = text_colors.find(plugin_item); if (iter != text_colors.end()) cl = iter->second; else if (!text_colors.empty()) cl = text_colors.begin()->second; if (plugin_item->IsCustomDraw()) { int brightness{ (GetRValue(cl) + GetGValue(cl) + GetBValue(cl)) / 2 }; ITMPlugin* plugin = theApp.m_plugins.GetPluginByItem(plugin_item); if (plugin != nullptr && plugin->GetAPIVersion() >= 2) { plugin->OnExtenedInfo(ITMPlugin::EI_VALUE_TEXT_COLOR, std::to_wstring(cl).c_str()); plugin->OnExtenedInfo(ITMPlugin::EI_DRAW_TASKBAR_WND, L"0"); } draw.GetDC()->SetTextColor(cl); plugin_item->DrawItem(draw.GetDC()->GetSafeHdc(), layout_item.x, layout_item.y, layout_item.width, m_layout_info.text_height, brightness >= 128); } else { //矩形区域 CRect rect(CPoint(layout_item.x, layout_item.y), CSize(layout_item.width, m_layout_info.text_height)); //绘制文本 DrawStr draw_str; draw_str.label = theApp.m_main_wnd_data.disp_str.Get(plugin_item).c_str(); draw_str.value = plugin_item->GetItemValueText(); DrawSkinText(draw, draw_str, rect, cl, layout_item.align); } } } } string CSkinFile::GetDisplayItemXmlNodeName(DisplayItem display_item) { switch (display_item) { case TDI_UP: return "up"; break; case TDI_DOWN: return "down"; break; case TDI_TOTAL_SPEED: return "total_speed"; break; case TDI_CPU: return "cpu"; break; case TDI_MEMORY: return "memory"; break; case TDI_GPU_USAGE: return "gpu"; break; case TDI_CPU_TEMP: return "cpu_temperature"; break; case TDI_GPU_TEMP: return "gpu_temperature"; break; case TDI_HDD_TEMP: return "hdd_temperature"; break; case TDI_MAIN_BOARD_TEMP: return "main_board_temperature"; break; case TDI_HDD_USAGE: return "hdd"; break; case TDI_CPU_FREQ: return "cpu_freq"; break; default: return string(); break; } } ================================================ FILE: TrafficMonitor/SkinFile.h ================================================ #pragma once #include "CommonData.h" #include "TinyXml2Helper.h" #include "DrawCommon.h" class CSkinFile { public: CSkinFile(); ~CSkinFile(); //从文件载入皮肤信息 void Load(const wstring& file_path); //皮肤信息 struct SkinInfo { std::vector text_color; //文本颜色 bool specify_each_item_color{}; //是否指定每个项目的颜色 wstring skin_author; //皮肤的作者 FontInfo font_info; //字体信息 DispStrings display_text; //每一项的显示文本 COLORREF TextColor(size_t i) const { if (i >= 0 && i < text_color.size()) return text_color[i]; else if (!text_color.empty()) return text_color.front(); else return 0; } }; //皮肤中每一项的布局信息 struct LayoutItem { int x{}; //X位置 int y{}; //Y位置 int width{}; //宽度 Alignment align{}; //对齐方式 bool show{}; //是否显示 }; //皮肤布局 struct Layout { int width{}; //宽度 int height{}; //高度 std::map layout_items; //每一项的布局信息 LayoutItem GetItem(CommonDisplayItem display_item) const { auto iter = layout_items.find(display_item); if (iter != layout_items.end()) return iter->second; return LayoutItem(); } }; //皮肤布局信息 struct LayoutInfo { int text_height{}; //皮肤文本的高度 bool no_label{}; //是否不显示标签 Layout layout_l; //“显示更多信息”时的布局 Layout layout_s; //不“显示更多信息”时的布局 }; //皮肤预览图信息 struct PreviewInfo { struct Pos { int x{}; int y{}; }; int width{}; //预览图的宽度 int height{}; //预览图的高度 Pos l_pos; //“显示更多信息”时的窗口在预览图中的位置 Pos s_pos; //不“显示更多信息”时的窗口在预览图中的位置 }; const SkinInfo& GetSkinInfo() const { return m_skin_info; } const LayoutInfo& GetLayoutInfo() const { return m_layout_info; } const PreviewInfo& GetPreviewInfo() const { return m_preview_info; } const CImage& GetBackgroundL() const { return m_background_l; } const CImage& GetBackgroundS() const { return m_background_s; } //绘制预览图 //pDC: 绘图的CDC //rect: 绘图区域 void DrawPreview(CDC* pDC, CRect rect); //绘制主界面 void DrawInfo(CDC* pDC, bool show_more_info, CFont& font); static string GetDisplayItemXmlNodeName(DisplayItem display_item); private: void LoadFromXml(const wstring& file_path); //从xml文件读取皮肤数据 void LoadFromIni(const wstring& file_path); //从ini文件读取皮肤数据(用于兼容旧版皮肤) CSkinFile::Layout LayoutFromXmlNode(tinyxml2::XMLElement* ele); struct DrawStr { CString label; CString value; CString GetStr() const { return label + value; } }; static void DrawSkinText(CDrawCommon drawer, DrawStr draw_str, CRect rect, COLORREF color, Alignment align); private: SkinInfo m_skin_info; LayoutInfo m_layout_info; PreviewInfo m_preview_info; std::map m_plugin_map; //插件名称与xml节点名称的映射关系。key是xml节点名称,value是插件ID CFont m_font; CImage m_background_s; CImage m_background_l; }; ================================================ FILE: TrafficMonitor/StaticEx.cpp ================================================ #include "stdafx.h" #include "StaticEx.h" CStaticEx::CStaticEx() { } CStaticEx::~CStaticEx() { } void CStaticEx::SetWindowTextEx(LPCTSTR lpszString, Alignment align) { m_text = lpszString; m_align = align; m_color_text = true; Invalidate(); } void CStaticEx::SetTextColor(COLORREF textColor) { m_text_color = textColor; Invalidate(); } void CStaticEx::SetBackColor(COLORREF back_color) { m_back_color = back_color; m_draw_background_color = true; } CString CStaticEx::GetString() const { return m_text; } LRESULT CStaticEx::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // TODO: ڴרô/û if (message == WM_SETTEXT) { CRect rect; CDC* pDC = GetDC(); GetClientRect(rect); DrawThemeParentBackground(m_hWnd, pDC->GetSafeHdc(), &rect); ReleaseDC(pDC); } return CStatic::DefWindowProc(message, wParam, lParam); } BEGIN_MESSAGE_MAP(CStaticEx, CStatic) ON_WM_PAINT() END_MESSAGE_MAP() void CStaticEx::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: ڴ˴Ϣ // ΪͼϢ CStatic::OnPaint() dc.SetTextColor(m_text_color); dc.SetBkMode(TRANSPARENT); dc.SelectObject(this->GetFont()); CRect rect; this->GetClientRect(&rect); if (m_draw_background_color) dc.FillSolidRect(rect, m_back_color); else DrawThemeParentBackground(m_hWnd, dc.GetSafeHdc(), &rect); //ػؼԽص CSize text_size = dc.GetTextExtent(m_text); UINT format{ DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX }; //CDC::DrawText()ıʽ if (text_size.cx > rect.Width()) //ıȳ˾Ŀȣ˾ʱ { if (m_align == Alignment::RIGHT) format |= DT_RIGHT; } else { switch (m_align) { case Alignment::RIGHT: format |= DT_RIGHT; break; case Alignment::CENTER: format |= DT_CENTER; break; } } dc.DrawText(m_text, rect, format); } void CStaticEx::PreSubclassWindow() { // TODO: ڴרô/û GetWindowText(m_text); CStatic::PreSubclassWindow(); } ================================================ FILE: TrafficMonitor/StaticEx.h ================================================ /* CStatic࣬ɫıؼ SetTextColorıɫ ҪʱSetWindowTextExÿؼı */ #pragma once #include "afxwin.h" #include "CommonData.h" class CStaticEx : public CStatic { public: CStaticEx(); ~CStaticEx(); //Staticؼɫıʱ public: void SetWindowTextEx(LPCTSTR lpszString, Alignment align = Alignment::LEFT); //ΪؼɫıҪSetTextColorʹã void SetTextColor(COLORREF textColor); //ÿؼıɫ void SetBackColor(COLORREF back_color); //ÿؼɫ CString GetString() const; //ȡؼı protected: bool m_color_text{ false }; COLORREF m_text_color; //ؼɫ COLORREF m_back_color; CString m_text; //ؼϵı Alignment m_align{}; //ıĶ뷽ʽ bool m_draw_background_color{ false }; //ǷҪΪؼ䱳ɫ protected: virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); public: DECLARE_MESSAGE_MAP() afx_msg void OnPaint(); virtual void PreSubclassWindow(); }; ================================================ FILE: TrafficMonitor/TabDlg.cpp ================================================ #include "stdafx.h" #include "TabDlg.h" #include "TrafficMonitor.h" IMPLEMENT_DYNAMIC(CTabDlg, CDialogEx) CTabDlg::CTabDlg(UINT nIDTemplate, CWnd * pParent) : CDialogEx(nIDTemplate, pParent) { m_pParent = pParent; } CTabDlg::~CTabDlg() { } BOOL CTabDlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 //由于这是tab标签中的子对话框,因此用户按回车或ESC后不应该响应当前对话框的IDOK或IDCANCEL, //而应该响应tab标签的父窗口的IDOK或IDCANCEL命令 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) { if (m_pParent != nullptr) m_pParent->SendMessage(WM_COMMAND, IDCANCEL); return TRUE; } if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { if (m_pParent != nullptr) m_pParent->SendMessage(WM_COMMAND, IDOK); return TRUE; } return CDialogEx::PreTranslateMessage(pMsg); } BOOL CTabDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // TODO: 在此添加额外的初始化 //将窗口背景设置成白色 if (theApp.m_win_version.IsWindows11OrLater()) SetBackgroundColor(RGB(249, 249, 249)); else SetBackgroundColor(RGB(255, 255, 255)); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } CWnd* CTabDlg::GetParentWindow() { CWnd* pParent = GetParent(); if (pParent != nullptr) { return pParent->GetParent(); } return nullptr; } void CTabDlg::SetScrollbarInfo(int nPage, int nMax) { //初始化滚动条 SCROLLINFO scrollinfo; GetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL); scrollinfo.nPage = nPage; //设置滑块大小 scrollinfo.nMin = 0; scrollinfo.nMax = nMax; //设置滚动条的最大位置 if (scrollinfo.nMax < 0) scrollinfo.nMax = 0; scrollinfo.nPos = scrollinfo.nMin; SetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL); m_scroll_enable = true; } void CTabDlg::ResetScroll() { if (m_scroll_enable) { m_last_pos = 0; SCROLLINFO scrollinfo; GetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL); int step = scrollinfo.nPos - scrollinfo.nMin; scrollinfo.nPos = scrollinfo.nMin; SetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL); ScrollWindow(0, step); } } void CTabDlg::ScrollWindowSimple(int step) { SCROLLINFO scrollinfo; GetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL); scrollinfo.nPos -= step; if (scrollinfo.nPos < scrollinfo.nMin) { step = scrollinfo.nPos + step - scrollinfo.nMin; //如果向上滚动一个距离后小于滚动条的最小位置了,则修正step的值,使窗口滚动到最上方 scrollinfo.nPos = scrollinfo.nMin; } if (scrollinfo.nPos + scrollinfo.nPage > scrollinfo.nMax) //此处一定要注意加上滑块的长度,再作判断 { step -= (scrollinfo.nMax - (scrollinfo.nPos + scrollinfo.nPage)); //如果向上滚动一个距离后大于滚动条的最大位置了,则修正step的值,使窗口滚动到最下方 if (step > 0) step = 0; scrollinfo.nPos = scrollinfo.nMax; } SetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL); ScrollWindow(0, step); } void CTabDlg::EnableDlgCtrl(UINT id, bool enable) { CWnd* pCtrl = GetDlgItem(id); if (pCtrl != nullptr) pCtrl->EnableWindow(enable); } void CTabDlg::ShowDlgCtrl(UINT id, bool show) { CWnd* pCtrl = GetDlgItem(id); if (pCtrl != nullptr) pCtrl->ShowWindow(show); } BEGIN_MESSAGE_MAP(CTabDlg, CDialogEx) ON_WM_VSCROLL() ON_WM_MOUSEWHEEL() ON_WM_SIZE() END_MESSAGE_MAP() void CTabDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //参考资料:https://www.cnblogs.com/ranjiewen/p/6013922.html if (m_scroll_enable) { SCROLLINFO scrollinfo; GetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL); int unit = 1; int step = theApp.DPI(16); switch (nSBCode) { case SB_LINEUP: //Scroll one line up ScrollWindowSimple(unit * step); break; case SB_LINEDOWN: //Scroll one line down ScrollWindowSimple(-unit * step); break; case SB_PAGEUP: //Scroll one page up. ScrollWindowSimple(unit * step * 5); break; case SB_PAGEDOWN: //Scroll one page down ScrollWindowSimple(-unit * step * 5); break; case SB_ENDSCROLL: //End scroll break; case SB_THUMBPOSITION: //Scroll to the absolute position. The current position is provided in nPos break; case SB_THUMBTRACK: //Drag scroll box to specified position. The current position is provided in nPos { int y_amount = (m_last_pos - nPos)*unit; ScrollWindow(0, y_amount); scrollinfo.nPos = nPos; SetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL); } break; } m_last_pos = scrollinfo.nPos; } CDialogEx::OnVScroll(nSBCode, nPos, pScrollBar); } BOOL CTabDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (m_scroll_enable) { int step = theApp.DPI(64); if (zDelta > 0) { ScrollWindowSimple(step); } if (zDelta < 0) { ScrollWindowSimple(-step); } SCROLLINFO scrollinfo; GetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL); m_last_pos = scrollinfo.nPos; } return CDialogEx::OnMouseWheel(nFlags, zDelta, pt); } void CTabDlg::OnOK() { // TODO: 在此添加专用代码和/或调用基类 CDialogEx::OnOK(); } bool CTabDlg::IsScrollBarVisible() { SCROLLINFO scrollinfo; GetScrollInfo(SB_VERT, &scrollinfo, SIF_ALL); bool visible = scrollinfo.nPage < scrollinfo.nMax; return visible; } void CTabDlg::OnSize(UINT nType, int cx, int cy) { CDialogEx::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 SetControlMouseWheelEnable(!IsScrollBarVisible()); //如果显示了滚动条,则禁止控件响应鼠标滚轮,此时鼠标滚轮用于滚动窗口 } ================================================ FILE: TrafficMonitor/TabDlg.h ================================================ //这是用于Tab标签中的子对话框类 #pragma once class CTabDlg : public CDialogEx { DECLARE_DYNAMIC(CTabDlg) public: CTabDlg(UINT nIDTemplate, CWnd *pParent = NULL); ~CTabDlg(); virtual BOOL PreTranslateMessage(MSG* pMsg); virtual BOOL OnInitDialog(); CWnd* GetParentWindow(); void SetScrollbarInfo(int nPage, int nMax); void ResetScroll(); virtual void OnTabEntered() {} //当标签切换到当前窗口时被调用 virtual void OnOK(); void SetScrollEnable(bool enable) { m_scroll_enable = enable; } virtual void SetControlMouseWheelEnable(bool enable) {} //在派生类中重写此函数以设置控件是否允许响应鼠标滚轮 bool IsScrollBarVisible(); //滚动条是否可见 protected: void ScrollWindowSimple(int step); void EnableDlgCtrl(UINT id, bool enable); void ShowDlgCtrl(UINT id, bool show); protected: CWnd* m_pParent; bool m_scroll_enable{ false }; int m_last_pos{}; public: DECLARE_MESSAGE_MAP() afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); afx_msg void OnSize(UINT nType, int cx, int cy); }; ================================================ FILE: TrafficMonitor/TaskBarDlg.cpp ================================================ // TaskBarDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "TaskBarDlg.h" #include "afxdialogex.h" #include "TrafficMonitorDlg.h" #include "WindowsSettingHelper.h" // CTaskBarDlg 对话框 IMPLEMENT_DYNAMIC(CTaskBarDlg, CDialogEx) CTaskBarDlg::CTaskBarDlg(CWnd* pParent /*=NULL*/) : CDialogEx(IDD_TASK_BAR_DIALOG, pParent) { } CTaskBarDlg::~CTaskBarDlg() { for (auto iter = m_map_history_data.begin(); iter != m_map_history_data.end(); ++iter) { iter->second.clear(); } } void CTaskBarDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CTaskBarDlg, CDialogEx) ON_WM_RBUTTONUP() ON_WM_INITMENU() ON_WM_MOUSEMOVE() ON_WM_LBUTTONDBLCLK() ON_WM_TIMER() ON_WM_PAINT() ON_WM_CLOSE() ON_WM_LBUTTONUP() ON_MESSAGE(WM_EXITMENULOOP, &CTaskBarDlg::OnExitmenuloop) END_MESSAGE_MAP() // CTaskBarDlg 消息处理程序 void CTaskBarDlg::ShowInfo(CDC* pDC) { if (this->GetSafeHwnd() == NULL || pDC == nullptr || !IsWindow(this->GetSafeHwnd())) return; if (m_rect.IsRectEmpty() || m_rect.IsRectNull()) return; CRect draw_rect{ m_rect }; //绘图的矩形区域 draw_rect.MoveToXY(0, 0); //设置缓冲的DC CDrawDoubleBuffer draw_double_buffer(pDC, draw_rect); //绘图 CDrawCommon draw; draw.Create(draw_double_buffer.GetMemDC(), nullptr); draw.FillRect(draw_rect, theApp.m_taskbar_data.back_color); //填充背景色 draw.SetFont(&m_font); draw.SetBackColor(theApp.m_taskbar_data.back_color); //计算各部分的位置 int index = 0; CRect item_rect{}; int item_count = static_cast(m_item_widths.size()); //要显示的项目数量 auto last_iter = m_item_widths.begin(); for (auto iter = m_item_widths.begin(); iter != m_item_widths.end(); ++iter) { auto last_item_width = last_iter->item_width; //任务栏在桌面顶部或底部 if (IsTasksbarOnTopOrBottom()) { if (theApp.m_taskbar_data.horizontal_arrange) //水平排列 { if (index > 0) item_rect.MoveToX(item_rect.right + theApp.DPI(theApp.m_taskbar_data.item_space)); item_rect.right = item_rect.left + iter->item_width.TotalWidth(); item_rect.bottom = item_rect.top + m_window_height; if (iter->is_plugin) DrawPluginItem(draw, iter->plugin_item, item_rect, iter->item_width.label_width); else DrawDisplayItem(draw, iter->item_type, item_rect, iter->item_width.label_width); } else //非水平排列时,每两个一组显示 { //在index为奇数时同时绘制两个项目 if (index % 2 == 1) { CRect item_rect_up; //上面一个项目的矩形区域 if (index > 0) item_rect_up.MoveToXY(item_rect.right + theApp.DPI(theApp.m_taskbar_data.item_space), 0); item_rect.left = item_rect_up.left; item_rect.top = (m_window_height - TASKBAR_WND_HEIGHT / 2); //确定窗口大小 item_rect_up.bottom = item_rect.top - 1; item_rect.bottom = m_window_height; int width = max(iter->item_width.TotalWidth(), last_item_width.TotalWidth()); item_rect.right = item_rect.left + width; item_rect_up.right = item_rect_up.left + width; //绘制信息 if (last_iter->is_plugin) DrawPluginItem(draw, last_iter->plugin_item, item_rect_up, last_item_width.label_width); else DrawDisplayItem(draw, last_iter->item_type, item_rect_up, last_item_width.label_width); if (iter->is_plugin) DrawPluginItem(draw, iter->plugin_item, item_rect, iter->item_width.label_width); else DrawDisplayItem(draw, iter->item_type, item_rect, iter->item_width.label_width); } //要绘制的项目为奇数时绘制最后一个 else if (item_count % 2 == 1 && index == item_count - 1) { item_rect.MoveToXY(item_rect.right + theApp.DPI(theApp.m_taskbar_data.item_space), 0); item_rect.bottom = TASKBAR_WND_HEIGHT; item_rect.right = item_rect.left + iter->item_width.MaxWidth(); if (iter->is_plugin) DrawPluginItem(draw, iter->plugin_item, item_rect, iter->item_width.label_width, true); else DrawDisplayItem(draw, iter->item_type, item_rect, iter->item_width.label_width, true); } } } //任务栏在桌面两侧 else { if (index > 0) item_rect.MoveToXY(0, item_rect.bottom + theApp.DPI(theApp.m_taskbar_data.item_space)); item_rect.bottom = item_rect.top + TASKBAR_WND_HEIGHT / 2; item_rect.right = item_rect.left + min(m_window_width, m_rcMin.Width() - theApp.DPI(theApp.m_taskbar_data.item_space)); if (iter->is_plugin) DrawPluginItem(draw, iter->plugin_item, item_rect, iter->item_width.label_width); else DrawDisplayItem(draw, iter->item_type, item_rect, iter->item_width.label_width); } index++; last_iter = iter; } } void CTaskBarDlg::DrawDisplayItem(CDrawCommon& drawer, DisplayItem type, CRect rect, int label_width, bool vertical) { m_item_rects[type] = rect; //设置要绘制的文本颜色 COLORREF label_color{}; COLORREF text_color{}; if (theApp.m_taskbar_data.specify_each_item_color) { label_color = theApp.m_taskbar_data.text_colors[type].label; text_color = theApp.m_taskbar_data.text_colors[type].value; } else if (!theApp.m_taskbar_data.text_colors.empty()) { label_color = theApp.m_taskbar_data.text_colors.begin()->second.label; text_color = theApp.m_taskbar_data.text_colors.begin()->second.label; } //设置标签和数值的矩形区域 CRect rect_label{ rect }; CRect rect_value{ rect }; if (!vertical) { rect_label.right = rect_label.left + label_width; rect_value.left = rect_label.right; } else if (label_width != 0) { rect_label.bottom = rect_label.top + (rect_label.Height() / 2); rect_value.top = rect_label.bottom; } // 绘制状态条 if (type == TDI_CPU || type == TDI_MEMORY || type == TDI_GPU_USAGE || type == TDI_CPU_TEMP || type == TDI_GPU_TEMP || type == TDI_HDD_TEMP || type == TDI_MAIN_BOARD_TEMP || type == TDI_HDD_USAGE || type == TDI_UP || type == TDI_DOWN || type == TDI_TOTAL_SPEED/* ||type==TDI_CPU_FREQ*/) { int figure_value{}; switch (type) { case TDI_CPU: figure_value = theApp.m_cpu_usage; break; case TDI_MEMORY: figure_value = theApp.m_memory_usage; break; case TDI_GPU_USAGE: figure_value = theApp.m_gpu_usage; break; case TDI_CPU_TEMP: figure_value = theApp.m_cpu_temperature; break; case TDI_GPU_TEMP: figure_value = theApp.m_gpu_temperature; break; case TDI_HDD_TEMP: figure_value = theApp.m_hdd_temperature; break; case TDI_MAIN_BOARD_TEMP: figure_value = theApp.m_main_board_temperature; break; case TDI_HDD_USAGE: figure_value = theApp.m_hdd_usage; break; //case TDI_CPU_FREQ: // figure_value = theApp.m_cpu_freq; // break; case TDI_UP: figure_value = CalculateNetspeedPercent(theApp.m_out_speed); break; case TDI_DOWN: figure_value = CalculateNetspeedPercent(theApp.m_in_speed); break; case TDI_TOTAL_SPEED: figure_value = CalculateNetspeedPercent(theApp.m_in_speed + theApp.m_out_speed); break; default: break; } if ((type != TDI_UP && type != TDI_DOWN && type != TDI_TOTAL_SPEED) && theApp.m_taskbar_data.show_status_bar || (type == TDI_UP || type == TDI_DOWN || type == TDI_TOTAL_SPEED) && theApp.m_taskbar_data.show_netspeed_figure) { if (theApp.m_taskbar_data.cm_graph_type) { AddHisToList(type, figure_value); TryDrawGraph(drawer, rect, type); } else { TryDrawStatusBar(drawer, rect, figure_value); } } } //绘制标签 if (label_width > 0) { wstring str_label = theApp.m_taskbar_data.disp_str.Get(type); //if (theApp.m_taskbar_data.swap_up_down) //{ // if (type == TDI_UP) // str_label = theApp.m_taskbar_data.disp_str.Get(TDI_DOWN); // else if (type == TDI_DOWN) // str_label = theApp.m_taskbar_data.disp_str.Get(TDI_UP); //} drawer.DrawWindowText(rect_label, str_label.c_str(), label_color, (vertical ? Alignment::CENTER : Alignment::LEFT)); } //绘制数值 CString str_value; Alignment value_alignment{ theApp.m_taskbar_data.value_right_align ? Alignment::RIGHT : Alignment::LEFT }; //数值的对齐方式 if (vertical) value_alignment = Alignment::CENTER; //绘制上传或下载速度 if (type == TDI_UP || type == TDI_DOWN || type == TDI_TOTAL_SPEED) { CString format_str; if (theApp.m_taskbar_data.hide_unit && theApp.m_taskbar_data.speed_unit != SpeedUnit::AUTO) format_str = _T("%s"); else format_str = _T("%s/s"); CString str_in_speed = CCommon::DataSizeToString(theApp.m_in_speed, theApp.m_taskbar_data); CString str_out_speed = CCommon::DataSizeToString(theApp.m_out_speed, theApp.m_taskbar_data); CString str_total_speed = CCommon::DataSizeToString(theApp.m_in_speed + theApp.m_out_speed, theApp.m_taskbar_data); //if (theApp.m_taskbar_data.swap_up_down) // std::swap(str_in_speed, str_out_speed); if (type == TDI_UP) { str_value.Format(format_str, str_out_speed.GetString()); } else if (type == TDI_DOWN) { str_value.Format(format_str, str_in_speed.GetString()); } else { str_value.Format(format_str, str_total_speed.GetString()); } } //当内存显示为已使用内存或可用内存时 if (type == TDI_MEMORY && (theApp.m_taskbar_data.memory_display == MemoryDisplay::MEMORY_USED || theApp.m_taskbar_data.memory_display == MemoryDisplay::MEMORY_AVAILABLE)) { if (theApp.m_taskbar_data.memory_display == MemoryDisplay::MEMORY_USED) str_value = CCommon::DataSizeToString(static_cast(theApp.m_used_memory) * 1024, theApp.m_taskbar_data.separate_value_unit_with_space); else str_value = CCommon::DataSizeToString((static_cast(theApp.m_total_memory) - static_cast(theApp.m_used_memory)) * 1024, theApp.m_taskbar_data.separate_value_unit_with_space); } //绘制CPU或内存利用率 else if (type == TDI_CPU || type == TDI_MEMORY || type == TDI_GPU_USAGE || type == TDI_HDD_USAGE) { int usage{}; switch (type) { case TDI_CPU: usage = theApp.m_cpu_usage; break; case TDI_MEMORY: usage = theApp.m_memory_usage; break; case TDI_GPU_USAGE: usage = theApp.m_gpu_usage; break; case TDI_HDD_USAGE: usage = theApp.m_hdd_usage; break; default: break; } str_value = CCommon::UsageToString(usage, theApp.m_taskbar_data); //如果CPU或内存利用率达到100%,会导致显示不全,此时将绘图区域向右扩展一些 int text_width = m_pDC->GetTextExtent(str_value).cx; if (usage >= 100 && rect_value.Width() < text_width) rect_value.right = rect_value.left + text_width; } //绘制温度 else if (type == TDI_CPU_TEMP || type == TDI_GPU_TEMP || type == TDI_HDD_TEMP || type == TDI_MAIN_BOARD_TEMP) { int temperature{}; switch (type) { case TDI_CPU_TEMP: temperature = theApp.m_cpu_temperature; break; case TDI_GPU_TEMP: temperature = theApp.m_gpu_temperature; break; case TDI_HDD_TEMP: temperature = theApp.m_hdd_temperature; break; case TDI_MAIN_BOARD_TEMP: temperature = theApp.m_main_board_temperature; break; default: break; } str_value = CCommon::TemperatureToString(temperature, theApp.m_taskbar_data); } else if (type == TDI_CPU_FREQ) { str_value = CCommon::FreqToString(theApp.m_cpu_freq, theApp.m_taskbar_data); } drawer.DrawWindowText(rect_value, str_value, text_color, value_alignment); } void CTaskBarDlg::DrawPluginItem(CDrawCommon& drawer, IPluginItem* item, CRect rect, int label_width, bool vertical) { if (item == nullptr) return; m_item_rects[item] = rect; //设置要绘制的文本颜色 COLORREF label_text_color{}; COLORREF value_text_color{}; if (theApp.m_taskbar_data.specify_each_item_color) { label_text_color = theApp.m_taskbar_data.text_colors[item].label; value_text_color = theApp.m_taskbar_data.text_colors[item].value; } else if (!theApp.m_taskbar_data.text_colors.empty()) { label_text_color = theApp.m_taskbar_data.text_colors.begin()->second.label; value_text_color = theApp.m_taskbar_data.text_colors.begin()->second.label; } if (item->IsCustomDraw()) { //根据背景色的亮度判断深色还是浅色模式 const COLORREF& bk{ theApp.m_taskbar_data.back_color }; int background_brightness{ (GetRValue(bk) + GetGValue(bk) + GetBValue(bk)) / 3 }; //由插件自绘 ITMPlugin* plugin = theApp.m_plugins.GetPluginByItem(item); if (plugin != nullptr && plugin->GetAPIVersion() >= 2) { plugin->OnExtenedInfo(ITMPlugin::EI_LABEL_TEXT_COLOR, std::to_wstring(label_text_color).c_str()); plugin->OnExtenedInfo(ITMPlugin::EI_VALUE_TEXT_COLOR, std::to_wstring(value_text_color).c_str()); plugin->OnExtenedInfo(ITMPlugin::EI_DRAW_TASKBAR_WND, L"1"); } drawer.GetDC()->SetTextColor(value_text_color); item->DrawItem(drawer.GetDC()->GetSafeHdc(), rect.left, rect.top, rect.Width(), rect.Height(), background_brightness < 128); } else { CRect rect_label, rect_value; rect_label = rect_value = rect; if (label_width > 0) { if (!vertical) { rect_label = rect_value = rect; rect_label.right = rect_label.left + label_width; rect_value.left = rect_label.right; } else { rect_label.bottom = rect_label.top + rect.Height() / 2; rect_value.top = rect_label.bottom; } } //画标签 CString lable_text = theApp.m_taskbar_data.disp_str.Get(item).c_str(); lable_text += L' '; drawer.DrawWindowText(rect_label, lable_text, label_text_color, (vertical ? Alignment::CENTER : Alignment::LEFT)); //画数值 Alignment value_alignment{ theApp.m_taskbar_data.value_right_align ? Alignment::RIGHT : Alignment::LEFT }; //数值的对齐方式 if (vertical) value_alignment = Alignment::CENTER; drawer.DrawWindowText(rect_value, item->GetItemValueText(), value_text_color, value_alignment); } } void CTaskBarDlg::MoveWindow(CRect rect) { if (IsWindow(GetSafeHwnd())) { ::MoveWindow(GetSafeHwnd(), rect.left, rect.top, rect.Width(), rect.Height(), TRUE); } } void CTaskBarDlg::TryDrawStatusBar(CDrawCommon& drawer, const CRect& rect_bar, int usage_percent) { CSize fill_size = CSize(rect_bar.Width() * usage_percent / 100, rect_bar.Height()); CRect rect_fill(rect_bar.TopLeft(), fill_size); if (theApp.m_taskbar_data.show_graph_dashed_box) drawer.DrawRectOutLine(rect_bar, theApp.m_taskbar_data.status_bar_color, 1, true); drawer.FillRect(rect_fill, theApp.m_taskbar_data.status_bar_color); } bool CTaskBarDlg::AdjustWindowPos() { if (this->GetSafeHwnd() == NULL || !IsWindow(this->GetSafeHwnd())) return false; ::GetWindowRect(m_hMin, m_rcMin); //获得最小化窗口的区域 ::GetWindowRect(m_hBar, m_rcBar); //获得二级容器的区域 static bool last_taskbar_on_top_or_bottom; CheckTaskbarOnTopOrBottom(); if (m_taskbar_on_top_or_bottom != last_taskbar_on_top_or_bottom) { CalculateWindowSize(); last_taskbar_on_top_or_bottom = m_taskbar_on_top_or_bottom; } if (m_taskbar_on_top_or_bottom) //当任务栏在桌面顶部或底部时 { //设置窗口大小 m_rect.right = m_rect.left + m_window_width; m_rect.bottom = m_rect.top + m_window_height; if (m_rcMin.Width() != m_min_bar_width) //如果最小化窗口的宽度改变了,重新设置任务栏窗口的位置 { m_rcMinOri = m_rcMin; m_left_space = m_rcMin.left - m_rcBar.left; m_min_bar_width = m_rcMin.Width() - m_rect.Width(); //保存最小化窗口宽度 if (!theApp.m_taskbar_data.tbar_wnd_on_left) { if (theApp.m_is_windows11_taskbar) { if (!theApp.m_taskbar_data.tbar_wnd_snap) m_rect.MoveToX(m_rcBar.Width() - m_rect.Width() + 2); else m_rect.MoveToX(m_rcMin.right + 2); } else { ::MoveWindow(m_hMin, m_left_space, 0, m_rcMin.Width() - m_rect.Width(), m_rcMin.Height(), TRUE); //设置最小化窗口的位置 m_rect.MoveToX(m_left_space + m_rcMin.Width() - m_rect.Width() + 2); } } else { if (theApp.m_is_windows11_taskbar) { if (CWindowsSettingHelper::IsTaskbarCenterAlign()) { if (theApp.m_taskbar_data.tbar_wnd_snap) { int taskbar_btn_num{ 1 }; //Win11任务栏“运行中的程序”左侧4个按钮(开始、搜索、任务视图、聊天)有几个显示。(“开始”按钮总是显示) if (CWindowsSettingHelper::IsTaskbarSearchBtnShown()) taskbar_btn_num++; if (CWindowsSettingHelper::IsTaskbarTaskViewBtnShown()) taskbar_btn_num++; if (CWindowsSettingHelper::IsTaskbarChartBtnShown()) taskbar_btn_num++; m_rect.MoveToX(m_rcMin.left - m_rect.Width() - 2 - theApp.DPI(44) * taskbar_btn_num); //每个按钮44像素 } else { if (CWindowsSettingHelper::IsTaskbarWidgetsBtnShown()) m_rect.MoveToX(2 + theApp.DPI(theApp.m_cfg_data.taskbar_left_space_win11)); else m_rect.MoveToX(2); } } else { m_rect.MoveToX(2); } } else { ::MoveWindow(m_hMin, m_left_space + m_rect.Width(), 0, m_rcMin.Width() - m_rect.Width(), m_rcMin.Height(), TRUE); m_rect.MoveToX(m_left_space); } } m_rect.MoveToY((m_rcBar.Height() - m_rect.Height()) / 2); if (theApp.m_taskbar_data.horizontal_arrange && theApp.m_win_version.IsWindows7()) m_rect.MoveToY(m_rect.top + theApp.DPI(1)); MoveWindow(m_rect); } } else //当任务栏在屏幕在左侧或右侧时 { //设置窗口大小 if (m_rcMin.Height() != m_min_bar_height) //如果最小化窗口的高度改变了,重新设置任务栏窗口的位置 { m_rcMinOri = m_rcMin; m_top_space = m_rcMin.top - m_rcBar.top; m_min_bar_height = m_rcMin.Height() - m_rect.Height(); //保存最小化窗口高度 if (!theApp.m_taskbar_data.tbar_wnd_on_left) { ::MoveWindow(m_hMin, 0, m_top_space, m_rcMin.Width(), m_rcMin.Height() - m_rect.Height(), TRUE); //设置最小化窗口的位置 m_rect.MoveToY(m_top_space + m_rcMin.Height() - m_rect.Height() + 2); } else { ::MoveWindow(m_hMin, 0, m_top_space + m_rect.Height(), m_rcMin.Width(), m_rcMin.Height() - m_rect.Height(), TRUE); //设置最小化窗口的位置 m_rect.MoveToY(m_top_space); } m_rect.MoveToX((m_rcMin.Width() - m_window_width) / 2); if (m_rect.left < theApp.DPI(2)) m_rect.MoveToX(theApp.DPI(2)); MoveWindow(m_rect); } } CRect rect{ m_rect }; //如果窗口没有被成功嵌入到任务栏,窗口移动到了基于屏幕左上角的绝对位置,则修正窗口的位置 if (m_connot_insert_to_task_bar) { rect.MoveToXY(rect.left + m_rcBar.left, rect.top + m_rcBar.top); this->MoveWindow(rect); } if (m_connot_insert_to_task_bar && ::GetForegroundWindow() == m_hTaskbar) //在窗口无法嵌入任务栏时,如果焦点设置在了任务栏上,则让窗口置顶 { SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); //设置置顶 } return true; } void CTaskBarDlg::ApplyWindowTransparentColor() { #ifndef COMPILE_FOR_WINXP if (theApp.m_is_windows11_taskbar) //Windows11下背景色不使用纯黑色,以解决深色模式下右键菜单无法弹出的问题 { if (theApp.m_taskbar_data.transparent_color == 0 && theApp.m_taskbar_data.back_color == 0) { theApp.m_taskbar_data.transparent_color = 1; theApp.m_taskbar_data.back_color = 1; } } if ((theApp.m_taskbar_data.transparent_color != 0) && theApp.m_taksbar_transparent_color_enable) { SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED); SetLayeredWindowAttributes(theApp.m_taskbar_data.transparent_color, 0, LWA_COLORKEY); } else { SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED); } #endif // !COMPILE_FOR_WINXP } void CTaskBarDlg::CheckTaskbarOnTopOrBottom() { CRect rect; CRect rcMin; CRect rcBar; if (m_hTaskbar != 0) { ::GetWindowRect(m_hMin, rcMin); //获得最小化窗口的区域 ::GetWindowRect(m_hBar, rcBar); //获得二级容器的区域 if (m_left_space == 0) m_left_space = rcMin.left - rcBar.left; if (m_top_space == 0) m_top_space = rcMin.top - rcBar.top; ::GetWindowRect(m_hTaskbar, rect); //获取任务栏的矩形区域 m_taskbar_on_top_or_bottom = (rect.Width() >= rect.Height()); //如果任务栏的宽度大于高度,则任务在屏幕的顶部或底部 } else { m_taskbar_on_top_or_bottom = true; } } CString CTaskBarDlg::GetMouseTipsInfo() { CString tip_info; CString temp; temp.Format(_T("%s: %s\r\n (%s: %s/%s: %s)"), CCommon::LoadText(IDS_TRAFFIC_USED_TODAY), CCommon::KBytesToString((theApp.m_today_up_traffic + theApp.m_today_down_traffic) / 1024u), CCommon::LoadText(IDS_UPLOAD), CCommon::KBytesToString(theApp.m_today_up_traffic / 1024u), CCommon::LoadText(IDS_DOWNLOAD), CCommon::KBytesToString(theApp.m_today_down_traffic / 1024u) ); tip_info += temp; if (!IsItemShow(TDI_UP)) { temp.Format(_T("\r\n%s: %s/s"), CCommon::LoadText(IDS_UPLOAD), CCommon::DataSizeToString(theApp.m_out_speed, theApp.m_main_wnd_data)); tip_info += temp; } if (!IsItemShow(TDI_DOWN)) { temp.Format(_T("\r\n%s: %s/s"), CCommon::LoadText(IDS_DOWNLOAD), CCommon::DataSizeToString(theApp.m_in_speed, theApp.m_main_wnd_data)); tip_info += temp; } if (!IsItemShow(TDI_CPU)) { temp.Format(_T("\r\n%s: %d %%"), CCommon::LoadText(IDS_CPU_USAGE), theApp.m_cpu_usage); tip_info += temp; } if (!IsShowCpuMemory()) { temp.Format(_T("\r\n%s: %s/%s"), CCommon::LoadText(IDS_MEMORY_USAGE), CCommon::KBytesToString(theApp.m_used_memory), CCommon::KBytesToString(theApp.m_total_memory)); } if (!IsItemShow(TDI_MEMORY)) { temp.Format(_T("\r\n%s: %s/%s (%d %%)"), CCommon::LoadText(IDS_MEMORY_USAGE), CCommon::KBytesToString(theApp.m_used_memory), CCommon::KBytesToString(theApp.m_total_memory), theApp.m_memory_usage); tip_info += temp; } else { temp.Format(_T("\r\n%s: %s/%s"), CCommon::LoadText(IDS_MEMORY_USAGE), CCommon::KBytesToString(theApp.m_used_memory), CCommon::KBytesToString(theApp.m_total_memory)); tip_info += temp; } #ifndef WITHOUT_TEMPERATURE CTrafficMonitorDlg* pMainWnd = dynamic_cast(theApp.m_pMainWnd); if (pMainWnd->IsTemperatureNeeded()) { if (!IsItemShow(TDI_GPU_USAGE) && theApp.m_gpu_usage >= 0) { temp.Format(_T("\r\n%s: %d %%"), CCommon::LoadText(IDS_GPU_USAGE), theApp.m_gpu_usage); tip_info += temp; } if (!IsItemShow(TDI_CPU_TEMP) && theApp.m_cpu_temperature > 0) { temp.Format(_T("\r\n%s: %s"), CCommon::LoadText(IDS_CPU_TEMPERATURE), CCommon::TemperatureToString(theApp.m_cpu_temperature, theApp.m_taskbar_data)); tip_info += temp; } if (!IsItemShow(TDI_CPU_FREQ) && theApp.m_cpu_freq > 0) { temp.Format(_T("\r\n%s: %s"), CCommon::LoadText(IDS_CPU_FREQ), CCommon::FreqToString(theApp.m_cpu_freq, theApp.m_taskbar_data)); tip_info += temp; } if (!IsItemShow(TDI_GPU_TEMP) && theApp.m_gpu_temperature > 0) { temp.Format(_T("\r\n%s: %s"), CCommon::LoadText(IDS_GPU_TEMPERATURE), CCommon::TemperatureToString(theApp.m_gpu_temperature, theApp.m_taskbar_data)); tip_info += temp; } if (!IsItemShow(TDI_HDD_TEMP) && theApp.m_hdd_temperature > 0) { temp.Format(_T("\r\n%s: %s"), CCommon::LoadText(IDS_HDD_TEMPERATURE), CCommon::TemperatureToString(theApp.m_hdd_temperature, theApp.m_taskbar_data)); tip_info += temp; } if (!IsItemShow(TDI_MAIN_BOARD_TEMP) && theApp.m_main_board_temperature > 0) { temp.Format(_T("\r\n%s: %s"), CCommon::LoadText(IDS_MAINBOARD_TEMPERATURE), CCommon::TemperatureToString(theApp.m_main_board_temperature, theApp.m_taskbar_data)); tip_info += temp; } if (!IsItemShow(TDI_HDD_USAGE) && theApp.m_hdd_usage >= 0) { temp.Format(_T("\r\n%s: %d %%"), CCommon::LoadText(IDS_HDD_USAGE), theApp.m_hdd_usage); tip_info += temp; } } #endif //添加插件项目的鼠标提示 tip_info += theApp.GetPlauginTooltipInfo().c_str(); return tip_info; } void CTaskBarDlg::SetTextFont() { //如果m_font已经关联了一个字体资源对象,则释放它 if (m_font.m_hObject) { m_font.DeleteObject(); } //创建新的字体 theApp.m_taskbar_data.font.Create(m_font, theApp.GetDpi()); } void CTaskBarDlg::ApplySettings() { SetTextFont(); CalculateWindowSize(); } void CTaskBarDlg::CalculateWindowSize() { bool horizontal_arrange = theApp.m_taskbar_data.horizontal_arrange && m_taskbar_on_top_or_bottom; if (theApp.m_taskbar_data.m_tbar_display_item == 0) theApp.m_taskbar_data.m_tbar_display_item |= TDI_UP; //至少显示一项 m_item_widths.clear(); //显示项目的宽度 std::map item_widths; m_pDC->SelectObject(&m_font); //计算标签宽度 //const auto& item_map = theApp.m_taskbar_data.disp_str.GetAllItems(); for (auto iter = theApp.m_plugins.AllDisplayItemsWithPlugins().begin(); iter != theApp.m_plugins.AllDisplayItemsWithPlugins().end(); ++iter) { if (iter->is_plugin) { auto plugin = iter->plugin_item; if (plugin != nullptr) { int& label_width{ item_widths[*iter].label_width }; if (plugin->IsCustomDraw()) { label_width = 0; } else { CString lable_text = theApp.m_taskbar_data.disp_str.Get(plugin).c_str(); if (!lable_text.IsEmpty()) lable_text += L' '; label_width = m_pDC->GetTextExtent(lable_text).cx; } } } else { item_widths[*iter].label_width = m_pDC->GetTextExtent(theApp.m_taskbar_data.disp_str.Get(*iter).c_str()).cx; } } //计算数值部分宽度 //计算显示上传下载部分所需要的宽度 CString sample_str; int value_width{}; wstring digits(theApp.m_taskbar_data.digits_number, L'8'); //根据数据位数生成指定个数的“8” bool hide_unit{ theApp.m_taskbar_data.hide_unit && theApp.m_taskbar_data.speed_unit != SpeedUnit::AUTO }; if (theApp.m_taskbar_data.speed_short_mode) { if (hide_unit) sample_str.Format(_T("%s."), digits.c_str()); else sample_str.Format(_T("%s.M/s"), digits.c_str()); } else { if (hide_unit) sample_str.Format(_T("%s.8"), digits.c_str()); else sample_str.Format(_T("%s.8MB/s"), digits.c_str()); } if (!hide_unit && theApp.m_taskbar_data.separate_value_unit_with_space) sample_str += _T(' '); if (theApp.m_taskbar_data.speed_short_mode && !theApp.m_taskbar_data.unit_byte && !theApp.m_taskbar_data.hide_unit) sample_str += _T('b'); value_width = m_pDC->GetTextExtent(sample_str).cx; //计算使用当前字体显示文本需要的宽度值 item_widths[TDI_UP].value_width = value_width; item_widths[TDI_DOWN].value_width = value_width; item_widths[TDI_TOTAL_SPEED].value_width = value_width; //计算显示CPU、内存部分所需要的宽度 CString str; if (theApp.m_taskbar_data.hide_percent) { str = _T("99"); } else if (theApp.m_taskbar_data.separate_value_unit_with_space) { str = _T("99 %"); } else { str = _T("99%"); } value_width = m_pDC->GetTextExtent(str).cx; //内存显示的宽度 int memory_width{ value_width }; if (theApp.m_taskbar_data.memory_display == MemoryDisplay::MEMORY_USED || theApp.m_taskbar_data.memory_display == MemoryDisplay::MEMORY_AVAILABLE) { if (theApp.m_taskbar_data.separate_value_unit_with_space) str = _T("19.99 GB"); else str = _T("19.99GB"); memory_width = m_pDC->GetTextExtent(str).cx; } item_widths[TDI_CPU].value_width = value_width; item_widths[TDI_MEMORY].value_width = memory_width; item_widths[TDI_GPU_USAGE].value_width = value_width; item_widths[TDI_HDD_USAGE].value_width = value_width; item_widths[TDI_CPU_FREQ].value_width = m_pDC->GetTextExtent(_T("1.00 GHz")).cx; //计算温度显示的宽度 if (theApp.m_taskbar_data.separate_value_unit_with_space) str = _T("99 °C"); else str = _T("99°C"); value_width = m_pDC->GetTextExtent(str).cx; value_width += theApp.DPI(2); item_widths[TDI_CPU_TEMP].value_width = value_width; item_widths[TDI_GPU_TEMP].value_width = value_width; item_widths[TDI_HDD_TEMP].value_width = value_width; item_widths[TDI_MAIN_BOARD_TEMP].value_width = value_width; //计算插件项目的宽度 for (const auto& plugin : theApp.m_plugins.GetPluginItems()) { int& value_width{ item_widths[plugin].value_width }; if (plugin != nullptr && theApp.m_taskbar_data.plugin_display_item.Contains(plugin->GetItemId())) { if (plugin->IsCustomDraw()) { value_width = theApp.m_plugins.GetItemWidth(plugin, m_pDC); } else { value_width = m_pDC->GetTextExtent(plugin->GetItemValueSampleText()).cx; } } } auto item_order{ theApp.m_taskbar_data.item_order.GetAllDisplayItemsWithOrder() }; for (const auto& item : item_order) { if (theApp.IsTaksbarItemDisplayed(item)) { ItemWidthInfo width_info = item; width_info.item_width = item_widths[item]; m_item_widths.push_back(width_info); } } int item_count = static_cast(m_item_widths.size()); //计算窗口总宽度 if (IsTasksbarOnTopOrBottom()) //任务栏在桌面的顶部或底部时 { m_window_width = 0; if (theApp.m_taskbar_data.horizontal_arrange) //水平排列时 { for (auto iter = m_item_widths.begin(); iter != m_item_widths.end(); ++iter) { m_window_width += iter->item_width.TotalWidth(); } m_window_width += theApp.DPI(theApp.m_taskbar_data.item_space) * item_count; //加上每个标签间的空隙 } else //非水平排列时,每两个一组排列 { int index = 0; int width0; for (auto iter = m_item_widths.begin(); iter != m_item_widths.end(); ++iter) { if (index % 2 == 0) { width0 = iter->item_width.TotalWidth(); } else { m_window_width += max(width0, iter->item_width.TotalWidth()); } if (item_count % 2 == 1 && index == item_count - 1) //项目数为奇数时加上最后一个的宽度 { m_window_width += iter->item_width.MaxWidth(); } index++; } m_window_width += theApp.DPI(theApp.m_taskbar_data.item_space) * ((item_count + 1) / 2 + 1); //加上每个标签间的空隙 } } else //任务栏在桌面两侧时 { m_window_width = 0; //所有标签中最大的宽度即为窗口宽度 for (auto iter = m_item_widths.begin(); iter != m_item_widths.end(); ++iter) { if (m_window_width < iter->item_width.TotalWidth()) m_window_width = iter->item_width.TotalWidth(); } } //计算窗口高度 if (IsTasksbarOnTopOrBottom()) { if (!horizontal_arrange) m_window_height = TASKBAR_WND_HEIGHT; else m_window_height = TASKBAR_WND_HEIGHT * 2 / 3; } else { m_window_height = TASKBAR_WND_HEIGHT / 2 * item_count; m_window_height += (theApp.DPI(theApp.m_taskbar_data.item_space) * item_count); //加上每个标签间的空隙 } m_rect.right = m_rect.left + m_window_width; m_rect.bottom = m_rect.top + m_window_height; } void CTaskBarDlg::SetToolTipsTopMost() { m_tool_tips.SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); } void CTaskBarDlg::UpdateToolTips() { if (theApp.m_taskbar_data.show_tool_tip && IsWindow(m_tool_tips.GetSafeHwnd())) { CString tip_info; tip_info = GetMouseTipsInfo(); m_tool_tips.UpdateTipText(tip_info, this); } } bool CTaskBarDlg::IsItemShow(DisplayItem item) { return (theApp.m_taskbar_data.m_tbar_display_item & item); } bool CTaskBarDlg::IsShowCpuMemory() { return ((theApp.m_taskbar_data.m_tbar_display_item & TDI_CPU) || (theApp.m_taskbar_data.m_tbar_display_item & TDI_MEMORY)); } bool CTaskBarDlg::IsShowNetSpeed() { return ((theApp.m_taskbar_data.m_tbar_display_item & TDI_UP) || (theApp.m_taskbar_data.m_tbar_display_item & TDI_DOWN)); } BOOL CTaskBarDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // TODO: 在此添加额外的初始化 //设置隐藏任务栏图标 ModifyStyleEx(0, WS_EX_TOOLWINDOW); m_pDC = GetDC(); //设置字体 SetTextFont(); m_pDC->SelectObject(&m_font); m_hTaskbar = ::FindWindow(L"Shell_TrayWnd", NULL); //寻找类名是Shell_TrayWnd的窗口句柄 m_hBar = ::FindWindowEx(m_hTaskbar, 0, L"ReBarWindow32", NULL); //寻找二级容器的句柄 m_hMin = ::FindWindowEx(m_hBar, 0, L"MSTaskSwWClass", NULL); //寻找最小化窗口的句柄 //在“Shell_TrayWnd”的子窗口找到类名为“Windows.UI.Composition.DesktopWindowContentBridge”的窗口则认为是Windows11的任务栏 if (theApp.m_win_version.IsWindows11OrLater()) { theApp.m_is_windows11_taskbar = (::FindWindowExW(m_hTaskbar, 0, L"Windows.UI.Composition.DesktopWindowContentBridge", NULL) != NULL); } //设置窗口透明色 ApplyWindowTransparentColor(); ::GetWindowRect(m_hMin, m_rcMin); //获得最小化窗口的区域 ::GetWindowRect(m_hBar, m_rcBar); //获得二级容器的区域 m_left_space = m_rcMin.left - m_rcBar.left; m_top_space = m_rcMin.top - m_rcBar.top; CheckTaskbarOnTopOrBottom(); CalculateWindowSize(); m_rect.SetRectEmpty(); m_rect.bottom = m_window_height; m_rect.right = m_rect.left + m_window_width; m_connot_insert_to_task_bar = !(::SetParent(this->m_hWnd, m_hBar)); //把程序窗口设置成任务栏的子窗口 m_error_code = GetLastError(); AdjustWindowPos(); SetBackgroundColor(theApp.m_taskbar_data.back_color); //初始化鼠标提示 if (IsWindow(GetSafeHwnd()) && m_tool_tips.Create(this, TTS_ALWAYSTIP) && IsWindow(m_tool_tips.GetSafeHwnd())) { m_tool_tips.SetMaxTipWidth(600); m_tool_tips.AddTool(this, _T("")); SetToolTipsTopMost(); //设置提示信息总是置顶 } //SetTimer(TASKBAR_TIMER, 100, NULL); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CTaskBarDlg::OnCancel() { // TODO: 在此添加专用代码和/或调用基类 //SaveConfig(); //关闭所有以任务栏窗口为父窗口的窗口 for (const auto& item : CBaseDialog::AllUniqueHandels()) { HWND parent = ::GetParent(item.second); if (parent == GetSafeHwnd()) { ::SendMessage(item.second, WM_COMMAND, IDCANCEL, 0); } } DestroyWindow(); //程序关闭的时候,把最小化窗口的width恢复回去 CheckTaskbarOnTopOrBottom(); if (m_taskbar_on_top_or_bottom) ::MoveWindow(m_hMin, m_left_space, 0, m_rcMinOri.Width(), m_rcMinOri.Height(), TRUE); else ::MoveWindow(m_hMin, 0, m_top_space, m_rcMinOri.Width(), m_rcMinOri.Height(), TRUE); //CDialogEx::OnCancel(); } void CTaskBarDlg::OnRButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_menu_popuped = true; m_tool_tips.Pop(); if (CheckClickedItem(point) && m_clicked_item.is_plugin && m_clicked_item.plugin_item != nullptr) { ITMPlugin* plugin = theApp.m_plugins.GetPluginByItem(m_clicked_item.plugin_item); if (plugin != nullptr && plugin->GetAPIVersion() >= 3) { if (m_clicked_item.plugin_item->OnMouseEvent(IPluginItem::MT_RCLICKED, point.x, point.y, (void*)GetSafeHwnd(), IPluginItem::MF_TASKBAR_WND) != 0) return; } } CPoint point1; //定义一个用于确定光标位置的位置 GetCursorPos(&point1); //获取当前光标的位置,以便使得菜单可以跟随光标 CMenu* pMenu = theApp.m_taskbar_menu.GetSubMenu(0); if (pMenu != nullptr) pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, this); //在指定位置显示弹出菜单 CDialogEx::OnRButtonUp(nFlags, point1); } void CTaskBarDlg::OnInitMenu(CMenu* pMenu) { CDialogEx::OnInitMenu(pMenu); // TODO: 在此处添加消息处理程序代码 pMenu->CheckMenuItem(ID_SHOW_MAIN_WND, MF_BYCOMMAND | (!theApp.m_cfg_data.m_hide_main_window ? MF_CHECKED : MF_UNCHECKED)); pMenu->EnableMenuItem(ID_SELECT_ALL_CONNECTION, MF_BYCOMMAND | (theApp.m_general_data.show_all_interface ? MF_GRAYED : MF_ENABLED)); pMenu->EnableMenuItem(ID_CHECK_UPDATE, MF_BYCOMMAND | (theApp.IsCheckingForUpdate() ? MF_GRAYED : MF_ENABLED)); //pMenu->SetDefaultItem(ID_NETWORK_INFO); //设置默认菜单项 switch (theApp.m_taskbar_data.double_click_action) { case DoubleClickAction::CONNECTION_INFO: pMenu->SetDefaultItem(ID_NETWORK_INFO); break; case DoubleClickAction::HISTORY_TRAFFIC: pMenu->SetDefaultItem(ID_TRAFFIC_HISTORY); break; case DoubleClickAction::SHOW_MORE_INFO: pMenu->SetDefaultItem(ID_SHOW_CPU_MEMORY2); break; case DoubleClickAction::OPTIONS: pMenu->SetDefaultItem(ID_OPTIONS2); break; case DoubleClickAction::TASK_MANAGER: pMenu->SetDefaultItem(ID_OPEN_TASK_MANAGER); break; default: pMenu->SetDefaultItem(-1); break; } ::SendMessage(theApp.m_pMainWnd->GetSafeHwnd(), WM_TASKBAR_MENU_POPED_UP, 0, 0); //通知主窗口菜单已弹出 } BOOL CTaskBarDlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 //屏蔽按回车键和ESC键退出 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) return TRUE; if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) return TRUE; if (theApp.m_taskbar_data.show_tool_tip && !m_menu_popuped && IsWindow(m_tool_tips.GetSafeHwnd()) && (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONUP || pMsg->message == WM_MOUSEMOVE)) { m_tool_tips.RelayEvent(pMsg); } return CDialogEx::PreTranslateMessage(pMsg); } void CTaskBarDlg::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CDialogEx::OnMouseMove(nFlags, point); } void CTaskBarDlg::OnLButtonDblClk(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (CheckClickedItem(point) && m_clicked_item.is_plugin && m_clicked_item.plugin_item != nullptr) { ITMPlugin* plugin = theApp.m_plugins.GetPluginByItem(m_clicked_item.plugin_item); if (plugin != nullptr && plugin->GetAPIVersion() >= 3) { if (m_clicked_item.plugin_item->OnMouseEvent(IPluginItem::MT_DBCLICKED, point.x, point.y, (void*)GetSafeHwnd(), IPluginItem::MF_TASKBAR_WND) != 0) return; } } switch (theApp.m_taskbar_data.double_click_action) { case DoubleClickAction::CONNECTION_INFO: SendMessage(WM_COMMAND, ID_NETWORK_INFO); //双击后弹出“连接详情”对话框 break; case DoubleClickAction::HISTORY_TRAFFIC: SendMessage(WM_COMMAND, ID_TRAFFIC_HISTORY); //双击后弹出“历史流量统计”对话框 break; case DoubleClickAction::SHOW_MORE_INFO: PostMessage(WM_COMMAND, ID_SHOW_CPU_MEMORY2); //切换显示CPU和内存利用率 break; case DoubleClickAction::OPTIONS: SendMessage(WM_COMMAND, ID_OPTIONS2); //双击后弹出“选项设置”对话框 break; case DoubleClickAction::TASK_MANAGER: ShellExecuteW(NULL, _T("open"), (theApp.m_system_dir + L"\\Taskmgr.exe").c_str(), NULL, NULL, SW_NORMAL); //打开任务管理器 break; case DoubleClickAction::SEPCIFIC_APP: ShellExecuteW(NULL, _T("open"), (theApp.m_taskbar_data.double_click_exe).c_str(), NULL, NULL, SW_NORMAL); //打开指定程序,默认任务管理器 break; default: break; } //CDialogEx::OnLButtonDblClk(nFlags, point); } void CTaskBarDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //if (nIDEvent == TASKBAR_TIMER) //{ // AdjustWindowPos(); // //ShowInfo(); // Invalidate(FALSE); //} CDialogEx::OnTimer(nIDEvent); } BOOL CTaskBarDlg::OnCommand(WPARAM wParam, LPARAM lParam) { // TODO: 在此添加专用代码和/或调用基类 UINT uMsg = LOWORD(wParam); if (uMsg == ID_SELECT_ALL_CONNECTION || uMsg == ID_SELETE_CONNECTION || (uMsg > ID_SELECT_ALL_CONNECTION && uMsg <= ID_SELETE_CONNECTION_MAX)) { ::SendMessage(theApp.m_pMainWnd->GetSafeHwnd(), WM_COMMAND, wParam, lParam); //如果点击了“选择网络连接”子菜单项,将消息转发到主窗口 return TRUE; } //选择了“显示项目”中的插件项目 if (uMsg >= ID_SHOW_PLUGIN_ITEM_START && uMsg <= ID_SHOW_PLUGIN_ITEM_MAX) { IPluginItem* item = theApp.m_plugins.GetItemByIndex(uMsg - ID_SHOW_PLUGIN_ITEM_START); if (item != nullptr) { bool displayed = theApp.m_taskbar_data.plugin_display_item.Contains(item->GetItemId()); theApp.m_taskbar_data.plugin_display_item.SetStrContained(item->GetItemId(), !displayed); ::PostMessage(theApp.m_pMainWnd->GetSafeHwnd(), WM_REOPEN_TASKBAR_WND, 0, 0); } } return CDialogEx::OnCommand(wParam, lParam); } void CTaskBarDlg::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CDialogEx::OnPaint() ShowInfo(&dc); } void CTaskBarDlg::AddHisToList(DisplayItem item_type, int current_usage_percent) { int& data_count{ m_history_data_count[item_type] }; std::list& list = m_map_history_data[item_type]; //将数累加到加链表的头部,直到添加的数据数量达到TASKBAR_GRAPH_STEP的倍数时计算平均数 if (data_count % TASKBAR_GRAPH_STEP == 0) { //计算前面累加的TASKBAR_GRAPH_STEP个数据的平均数 if (!list.empty()) list.front() /= TASKBAR_GRAPH_STEP; //将新的数据添加到末尾 list.push_front(current_usage_percent); } else { //数累加到加链表的头部 list.front() += current_usage_percent; } size_t graph_max_length = m_item_rects[item_type].Width(); //判断是否超过最大长度,如果超过,将链表尾部数据移除 if (list.size() > graph_max_length) { list.pop_back(); } data_count++; } int CTaskBarDlg::CalculateNetspeedPercent(unsigned __int64 net_speed) { int percet = 0; unsigned __int64 max_value{ theApp.m_taskbar_data.GetNetspeedFigureMaxValueInBytes() }; if (net_speed >= max_value) percet = 100; else if (max_value > 0) percet = net_speed * 100 / max_value; return percet; } bool CTaskBarDlg::CheckClickedItem(CPoint point) { for (const auto& item : m_item_rects) { if (item.second.PtInRect(point)) { m_clicked_item = item.first; return true; } } m_clicked_item = TDI_UP; return false; } void CTaskBarDlg::TryDrawGraph(CDrawCommon& drawer, const CRect& value_rect, DisplayItem item_type) { std::list& list = m_map_history_data[item_type]; if (theApp.m_taskbar_data.show_graph_dashed_box) drawer.DrawRectOutLine(value_rect, theApp.m_taskbar_data.status_bar_color, 1, true); int i{ -1 }; for (const auto& item : list) { i++; if (i == 0) //不绘制链表头部的数据,因为在累加中,还未取平均数 continue; if (i >= value_rect.Width()) break; //从右往左画线 CPoint start_point = CPoint(value_rect.right - i, value_rect.bottom); int height = item * value_rect.Height() / 100; drawer.DrawLine(start_point, height, theApp.m_taskbar_data.status_bar_color); } } void CTaskBarDlg::OnClose() { // TODO: 在此添加消息处理程序代码和/或调用默认值 ::SendMessage(theApp.m_pMainWnd->GetSafeHwnd(), WM_TASKBAR_WND_CLOSED, 0, 0); CDialogEx::OnClose(); } void CTaskBarDlg::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (CheckClickedItem(point) && m_clicked_item.is_plugin && m_clicked_item.plugin_item != nullptr) { ITMPlugin* plugin = theApp.m_plugins.GetPluginByItem(m_clicked_item.plugin_item); if (plugin != nullptr && plugin->GetAPIVersion() >= 3) { if (m_clicked_item.plugin_item->OnMouseEvent(IPluginItem::MT_LCLICKED, point.x, point.y, (void*)GetSafeHwnd(), IPluginItem::MF_TASKBAR_WND) != 0) return; } } CDialogEx::OnLButtonUp(nFlags, point); } afx_msg LRESULT CTaskBarDlg::OnExitmenuloop(WPARAM wParam, LPARAM lParam) { m_menu_popuped = false; return 0; } ================================================ FILE: TrafficMonitor/TaskBarDlg.h ================================================ #pragma once #include "Common.h" #include "afxwin.h" #include "DrawCommon.h" #include "IniHelper.h" #include "CommonData.h" #include "TaskbarItemOrderHelper.h" #include // CTaskBarDlg 对话框 #define TASKBAR_WND_HEIGHT theApp.DPI(32) //任务栏窗口的高度 #define WM_TASKBAR_MENU_POPED_UP (WM_USER + 1004) //定义任务栏窗口右键菜单弹出时发出的消息 //#define TASKBAR_GRAPH_MAX_LEN 600 //历史数据存储最大长度 #define TASKBAR_GRAPH_STEP 5 //几秒钟画一条线 class CTaskBarDlg : public CDialogEx { DECLARE_DYNAMIC(CTaskBarDlg) public: CTaskBarDlg(CWnd* pParent = NULL); // 标准构造函数 virtual ~CTaskBarDlg(); CToolTipCtrl m_tool_tips; void ShowInfo(CDC* pDC); //将信息绘制到控件上 void TryDrawStatusBar(CDrawCommon& drawer, const CRect& rect_bar, int usage_percent); //绘制CPU/内存状态条 void TryDrawGraph(CDrawCommon& drawer, const CRect& value_rect, DisplayItem item_type); // 绘制CPU/内存动态图 bool AdjustWindowPos(); //设置窗口在任务栏中的位置 void ApplyWindowTransparentColor(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_TASK_BAR_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 HWND m_hTaskbar; //任务栏窗口句柄 HWND m_hBar; //任务栏窗口二级容器的句柄 HWND m_hMin; //最小化窗口的句柄 CRect m_rcBar; //初始状态时任务栏窗口的矩形区域 CRect m_rcMin; //最小化窗口的矩形区域 CRect m_rcMinOri; //初始状态时最小化窗口的矩形区域 CRect m_rect; //当前窗口的矩形区域 int m_window_width{}; int m_window_height{}; //任务栏各个部分的宽度 struct ItemWidth { int label_width{}; //标签部分宽度 int value_width{}; //数值部分宽度 int TotalWidth() const //总宽度 { return label_width + value_width; } int MaxWidth() const //最大宽度 { return max(label_width, value_width); } }; struct ItemWidthInfo : public CommonDisplayItem { ItemWidth item_width; ItemWidthInfo() {} ItemWidthInfo(const CommonDisplayItem& item) : CommonDisplayItem(item) {} }; std::vector m_item_widths; //任务栏窗口每个部分的宽度 std::map m_item_rects; //任务栏窗口每个部分的矩形区域 CommonDisplayItem m_clicked_item; //鼠标点击的任务栏项目 int m_min_bar_width; //最小化窗口缩小宽度后的宽度 int m_min_bar_height; //最小化窗口缩小高度后的高度(用于任务栏在屏幕左侧或右侧时) std::map> m_map_history_data; //保存各项数据历史数据的链表,链表保存按照时间顺序,越靠近头部数据越新 std::map m_history_data_count; //统计添加到历史数据链表的次数 int m_left_space{}; //最小化窗口和二级窗口窗口左侧的边距 int m_top_space{}; //最小化窗口和二级窗口窗口顶部的边距(用于任务栏在屏幕左侧或右侧时) bool m_connot_insert_to_task_bar{ false }; //如果窗口无法嵌入任务栏,则为true bool m_taskbar_on_top_or_bottom{ true }; //如果任务栏在屏幕顶部或底部,则为ture int m_error_code{}; bool m_menu_popuped{ false }; //指示当前是否有菜单处于弹出状态 CFont m_font; //字体 CDC* m_pDC{}; //窗口的DC,用来计算窗口的宽度 void CheckTaskbarOnTopOrBottom(); //检查任务栏是否在屏幕的顶部或底部,并将结果保存在m_taskbar_on_top_or_bottom中 CString GetMouseTipsInfo(); //获取鼠标提示 void AddHisToList(DisplayItem item_type, int current_usage_percent); //将当前利用率数值添加进链表 int CalculateNetspeedPercent(unsigned __int64 net_speed); //计算网速占网速占用图的最大值的百分比 //判断一个点在哪个显示项目的区域内,并保存到m_clicked_item。如果返回false,则该点不在任何一个项目的区域内,否则返回true bool CheckClickedItem(CPoint point); //绘制任务栏窗口中的一个显示项目 // drawer: 绘图类的对象 // type: 项目的类型 // rect: 绘制矩形区域 // label_width: 标签区域的宽度 // vertical: 如果为true,则标签和数值上下显示 void DrawDisplayItem(CDrawCommon& drawer, DisplayItem type, CRect rect, int label_width, bool vertical = false); //绘制任务栏窗口中的一个插件项目 // drawer: 绘图类的对象 // item: 插件显示项目的指针 // rect: 绘制矩形区域 // label_width: 标签区域的宽度 // vertical: 如果为true,则标签和数值上下显示 void DrawPluginItem(CDrawCommon& drawer, IPluginItem* item, CRect rect, int label_width, bool vertical = false); void MoveWindow(CRect rect); public: void SetTextFont(); void ApplySettings(); void CalculateWindowSize(); //计算窗口每部分的大小,及各个部分的宽度。窗口大小保存到m_window_width和m_window_height中,各部分宽度保存到m_item_widths中 void SetToolTipsTopMost(); //设置鼠标提示置顶 void UpdateToolTips(); bool GetCannotInsertToTaskBar() const { return m_connot_insert_to_task_bar; } int GetErrorCode() const { return m_error_code; } bool IsTasksbarOnTopOrBottom() { return m_taskbar_on_top_or_bottom; } static bool IsItemShow(DisplayItem item); static bool IsShowCpuMemory(); static bool IsShowNetSpeed(); CommonDisplayItem GetClickedItem() const { return m_clicked_item; } DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); virtual void OnCancel(); afx_msg void OnRButtonUp(UINT nFlags, CPoint point); //afx_msg void OnSetBackgroundColor(); //afx_msg void OnSetTextColor(); afx_msg void OnInitMenu(CMenu* pMenu); virtual BOOL PreTranslateMessage(MSG* pMsg); //afx_msg void OnSetFont(); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); afx_msg void OnTimer(UINT_PTR nIDEvent); virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); afx_msg void OnPaint(); afx_msg void OnClose(); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); protected: afx_msg LRESULT OnExitmenuloop(WPARAM wParam, LPARAM lParam); }; ================================================ FILE: TrafficMonitor/TaskBarSettingsDlg.cpp ================================================ // TaskBarSettingsDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "TaskBarSettingsDlg.h" #include "afxdialogex.h" #include "CMFCColorDialogEx.h" #include "CAutoAdaptSettingsDlg.h" #include "DisplayTextSettingDlg.h" #include "SetItemOrderDlg.h" #include "WindowsSettingHelper.h" // CTaskBarSettingsDlg 对话框 IMPLEMENT_DYNAMIC(CTaskBarSettingsDlg, CTabDlg) CTaskBarSettingsDlg::CTaskBarSettingsDlg(CWnd* pParent /*=NULL*/) : CTabDlg(IDD_TASKBAR_SETTINGS_DIALOG, pParent) { } CTaskBarSettingsDlg::~CTaskBarSettingsDlg() { } bool CTaskBarSettingsDlg::IsStyleModified() { bool modified{}; modified |= (theApp.m_taskbar_data.text_colors != m_data.text_colors); modified |= (theApp.m_taskbar_data.back_color != m_data.back_color); modified |= (theApp.m_taskbar_data.transparent_color != m_data.transparent_color); modified |= (theApp.m_taskbar_data.status_bar_color != m_data.status_bar_color); modified |= (theApp.m_taskbar_data.specify_each_item_color != m_data.specify_each_item_color); return modified && m_style_modified; } void CTaskBarSettingsDlg::DrawStaticColor() { //CCommon::FillStaticColor(m_text_color_static, m_data.text_color); //CCommon::FillStaticColor(m_back_color_static, m_data.back_color); if (m_data.specify_each_item_color) { int color_num{}; #ifdef WITHOUT_TEMPERATURE color_num = 8; #else color_num = 16; #endif int i{}; m_text_color_static.SetColorNum(color_num); for (const auto& item : m_data.text_colors) { m_text_color_static.SetFillColor(i, item.second.label); m_text_color_static.SetFillColor(i + 1, item.second.value); i += 2; } m_text_color_static.Invalidate(); } else if (!m_data.text_colors.empty()) { m_text_color_static.SetFillColor(m_data.text_colors.begin()->second.label); } m_back_color_static.SetFillColor(m_data.back_color); //m_trans_color_static.SetFillColor(m_data.transparent_color); m_status_bar_color_static.SetFillColor(m_data.status_bar_color); } void CTaskBarSettingsDlg::IniUnitCombo() { m_unit_combo.ResetContent(); m_unit_combo.AddString(CCommon::LoadText(IDS_AUTO)); if (m_data.unit_byte) { m_unit_combo.AddString(CCommon::LoadText(IDS_FIXED_AS, _T(" KB/s"))); m_unit_combo.AddString(CCommon::LoadText(IDS_FIXED_AS, _T(" MB/s"))); } else { m_unit_combo.AddString(CCommon::LoadText(IDS_FIXED_AS, _T(" Kb/s"))); m_unit_combo.AddString(CCommon::LoadText(IDS_FIXED_AS, _T(" Mb/s"))); } m_unit_combo.SetCurSel(static_cast(m_data.speed_unit)); } void CTaskBarSettingsDlg::ApplyDefaultStyle(int index) { theApp.m_taskbar_default_style.ApplyDefaultStyle(index, m_data); DrawStaticColor(); ((CButton*)GetDlgItem(IDC_SPECIFY_EACH_ITEM_COLOR_CHECK))->SetCheck(m_data.specify_each_item_color); m_background_transparent_chk.SetCheck(IsTaskbarTransparent()); } void CTaskBarSettingsDlg::ModifyDefaultStyle(int index) { theApp.m_taskbar_default_style.ModifyDefaultStyle(index, m_data); } void CTaskBarSettingsDlg::EnableControl() { bool exe_path_enable = (m_data.double_click_action == DoubleClickAction::SEPCIFIC_APP); ShowDlgCtrl(IDC_EXE_PATH_STATIC, exe_path_enable); ShowDlgCtrl(IDC_EXE_PATH_EDIT, exe_path_enable); ShowDlgCtrl(IDC_BROWSE_BUTTON, exe_path_enable); EnableDlgCtrl(IDC_AUTO_ADAPT_SETTINGS_BUTTON, m_data.auto_adapt_light_theme); EnableDlgCtrl(IDC_SHOW_DASHED_BOX, m_data.show_status_bar || m_data.show_netspeed_figure); m_status_bar_color_static.EnableWindow(m_data.show_status_bar || m_data.show_netspeed_figure); EnableDlgCtrl(IDC_CM_GRAPH_BAR_RADIO, m_data.show_status_bar || m_data.show_netspeed_figure); EnableDlgCtrl(IDC_CM_GRAPH_PLOT_RADIO, m_data.show_status_bar || m_data.show_netspeed_figure); EnableDlgCtrl(IDC_NET_SPEED_FIGURE_MAX_VALUE_EDIT, m_data.show_netspeed_figure); EnableDlgCtrl(IDC_NET_SPEED_FIGURE_MAX_VALUE_UNIT_COMBO, m_data.show_netspeed_figure); //EnableDlgCtrl(IDC_TASKBAR_WND_SNAP_CHECK, theApp.m_win_version.IsWindows11OrLater() && !m_data.tbar_wnd_on_left); } void CTaskBarSettingsDlg::SetTaskabrTransparent(bool transparent) { CTaskbarDefaultStyle::SetTaskabrTransparent(transparent, m_data); } bool CTaskBarSettingsDlg::IsTaskbarTransparent() { return CTaskbarDefaultStyle::IsTaskbarTransparent(m_data); } void CTaskBarSettingsDlg::SetControlMouseWheelEnable(bool enable) { m_unit_combo.SetMouseWheelEnable(enable); m_double_click_combo.SetMouseWheelEnable(enable); m_digit_number_combo.SetMouseWheelEnable(enable); m_font_size_edit.SetMouseWheelEnable(enable); m_memory_display_combo.SetMouseWheelEnable(enable); m_item_space_edit.SetMouseWheelEnable(enable); m_net_speed_figure_max_val_edit.SetMouseWheelEnable(enable); m_net_speed_figure_max_val_unit_combo.SetMouseWheelEnable(enable); } void CTaskBarSettingsDlg::DoDataExchange(CDataExchange* pDX) { DDX_Control(pDX, IDC_TEXT_COLOR_STATIC1, m_text_color_static); DDX_Control(pDX, IDC_TEXT_COLOR_STATIC2, m_back_color_static); DDX_Control(pDX, IDC_TEXT_COLOR_STATIC3, m_status_bar_color_static); CTabDlg::DoDataExchange(pDX); DDX_Control(pDX, IDC_UNIT_COMBO, m_unit_combo); DDX_Control(pDX, IDC_HIDE_UNIT_CHECK, m_hide_unit_chk); DDX_Control(pDX, IDC_FONT_SIZE_EDIT1, m_font_size_edit); DDX_Control(pDX, IDC_DOUBLE_CLICK_COMBO, m_double_click_combo); DDX_Control(pDX, IDC_DIGIT_NUMBER_COMBO, m_digit_number_combo); //DDX_Control(pDX, IDC_TRANSPARENT_COLOR_STATIC, m_trans_color_static); DDX_Control(pDX, IDC_BACKGROUND_TRANSPARENT_CHECK, m_background_transparent_chk); DDX_Control(pDX, IDC_AUTO_ADAPT_LIGHT_THEME_CHECK, m_atuo_adapt_light_theme_chk); DDX_Control(pDX, IDC_AUTO_SET_BACK_COLOR_CHECK, m_auto_set_back_color_chk); DDX_Control(pDX, IDC_MEMORY_DISPLAY_COMBO, m_memory_display_combo); DDX_Control(pDX, IDC_ITEM_SPACE_EDIT, m_item_space_edit); DDX_Control(pDX, IDC_NET_SPEED_FIGURE_MAX_VALUE_EDIT, m_net_speed_figure_max_val_edit); DDX_Control(pDX, IDC_NET_SPEED_FIGURE_MAX_VALUE_UNIT_COMBO, m_net_speed_figure_max_val_unit_combo); } BEGIN_MESSAGE_MAP(CTaskBarSettingsDlg, CTabDlg) ON_BN_CLICKED(IDC_SET_FONT_BUTTON1, &CTaskBarSettingsDlg::OnBnClickedSetFontButton1) ON_BN_CLICKED(IDC_TASKBAR_WND_ON_LEFT_CHECK, &CTaskBarSettingsDlg::OnBnClickedTaskbarWndOnLeftCheck) ON_BN_CLICKED(IDC_SPEED_SHORT_MODE_CHECK, &CTaskBarSettingsDlg::OnBnClickedSpeedShortModeCheck) ON_CBN_SELCHANGE(IDC_UNIT_COMBO, &CTaskBarSettingsDlg::OnCbnSelchangeUnitCombo) ON_BN_CLICKED(IDC_HIDE_UNIT_CHECK, &CTaskBarSettingsDlg::OnBnClickedHideUnitCheck) ON_BN_CLICKED(IDC_VALUE_RIGHT_ALIGN_CHECK, &CTaskBarSettingsDlg::OnBnClickedValueRightAlignCheck) ON_BN_CLICKED(IDC_HIDE_PERCENTAGE_CHECK, &CTaskBarSettingsDlg::OnBnClickedHidePercentageCheck) ON_MESSAGE(WM_STATIC_CLICKED, &CTaskBarSettingsDlg::OnStaticClicked) ON_BN_CLICKED(IDC_SPECIFY_EACH_ITEM_COLOR_CHECK, &CTaskBarSettingsDlg::OnBnClickedSpecifyEachItemColorCheck) ON_CBN_SELCHANGE(IDC_DOUBLE_CLICK_COMBO, &CTaskBarSettingsDlg::OnCbnSelchangeDoubleClickCombo) ON_BN_CLICKED(IDC_HORIZONTAL_ARRANGE_CHECK, &CTaskBarSettingsDlg::OnBnClickedHorizontalArrangeCheck) ON_BN_CLICKED(IDC_SHOW_STATUS_BAR_CHECK, &CTaskBarSettingsDlg::OnBnClickedShowStatusBarCheck) ON_BN_CLICKED(IDC_SEPARATE_VALUE_UNIT_CHECK, &CTaskBarSettingsDlg::OnBnClickedSeparateValueUnitCheck) ON_BN_CLICKED(IDC_UNIT_BYTE_RADIO, &CTaskBarSettingsDlg::OnBnClickedUnitByteRadio) ON_BN_CLICKED(IDC_UNIT_BIT_RADIO, &CTaskBarSettingsDlg::OnBnClickedUnitBitRadio) ON_BN_CLICKED(IDC_SHOW_TOOL_TIP_CHK, &CTaskBarSettingsDlg::OnBnClickedShowToolTipChk) ON_BN_CLICKED(IDC_DEFAULT_STYLE_BUTTON, &CTaskBarSettingsDlg::OnBnClickedDefaultStyleButton) ON_WM_DESTROY() ON_BN_CLICKED(IDC_BROWSE_BUTTON, &CTaskBarSettingsDlg::OnBnClickedBrowseButton) ON_BN_CLICKED(IDC_CM_GRAPH_BAR_RADIO, &CTaskBarSettingsDlg::OnBnClickedCMGraphBarRadio) ON_BN_CLICKED(IDC_CM_GRAPH_PLOT_RADIO, &CTaskBarSettingsDlg::OnBnClickedCMGraphPLOTRadio) ON_BN_CLICKED(IDC_BACKGROUND_TRANSPARENT_CHECK, &CTaskBarSettingsDlg::OnBnClickedBackgroundTransparentCheck) ON_BN_CLICKED(IDC_AUTO_ADAPT_SETTINGS_BUTTON, &CTaskBarSettingsDlg::OnBnClickedAutoAdaptSettingsButton) ON_BN_CLICKED(IDC_AUTO_ADAPT_LIGHT_THEME_CHECK, &CTaskBarSettingsDlg::OnBnClickedAutoAdaptLightThemeCheck) ON_BN_CLICKED(IDC_AUTO_SET_BACK_COLOR_CHECK, &CTaskBarSettingsDlg::OnBnClickedAutoSetBackColorCheck) ON_BN_CLICKED(IDC_DISPLAY_TEXT_SETTING_BUTTON, &CTaskBarSettingsDlg::OnBnClickedDisplayTextSettingButton) ON_CBN_SELCHANGE(IDC_MEMORY_DISPLAY_COMBO, &CTaskBarSettingsDlg::OnCbnSelchangeMemoryDisplayCombo) ON_BN_CLICKED(IDC_SHOW_DASHED_BOX, &CTaskBarSettingsDlg::OnBnClickedShowDashedBox) ON_BN_CLICKED(IDC_SET_ORDER_BUTTON, &CTaskBarSettingsDlg::OnBnClickedSetOrderButton) ON_BN_CLICKED(IDC_TASKBAR_WND_SNAP_CHECK, &CTaskBarSettingsDlg::OnBnClickedTaskbarWndSnapCheck) ON_EN_CHANGE(IDC_ITEM_SPACE_EDIT, &CTaskBarSettingsDlg::OnEnChangeItemSpaceEdit) ON_BN_CLICKED(IDC_SHOW_NET_SPEED_FIGURE_CHECK, &CTaskBarSettingsDlg::OnBnClickedShowNetSpeedFigureCheck) ON_CBN_SELCHANGE(IDC_NET_SPEED_FIGURE_MAX_VALUE_UNIT_COMBO, &CTaskBarSettingsDlg::OnCbnSelchangeNetSpeedFigureMaxValueUnitCombo) ON_EN_CHANGE(IDC_NET_SPEED_FIGURE_MAX_VALUE_EDIT, &CTaskBarSettingsDlg::OnEnChangeNetSpeedFigureMaxValueEdit) END_MESSAGE_MAP() // CTaskBarSettingsDlg 消息处理程序 BOOL CTaskBarSettingsDlg::OnInitDialog() { CTabDlg::OnInitDialog(); // TODO: 在此添加额外的初始化 theApp.m_taskbar_default_style.LoadConfig(); //初始化各控件状态 SetDlgItemText(IDC_FONT_NAME_EDIT1, m_data.font.name); //wchar_t buff[16]; //swprintf_s(buff, L"%d", m_data.font_size); //SetDlgItemText(IDC_FONT_SIZE_EDIT1, buff); m_font_size_edit.SetRange(5, 72); m_font_size_edit.SetValue(m_data.font.size); //SetDlgItemText(IDC_UPLOAD_EDIT1, m_data.disp_str.Get(TDI_UP).c_str()); //SetDlgItemText(IDC_DOWNLOAD_EDIT1, m_data.disp_str.Get(TDI_DOWN).c_str()); //SetDlgItemText(IDC_CPU_EDIT1, m_data.disp_str.Get(TDI_CPU).c_str()); //SetDlgItemText(IDC_MEMORY_EDIT1, m_data.disp_str.Get(TDI_MEMORY).c_str()); //((CButton*)GetDlgItem(IDC_SWITCH_UP_DOWN_CHECK1))->SetCheck(m_data.swap_up_down); ((CButton*)GetDlgItem(IDC_TASKBAR_WND_ON_LEFT_CHECK))->SetCheck(m_data.tbar_wnd_on_left); ((CButton*)GetDlgItem(IDC_SPEED_SHORT_MODE_CHECK))->SetCheck(m_data.speed_short_mode); ((CButton*)GetDlgItem(IDC_VALUE_RIGHT_ALIGN_CHECK))->SetCheck(m_data.value_right_align); ((CButton*)GetDlgItem(IDC_HORIZONTAL_ARRANGE_CHECK))->SetCheck(m_data.horizontal_arrange); ((CButton*)GetDlgItem(IDC_SHOW_STATUS_BAR_CHECK))->SetCheck(m_data.show_status_bar); ((CButton*)GetDlgItem(IDC_SEPARATE_VALUE_UNIT_CHECK))->SetCheck(m_data.separate_value_unit_with_space); ((CButton*)GetDlgItem(IDC_SHOW_TOOL_TIP_CHK))->SetCheck(m_data.show_tool_tip); EnableDlgCtrl(IDC_TASKBAR_WND_SNAP_CHECK, theApp.m_win_version.IsWindows11OrLater()); CheckDlgButton(IDC_TASKBAR_WND_SNAP_CHECK, m_data.tbar_wnd_snap); m_text_color_static.SetLinkCursor(); m_back_color_static.SetLinkCursor(); //m_trans_color_static.SetLinkCursor(); m_status_bar_color_static.SetLinkCursor(); DrawStaticColor(); #ifdef COMPILE_FOR_WINXP m_background_transparent_chk.EnableWindow(FALSE); #endif // COMPILE_FOR_WINXP if (theApp.m_win_version.IsWindows7()) m_background_transparent_chk.EnableWindow(FALSE); m_toolTip.Create(this); m_toolTip.SetMaxTipWidth(theApp.DPI(300)); m_toolTip.AddTool(GetDlgItem(IDC_SPEED_SHORT_MODE_CHECK), CCommon::LoadText(IDS_SPEED_SHORT_MODE_TIP)); m_toolTip.AddTool(&m_atuo_adapt_light_theme_chk, CCommon::LoadText(IDS_AUTO_ADAPT_TIP_INFO)); m_toolTip.AddTool(GetDlgItem(IDC_SHOW_STATUS_BAR_CHECK), CCommon::LoadText(IDS_SHOW_RESOURCE_USAGE_GRAPH_TIP)); m_toolTip.AddTool(GetDlgItem(IDC_SHOW_NET_SPEED_FIGURE_CHECK), CCommon::LoadText(IDS_SHOW_NET_SPEED_GRAPH_TIP)); if (m_data.unit_byte) ((CButton*)GetDlgItem(IDC_UNIT_BYTE_RADIO))->SetCheck(TRUE); else ((CButton*)GetDlgItem(IDC_UNIT_BIT_RADIO))->SetCheck(TRUE); IniUnitCombo(); m_hide_unit_chk.SetCheck(m_data.hide_unit); if (m_data.speed_unit == SpeedUnit::AUTO) { m_hide_unit_chk.SetCheck(FALSE); m_data.hide_unit = false; m_hide_unit_chk.EnableWindow(FALSE); } ((CButton*)GetDlgItem(IDC_HIDE_PERCENTAGE_CHECK))->SetCheck(m_data.hide_percent); ((CButton*)GetDlgItem(IDC_SPECIFY_EACH_ITEM_COLOR_CHECK))->SetCheck(m_data.specify_each_item_color); m_background_transparent_chk.SetCheck(IsTaskbarTransparent()); m_atuo_adapt_light_theme_chk.SetCheck(m_data.auto_adapt_light_theme); m_auto_set_back_color_chk.SetCheck(m_data.auto_set_background_color); m_auto_set_back_color_chk.EnableWindow(theApp.m_win_version.IsWindows8OrLater()); if (theApp.m_win_version.GetMajorVersion() < 10) { m_data.auto_adapt_light_theme = false; m_atuo_adapt_light_theme_chk.EnableWindow(FALSE); } m_double_click_combo.AddString(CCommon::LoadText(IDS_OPEN_CONNECTION_DETIAL)); m_double_click_combo.AddString(CCommon::LoadText(IDS_OPEN_HISTORICAL_TRAFFIC)); m_double_click_combo.AddString(CCommon::LoadText(IDS_SHOW_HIDE_CPU_MEMORY)); m_double_click_combo.AddString(CCommon::LoadText(IDS_OPEN_OPTION_SETTINGS)); m_double_click_combo.AddString(CCommon::LoadText(IDS_OPEN_TASK_MANAGER)); m_double_click_combo.AddString(CCommon::LoadText(IDS_SPECIFIC_APP)); m_double_click_combo.AddString(CCommon::LoadText(IDS_NONE)); m_double_click_combo.SetCurSel(static_cast(m_data.double_click_action)); m_digit_number_combo.AddString(_T("3")); m_digit_number_combo.AddString(_T("4")); m_digit_number_combo.AddString(_T("5")); m_digit_number_combo.AddString(_T("6")); m_digit_number_combo.AddString(_T("7")); m_digit_number_combo.SetCurSel(m_data.digits_number - 3); SetDlgItemText(IDC_EXE_PATH_EDIT, m_data.double_click_exe.c_str()); EnableControl(); //m_default_style_menu.LoadMenu(IDR_TASKBAR_STYLE_MENU); if (m_data.cm_graph_type) CheckDlgButton(IDC_CM_GRAPH_PLOT_RADIO, TRUE); else CheckDlgButton(IDC_CM_GRAPH_BAR_RADIO, TRUE); CheckDlgButton(IDC_SHOW_DASHED_BOX, m_data.show_graph_dashed_box); m_item_space_edit.SetRange(0, 32); m_item_space_edit.SetValue(m_data.item_space); //初始化内存显示方式下拉列表 m_memory_display_combo.AddString(CCommon::LoadText(IDS_USAGE_PERCENTAGE)); m_memory_display_combo.AddString(CCommon::LoadText(IDS_MEMORY_USED)); m_memory_display_combo.AddString(CCommon::LoadText(IDS_MEMORY_AVAILABLE)); m_memory_display_combo.SetCurSel(static_cast(m_data.memory_display)); CheckDlgButton(IDC_SHOW_NET_SPEED_FIGURE_CHECK, m_data.show_netspeed_figure); m_net_speed_figure_max_val_edit.SetRange(1, 1024); m_net_speed_figure_max_val_edit.SetValue(m_data.netspeed_figure_max_value); m_net_speed_figure_max_val_unit_combo.AddString(_T("KB")); m_net_speed_figure_max_val_unit_combo.AddString(_T("MB")); m_net_speed_figure_max_val_unit_combo.SetCurSel(m_data.netspeed_figure_max_value_unit); ((CButton*)GetDlgItem(IDC_SET_ORDER_BUTTON))->SetIcon(theApp.GetMenuIcon(IDI_ITEM)); //初始化“预设方案”菜单 m_default_style_menu.CreatePopupMenu(); m_modify_default_style_menu.CreatePopupMenu(); for (int i{ 0 }; i < TASKBAR_DEFAULT_STYLE_NUM; i++) { CString item_name; item_name.Format(_T("%s %d"), CCommon::LoadText(IDS_PRESET).GetString(), i + 1); m_default_style_menu.AppendMenu(MF_STRING | MF_ENABLED, ID_DEFAULT_STYLE1 + i, item_name); m_modify_default_style_menu.AppendMenu(MF_STRING | MF_ENABLED, ID_MODIFY_DEFAULT_STYLE1 + i, item_name); } m_default_style_menu.AppendMenu(MF_SEPARATOR); m_default_style_menu.AppendMenu(MF_POPUP | MF_STRING, (UINT)m_modify_default_style_menu.m_hMenu, CCommon::LoadText(IDS_MODIFY_PRESET)); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CTaskBarSettingsDlg::OnBnClickedSetFontButton1() { // TODO: 在此添加控件通知处理程序代码 LOGFONT lf{}; lf.lfHeight = FontSizeToLfHeight(m_data.font.size); lf.lfWeight = (m_data.font.bold ? FW_BOLD : FW_NORMAL); lf.lfItalic = m_data.font.italic; lf.lfUnderline = m_data.font.underline; lf.lfStrikeOut = m_data.font.strike_out; lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS; //wcsncpy_s(lf.lfFaceName, m_data.font.name.GetString(), 32); CCommon::WStringCopy(lf.lfFaceName, 32, m_data.font.name.GetString()); CCommon::NormalizeFont(lf); CFontDialog fontDlg(&lf); //构造字体对话框,初始选择字体为之前字体 if (IDOK == fontDlg.DoModal()) // 显示字体对话框 { //获取字体信息 m_data.font.name = fontDlg.GetFaceName(); m_data.font.size = fontDlg.GetSize() / 10; m_data.font.bold = (fontDlg.IsBold() != FALSE); m_data.font.italic = (fontDlg.IsItalic() != FALSE); m_data.font.underline = (fontDlg.IsUnderline() != FALSE); m_data.font.strike_out = (fontDlg.IsStrikeOut() != FALSE); //将字体信息显示出来 SetDlgItemText(IDC_FONT_NAME_EDIT1, m_data.font.name); wchar_t buff[16]; swprintf_s(buff, L"%d", m_data.font.size); SetDlgItemText(IDC_FONT_SIZE_EDIT1, buff); } } void CTaskBarSettingsDlg::OnBnClickedTaskbarWndOnLeftCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.tbar_wnd_on_left = (((CButton*)GetDlgItem(IDC_TASKBAR_WND_ON_LEFT_CHECK))->GetCheck() != 0); EnableControl(); } void CTaskBarSettingsDlg::OnBnClickedSpeedShortModeCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.speed_short_mode = (((CButton*)GetDlgItem(IDC_SPEED_SHORT_MODE_CHECK))->GetCheck() != 0); } BOOL CTaskBarSettingsDlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 if (pMsg->message == WM_MOUSEMOVE) m_toolTip.RelayEvent(pMsg); return CTabDlg::PreTranslateMessage(pMsg); } void CTaskBarSettingsDlg::OnCbnSelchangeUnitCombo() { // TODO: 在此添加控件通知处理程序代码 m_data.speed_unit = static_cast(m_unit_combo.GetCurSel()); if (m_data.speed_unit == SpeedUnit::AUTO) { m_hide_unit_chk.SetCheck(FALSE); m_data.hide_unit = false; m_hide_unit_chk.EnableWindow(FALSE); } else { m_hide_unit_chk.EnableWindow(TRUE); } } void CTaskBarSettingsDlg::OnBnClickedHideUnitCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.hide_unit = (m_hide_unit_chk.GetCheck() != 0); } void CTaskBarSettingsDlg::OnOK() { // TODO: 在此添加专用代码和/或调用基类 //获取字体设置 int font_size; font_size = m_font_size_edit.GetValue(); if (font_size > MAX_FONT_SIZE || font_size < MIN_FONT_SIZE) { CString info; info.Format(CCommon::LoadText(IDS_FONT_SIZE_WARNING), MIN_FONT_SIZE, MAX_FONT_SIZE); MessageBox(info, NULL, MB_OK | MB_ICONWARNING); } else { m_data.font.size = font_size; } GetDlgItemText(IDC_FONT_NAME_EDIT1, m_data.font.name); //获取数据位数的设置 m_data.digits_number = m_digit_number_combo.GetCurSel() + 3; bool is_taskbar_transparent_checked = (m_background_transparent_chk.GetCheck() != 0); SetTaskabrTransparent(is_taskbar_transparent_checked); SaveColorSettingToDefaultStyle(); CTabDlg::OnOK(); } void CTaskBarSettingsDlg::SaveColorSettingToDefaultStyle() { //如果开启了自动适应Windows10深色/浅色模式功能时,自动将当前配置保存到对应预设 if (theApp.m_taskbar_data.auto_save_taskbar_color_settings_to_preset && m_data.auto_adapt_light_theme && IsStyleModified()) { int default_style_saved{ CWindowsSettingHelper::IsWindows10LightTheme() ? m_data.light_default_style : m_data.dark_default_style }; ModifyDefaultStyle(default_style_saved); } } void CTaskBarSettingsDlg::OnBnClickedValueRightAlignCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.value_right_align = (((CButton*)GetDlgItem(IDC_VALUE_RIGHT_ALIGN_CHECK))->GetCheck() != 0); } void CTaskBarSettingsDlg::OnBnClickedHidePercentageCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.hide_percent = (((CButton*)GetDlgItem(IDC_HIDE_PERCENTAGE_CHECK))->GetCheck() != 0); } afx_msg LRESULT CTaskBarSettingsDlg::OnStaticClicked(WPARAM wParam, LPARAM lParam) { switch (::GetDlgCtrlID(((CWnd*)wParam)->m_hWnd)) { case IDC_TEXT_COLOR_STATIC1: //点击“文本颜色”时 { //设置文本颜色 if (m_data.specify_each_item_color) { CTaskbarColorDlg colorDlg(m_data.text_colors); if (colorDlg.DoModal() == IDOK) { m_data.text_colors = colorDlg.GetColors(); DrawStaticColor(); m_style_modified = true; } } else if (!m_data.text_colors.empty()) { CMFCColorDialogEx colorDlg(m_data.text_colors.begin()->second.label, 0, this); if (colorDlg.DoModal() == IDOK) { m_data.text_colors.begin()->second.label = colorDlg.GetColor(); if (m_data.back_color == m_data.text_colors.begin()->second.label) MessageBox(CCommon::LoadText(IDS_SAME_TEXT_BACK_COLOR_WARNING), NULL, MB_ICONWARNING); DrawStaticColor(); m_style_modified = true; } } break; } case IDC_TEXT_COLOR_STATIC2: //点击“背景颜色”时 { //设置背景颜色 CMFCColorDialogEx colorDlg(m_data.back_color, 0, this); if (colorDlg.DoModal() == IDOK) { bool background_transparent = IsTaskbarTransparent(); m_data.back_color = colorDlg.GetColor(); if (m_data.back_color == m_data.text_colors.begin()->second.label) MessageBox(CCommon::LoadText(IDS_SAME_BACK_TEXT_COLOR_WARNING), NULL, MB_ICONWARNING); if (background_transparent) { CCommon::TransparentColorConvert(m_data.back_color); //如果当前设置了背景透明,则更改了背景色后同时将透明色设置成和背景色一样的颜色,以保持背景透明 m_data.transparent_color = m_data.back_color; } DrawStaticColor(); m_style_modified = true; } break; } //case IDC_TRANSPARENT_COLOR_STATIC: //点击“透明色”时 //{ // CMFCColorDialogEx colorDlg(m_data.transparent_color, 0, this); // if (colorDlg.DoModal() == IDOK) // { // m_data.transparent_color = colorDlg.GetColor(); // DrawStaticColor(); // } // break; //} case IDC_TEXT_COLOR_STATIC3: //点击“状态条颜色”时 { CMFCColorDialogEx colorDlg(m_data.status_bar_color, 0, this); if (colorDlg.DoModal() == IDOK) { m_data.status_bar_color = colorDlg.GetColor(); DrawStaticColor(); m_style_modified = true; } break; } default: break; } return 0; } void CTaskBarSettingsDlg::OnBnClickedSpecifyEachItemColorCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.specify_each_item_color = (((CButton*)GetDlgItem(IDC_SPECIFY_EACH_ITEM_COLOR_CHECK))->GetCheck() != 0); DrawStaticColor(); m_style_modified = true; } void CTaskBarSettingsDlg::OnCbnSelchangeDoubleClickCombo() { // TODO: 在此添加控件通知处理程序代码 m_data.double_click_action = static_cast(m_double_click_combo.GetCurSel()); EnableControl(); } void CTaskBarSettingsDlg::OnBnClickedHorizontalArrangeCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.horizontal_arrange = (((CButton*)GetDlgItem(IDC_HORIZONTAL_ARRANGE_CHECK))->GetCheck() != 0); } void CTaskBarSettingsDlg::OnBnClickedShowStatusBarCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.show_status_bar = (((CButton*)GetDlgItem(IDC_SHOW_STATUS_BAR_CHECK))->GetCheck() != 0); EnableControl(); } void CTaskBarSettingsDlg::OnBnClickedSeparateValueUnitCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.separate_value_unit_with_space = (((CButton*)GetDlgItem(IDC_SEPARATE_VALUE_UNIT_CHECK))->GetCheck() != 0); } void CTaskBarSettingsDlg::OnBnClickedUnitByteRadio() { // TODO: 在此添加控件通知处理程序代码 m_data.unit_byte = true; IniUnitCombo(); } void CTaskBarSettingsDlg::OnBnClickedUnitBitRadio() { // TODO: 在此添加控件通知处理程序代码 m_data.unit_byte = false; IniUnitCombo(); } void CTaskBarSettingsDlg::OnBnClickedShowToolTipChk() { // TODO: 在此添加控件通知处理程序代码 m_data.show_tool_tip = (((CButton*)GetDlgItem(IDC_SHOW_TOOL_TIP_CHK))->GetCheck() != 0); } void CTaskBarSettingsDlg::OnBnClickedDefaultStyleButton() { // TODO: 在此添加控件通知处理程序代码 CWnd* pBtn = GetDlgItem(IDC_DEFAULT_STYLE_BUTTON); CPoint point; if (pBtn != nullptr) { CRect rect; pBtn->GetWindowRect(rect); point.x = rect.left; point.y = rect.bottom; m_default_style_menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this); } } void CTaskBarSettingsDlg::OnDestroy() { CTabDlg::OnDestroy(); // TODO: 在此处添加消息处理程序代码 theApp.m_taskbar_default_style.SaveConfig(); } void CTaskBarSettingsDlg::OnBnClickedBrowseButton() { // TODO: 在此添加控件通知处理程序代码 CString szFilter = CCommon::LoadText(IDS_EXE_FILTER); CFileDialog fileDlg(TRUE, NULL, NULL, 0, szFilter, this); if (IDOK == fileDlg.DoModal()) { m_data.double_click_exe = fileDlg.GetPathName(); SetDlgItemText(IDC_EXE_PATH_EDIT, m_data.double_click_exe.c_str()); } } void CTaskBarSettingsDlg::OnBnClickedCMGraphPLOTRadio() { m_data.cm_graph_type = true; } void CTaskBarSettingsDlg::OnBnClickedCMGraphBarRadio() { m_data.cm_graph_type = false; } void CTaskBarSettingsDlg::OnBnClickedBackgroundTransparentCheck() { // TODO: 在此添加控件通知处理程序代码 bool checked = (m_background_transparent_chk.GetCheck() != 0); SetTaskabrTransparent(checked); m_style_modified = true; } void CTaskBarSettingsDlg::OnBnClickedAutoAdaptSettingsButton() { // TODO: 在此添加控件通知处理程序代码 CAutoAdaptSettingsDlg dlg(m_data); dlg.DoModal(); } void CTaskBarSettingsDlg::OnBnClickedAutoAdaptLightThemeCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.auto_adapt_light_theme = (m_atuo_adapt_light_theme_chk.GetCheck() != 0); EnableControl(); } void CTaskBarSettingsDlg::OnBnClickedAutoSetBackColorCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.auto_set_background_color = (m_auto_set_back_color_chk.GetCheck() != 0); } void CTaskBarSettingsDlg::OnBnClickedDisplayTextSettingButton() { // TODO: 在此添加控件通知处理程序代码 CDisplayTextSettingDlg dlg(m_data.disp_str); dlg.DoModal(); } void CTaskBarSettingsDlg::OnCbnSelchangeMemoryDisplayCombo() { // TODO: 在此添加控件通知处理程序代码 m_data.memory_display = static_cast(m_memory_display_combo.GetCurSel()); } void CTaskBarSettingsDlg::OnBnClickedShowDashedBox() { // TODO: 在此添加控件通知处理程序代码 m_data.show_graph_dashed_box = (IsDlgButtonChecked(IDC_SHOW_DASHED_BOX) != 0); } void CTaskBarSettingsDlg::OnBnClickedSetOrderButton() { // TODO: 在此添加控件通知处理程序代码 CSetItemOrderDlg dlg; dlg.SetItemOrder(m_data.item_order.GetItemOrderConst()); dlg.SetDisplayItem(m_data.m_tbar_display_item); dlg.SetPluginDisplayItem(m_data.plugin_display_item); if (dlg.DoModal() == IDOK) { m_data.item_order.SetOrder(dlg.GetItemOrder()); m_data.m_tbar_display_item = dlg.GetDisplayItem(); m_data.plugin_display_item = dlg.GetPluginDisplayItem(); } } void CTaskBarSettingsDlg::OnBnClickedTaskbarWndSnapCheck() { // TODO: 在此添加控件通知处理程序代码 m_data.tbar_wnd_snap = (IsDlgButtonChecked(IDC_TASKBAR_WND_SNAP_CHECK) != 0); } void CTaskBarSettingsDlg::OnEnChangeItemSpaceEdit() { // TODO: 如果该控件是 RICHEDIT 控件,它将不 // 发送此通知,除非重写 CTabDlg::OnInitDialog() // 函数并调用 CRichEditCtrl().SetEventMask(), // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // TODO: 在此添加控件通知处理程序代码 m_data.item_space = m_item_space_edit.GetValue(); m_data.ValidItemSpace(); } BOOL CTaskBarSettingsDlg::OnCommand(WPARAM wParam, LPARAM lParam) { // TODO: 在此添加专用代码和/或调用基类 UINT cmd = LOWORD(wParam); if (cmd >= ID_DEFAULT_STYLE1 && cmd < ID_DEFAULT_STYLE_MAX) { int default_style = cmd - ID_DEFAULT_STYLE1; ApplyDefaultStyle(default_style); } if (cmd >= ID_MODIFY_DEFAULT_STYLE1 && cmd < ID_MODIFY_DEFAULT_STYLE_MAX) { int default_style = cmd - ID_MODIFY_DEFAULT_STYLE1; if (MessageBox(CCommon::LoadTextFormat(IDS_SAVE_DEFAULT_STYLE_INQUIRY, { default_style + 1 }), NULL, MB_ICONQUESTION | MB_YESNO) == IDYES) { ModifyDefaultStyle(default_style); } } return CTabDlg::OnCommand(wParam, lParam); } void CTaskBarSettingsDlg::OnBnClickedShowNetSpeedFigureCheck() { m_data.show_netspeed_figure = (IsDlgButtonChecked(IDC_SHOW_NET_SPEED_FIGURE_CHECK) != 0); EnableControl(); } void CTaskBarSettingsDlg::OnCbnSelchangeNetSpeedFigureMaxValueUnitCombo() { m_data.netspeed_figure_max_value_unit = m_net_speed_figure_max_val_unit_combo.GetCurSel(); } void CTaskBarSettingsDlg::OnEnChangeNetSpeedFigureMaxValueEdit() { m_data.netspeed_figure_max_value = m_net_speed_figure_max_val_edit.GetValue(); } ================================================ FILE: TrafficMonitor/TaskBarSettingsDlg.h ================================================ #pragma once #include "ColorStatic.h" #include "afxwin.h" #include "SpinEdit.h" #include "TabDlg.h" #include "TaskbarColorDlg.h" #include "ComboBox2.h" // CTaskBarSettingsDlg 对话框 class CTaskBarSettingsDlg : public CTabDlg { DECLARE_DYNAMIC(CTaskBarSettingsDlg) public: CTaskBarSettingsDlg(CWnd* pParent = NULL); // 标准构造函数 virtual ~CTaskBarSettingsDlg(); bool IsStyleModified(); //如果开启了自动适应Windows10深色/浅色模式功能时,将当前配置保存到对应预设 void SaveColorSettingToDefaultStyle(); //选项设置数据 TaskBarSettingData m_data; CWinVersionHelper m_win_version; //当前Windows的版本 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_TASKBAR_SETTINGS_DIALOG }; #endif protected: //控件变量 CColorStatic m_text_color_static; CColorStatic m_back_color_static; CColorStatic m_trans_color_static; CColorStatic m_status_bar_color_static; CToolTipCtrl m_toolTip; CComboBox2 m_unit_combo; CButton m_hide_unit_chk; CSpinEdit m_font_size_edit; CComboBox2 m_double_click_combo; CComboBox2 m_digit_number_combo; CMenu m_default_style_menu; CMenu m_modify_default_style_menu; CButton m_background_transparent_chk; CButton m_atuo_adapt_light_theme_chk; CButton m_auto_set_back_color_chk; CComboBox2 m_memory_display_combo; CSpinEdit m_item_space_edit; CSpinEdit m_net_speed_figure_max_val_edit; CComboBox2 m_net_speed_figure_max_val_unit_combo; bool m_style_modified{}; protected: void DrawStaticColor(); void IniUnitCombo(); void ApplyDefaultStyle(int index); //应用一个预设方案 public: void ModifyDefaultStyle(int index); //将当前颜色设置保存到一个预设方案 protected: void EnableControl(); void SetTaskabrTransparent(bool transparent); bool IsTaskbarTransparent(); virtual void SetControlMouseWheelEnable(bool enable) override; virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnBnClickedSetFontButton1(); afx_msg void OnBnClickedTaskbarWndOnLeftCheck(); afx_msg void OnBnClickedSpeedShortModeCheck(); virtual BOOL PreTranslateMessage(MSG* pMsg); afx_msg void OnCbnSelchangeUnitCombo(); afx_msg void OnBnClickedHideUnitCheck(); virtual void OnOK(); afx_msg void OnBnClickedValueRightAlignCheck(); afx_msg void OnBnClickedHidePercentageCheck(); protected: afx_msg LRESULT OnStaticClicked(WPARAM wParam, LPARAM lParam); public: afx_msg void OnBnClickedSpecifyEachItemColorCheck(); afx_msg void OnCbnSelchangeDoubleClickCombo(); afx_msg void OnBnClickedHorizontalArrangeCheck(); afx_msg void OnBnClickedShowStatusBarCheck(); afx_msg void OnBnClickedSeparateValueUnitCheck(); afx_msg void OnBnClickedUnitByteRadio(); afx_msg void OnBnClickedUnitBitRadio(); afx_msg void OnBnClickedShowToolTipChk(); afx_msg void OnBnClickedDefaultStyleButton(); afx_msg void OnDestroy(); afx_msg void OnBnClickedBrowseButton(); afx_msg void OnBnClickedCMGraphBarRadio(); afx_msg void OnBnClickedCMGraphPLOTRadio(); afx_msg void OnBnClickedBackgroundTransparentCheck(); afx_msg void OnBnClickedAutoAdaptSettingsButton(); afx_msg void OnBnClickedAutoAdaptLightThemeCheck(); afx_msg void OnBnClickedAutoSetBackColorCheck(); afx_msg void OnBnClickedDisplayTextSettingButton(); afx_msg void OnCbnSelchangeMemoryDisplayCombo(); afx_msg void OnBnClickedShowDashedBox(); afx_msg void OnBnClickedSetOrderButton(); afx_msg void OnBnClickedTaskbarWndSnapCheck(); afx_msg void OnEnChangeItemSpaceEdit(); virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); afx_msg void OnBnClickedShowNetSpeedFigureCheck(); afx_msg void OnCbnSelchangeNetSpeedFigureMaxValueUnitCombo(); afx_msg void OnEnChangeNetSpeedFigureMaxValueEdit(); }; ================================================ FILE: TrafficMonitor/TaskbarColorDlg.cpp ================================================ // TaskbarColorDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "TaskbarColorDlg.h" #include "afxdialogex.h" #include "CMFCColorDialogEx.h" // CTaskbarColorDlg 对话框 IMPLEMENT_DYNAMIC(CTaskbarColorDlg, CBaseDialog) CTaskbarColorDlg::CTaskbarColorDlg(const std::map& colors, CWnd* pParent /*=NULL*/) : CBaseDialog(IDD_TASKBAR_COLOR_DIALOG, pParent), m_colors(colors) { } CTaskbarColorDlg::~CTaskbarColorDlg() { } CString CTaskbarColorDlg::GetDialogName() const { return _T("TaskbarColorDlg"); } void CTaskbarColorDlg::DoDataExchange(CDataExchange* pDX) { CBaseDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST1, m_list_ctrl); } BEGIN_MESSAGE_MAP(CTaskbarColorDlg, CBaseDialog) ON_NOTIFY(NM_DBLCLK, IDC_LIST1, &CTaskbarColorDlg::OnNMDblclkList1) END_MESSAGE_MAP() // CTaskbarColorDlg 消息处理程序 BOOL CTaskbarColorDlg::OnInitDialog() { CBaseDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 SetIcon(theApp.GetMenuIcon(IDI_TASKBAR_WINDOW), FALSE); // 设置小图标 //初始化列表控件 CRect rect; m_list_ctrl.GetClientRect(rect); m_list_ctrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP); int width0 = rect.Width() /2; int width1 = (rect.Width() - width0 - theApp.DPI(20) - 1) / 2; int width2 = rect.Width() - width0 - width1 - theApp.DPI(20) - 1; m_list_ctrl.InsertColumn(0, CCommon::LoadText(IDS_ITEM), LVCFMT_LEFT, width0); m_list_ctrl.InsertColumn(1, CCommon::LoadText(IDS_COLOR_LABEL), LVCFMT_LEFT, width1); m_list_ctrl.InsertColumn(2, CCommon::LoadText(IDS_COLOR_VALUE), LVCFMT_LEFT, width2); m_list_ctrl.SetDrawItemRangMargin(theApp.DPI(2)); //向列表中插入行 for (auto iter = theApp.m_plugins.AllDisplayItemsWithPlugins().begin(); iter != theApp.m_plugins.AllDisplayItemsWithPlugins().end(); ++iter) { CString item_name = iter->GetItemName(); if (!item_name.IsEmpty()) { int index = m_list_ctrl.GetItemCount(); m_list_ctrl.InsertItem(index, item_name); m_list_ctrl.SetItemColor(index, 1, m_colors[*iter].label); m_list_ctrl.SetItemColor(index, 2, m_colors[*iter].value); m_list_ctrl.SetItemData(index, (DWORD_PTR)&(*iter)); } } return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CTaskbarColorDlg::OnNMDblclkList1(NMHDR *pNMHDR, LRESULT *pResult) { LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR); // TODO: 在此添加控件通知处理程序代码 int index = pNMItemActivate->iItem; int col = pNMItemActivate->iSubItem; if (col == 1 || col == 2) { COLORREF color = m_list_ctrl.GetItemColor(index, col); CMFCColorDialogEx colorDlg(color, 0, this); if (colorDlg.DoModal() == IDOK) { color = colorDlg.GetColor(); m_list_ctrl.SetItemColor(index, col, color); CommonDisplayItem* item = (CommonDisplayItem*)(m_list_ctrl.GetItemData(index)); if (col == 1) m_colors[*item].label = color; else m_colors[*item].value = color; } } *pResult = 0; } ================================================ FILE: TrafficMonitor/TaskbarColorDlg.h ================================================ #pragma once #include "ColorStatic.h" #include "afxwin.h" #include "ColorSettingListCtrl.h" #include "BaseDialog.h" // CTaskbarColorDlg 对话框 class CTaskbarColorDlg : public CBaseDialog { DECLARE_DYNAMIC(CTaskbarColorDlg) public: CTaskbarColorDlg(const std::map& colors, CWnd* pParent = NULL); // 标准构造函数 virtual ~CTaskbarColorDlg(); const std::map& GetColors() const { return m_colors; } // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_TASKBAR_COLOR_DIALOG }; #endif protected: std::map m_colors; CColorSettingListCtrl m_list_ctrl; virtual CString GetDialogName() const override; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); afx_msg void OnNMDblclkList1(NMHDR *pNMHDR, LRESULT *pResult); }; ================================================ FILE: TrafficMonitor/TaskbarDefaultStyle.cpp ================================================ #include "stdafx.h" #include "TaskbarDefaultStyle.h" #include "IniHelper.h" #include "TrafficMonitor.h" #include "WindowsSettingHelper.h" CTaskbarDefaultStyle::CTaskbarDefaultStyle() { } CTaskbarDefaultStyle::~CTaskbarDefaultStyle() { SaveConfig(); } void CTaskbarDefaultStyle::LoadConfig() { CIniHelper ini{ theApp.m_config_path }; for (int i = 0; i < TASKBAR_DEFAULT_STYLE_NUM; i++) { COLORREF default_text_color = (i == TASKBAR_DEFAULT_LIGHT_STYLE_INDEX ? RGB(0, 0, 0) : RGB(255, 255, 255)); COLORREF default_back_color = (i == TASKBAR_DEFAULT_LIGHT_STYLE_INDEX ? RGB(210, 210, 211) : 0); COLORREF default_transparent_color = (i == TASKBAR_DEFAULT_LIGHT_STYLE_INDEX ? RGB(210, 210, 211) : 0); COLORREF default_status_bar_color = (i == TASKBAR_DEFAULT_LIGHT_STYLE_INDEX ? RGB(165, 165, 165) : 0x005A5A5A); wchar_t buff[64]; swprintf_s(buff, L"default%d_", i + 1); wstring key_name = buff; ini.LoadTaskbarWndColors(L"taskbar_default_style", (key_name + L"text_color").c_str(), m_default_style[i].text_colors, default_text_color); m_default_style[i].back_color = ini.GetInt(L"taskbar_default_style", (key_name + L"back_color").c_str(), default_back_color); m_default_style[i].transparent_color = ini.GetInt(L"taskbar_default_style", (key_name + L"transparent_color").c_str(), default_transparent_color); m_default_style[i].status_bar_color = ini.GetInt(L"taskbar_default_style", (key_name + L"status_bar_color").c_str(), default_status_bar_color); m_default_style[i].specify_each_item_color = ini.GetBool(L"taskbar_default_style", (key_name + L"specify_each_item_color").c_str(), false); } } void CTaskbarDefaultStyle::SaveConfig() const { CIniHelper ini{ theApp.m_config_path }; for (int i = 0; i < TASKBAR_DEFAULT_STYLE_NUM; i++) { wchar_t buff[64]; swprintf_s(buff, L"default%d_", i + 1); wstring key_name = buff; if (IsTaskBarStyleDataValid(m_default_style[i])) //保存前检查当前颜色预设是否有效 { ini.SaveTaskbarWndColors(L"taskbar_default_style", (key_name + L"text_color").c_str(), m_default_style[i].text_colors); ini.WriteInt(L"taskbar_default_style", (key_name + L"back_color").c_str(), m_default_style[i].back_color); ini.WriteInt(L"taskbar_default_style", (key_name + L"transparent_color").c_str(), m_default_style[i].transparent_color); ini.WriteInt(L"taskbar_default_style", (key_name + L"status_bar_color").c_str(), m_default_style[i].status_bar_color); ini.WriteBool(L"taskbar_default_style", (key_name + L"specify_each_item_color").c_str(), m_default_style[i].specify_each_item_color); } else { //写入日志 CString log_str; log_str.Format(_T("在保存预设%d时检测到背景色和文字颜色都为黑色,该预设未被保存。"), i); CCommon::WriteLog(log_str, theApp.m_log_path.c_str()); return; } } ini.Save(); } void CTaskbarDefaultStyle::ApplyDefaultStyle(int index, TaskBarSettingData & data) const { /*if (index == TASKBAR_DEFAULT_LIGHT_STYLE_INDEX) { ApplyDefaultLightStyle(data); } else */if (index >= 0 && index < TASKBAR_DEFAULT_STYLE_NUM) { if (!IsTaskBarStyleDataValid(m_default_style[index])) return; data.text_colors = m_default_style[index].text_colors; data.back_color = m_default_style[index].back_color; data.transparent_color = m_default_style[index].transparent_color; data.status_bar_color = m_default_style[index].status_bar_color; data.specify_each_item_color = m_default_style[index].specify_each_item_color; if (data.transparent_color == data.back_color) { CCommon::TransparentColorConvert(data.back_color); CCommon::TransparentColorConvert(data.transparent_color); } } } //void CTaskbarDefaultStyle::ApplyDefaultLightStyle(TaskBarSettingData& data) //{ // for (auto& item : data.text_colors) // { // item.second.label = RGB(0, 0, 0); // item.second.value = RGB(0, 0, 0); // } // data.back_color = RGB(210, 210, 211); // data.transparent_color = RGB(210, 210, 211); // data.status_bar_color = RGB(165, 165, 165); //} void CTaskbarDefaultStyle::ModifyDefaultStyle(int index, TaskBarSettingData & data) { if (index < 0 || index >= TASKBAR_DEFAULT_STYLE_NUM) return; m_default_style[index].text_colors = data.text_colors; m_default_style[index].back_color = data.back_color; m_default_style[index].transparent_color = data.transparent_color; m_default_style[index].status_bar_color = data.status_bar_color; m_default_style[index].specify_each_item_color = data.specify_each_item_color; } bool CTaskbarDefaultStyle::IsTaskbarTransparent(const TaskBarSettingData& data) { if (CWindowsSettingHelper::IsWindows10LightTheme() || theApp.m_win_version.IsWindows8Or8point1() || theApp.m_is_windows11_taskbar) return (data.transparent_color == data.back_color); else return data.transparent_color == 0; } void CTaskbarDefaultStyle::SetTaskabrTransparent(bool transparent, TaskBarSettingData& data) { if (transparent) { if (CWindowsSettingHelper::IsWindows10LightTheme() || theApp.m_win_version.IsWindows8Or8point1() || theApp.m_is_windows11_taskbar) { //浅色模式下要设置任务栏窗口透明,只需将透明色设置成和背景色一样即可 CCommon::TransparentColorConvert(data.back_color); data.transparent_color = data.back_color; } else { //深色模式下,背景色透明将透明色设置成黑色 data.transparent_color = 0; } } else { //要设置任务栏窗口不透明,只需将透明色设置成和背景色不一样即可 if (data.back_color != TASKBAR_TRANSPARENT_COLOR1) data.transparent_color = TASKBAR_TRANSPARENT_COLOR1; else data.transparent_color = TASKBAR_TRANSPARENT_COLOR2; } } bool CTaskbarDefaultStyle::IsTaskBarStyleDataValid(const TaskBarStyleData& data) { for (const auto& item : data.text_colors) { if (item.second.label != data.back_color || item.second.value != data.back_color) return true; } return false; //如果文本颜色全部等于背景颜色,则该颜色预设无效 } ================================================ FILE: TrafficMonitor/TaskbarDefaultStyle.h ================================================ #pragma once #include "CommonData.h" #define TASKBAR_DEFAULT_STYLE_NUM 4 #define TASKBAR_DEFAULT_LIGHT_STYLE_INDEX 3 class CTaskbarDefaultStyle { public: struct TaskBarStyleData { std::map text_colors{}; COLORREF back_color{}; COLORREF transparent_color{}; COLORREF status_bar_color{}; bool specify_each_item_color{}; }; CTaskbarDefaultStyle(); ~CTaskbarDefaultStyle(); void LoadConfig(); void SaveConfig() const; void ApplyDefaultStyle(int index, TaskBarSettingData& data) const; //应用一个颜色预设 //static void ApplyDefaultLightStyle(TaskBarSettingData& data); //应用默认的浅色模式预设 void ModifyDefaultStyle(int index, TaskBarSettingData& data); //将当前颜色设置保存到一个预设方案 static bool IsTaskbarTransparent(const TaskBarSettingData& data); static void SetTaskabrTransparent(bool transparent, TaskBarSettingData& data); static bool IsTaskBarStyleDataValid(const TaskBarStyleData& data); //判断一个颜色模式是否有效 private: TaskBarStyleData m_default_style[TASKBAR_DEFAULT_STYLE_NUM]; //预设样式 }; ================================================ FILE: TrafficMonitor/TaskbarItemOrderHelper.cpp ================================================ #include "stdafx.h" #include "TaskbarItemOrderHelper.h" #include "Common.h" #include "TrafficMonitor.h" CommonDisplayItem::CommonDisplayItem(DisplayItem item) { is_plugin = false; item_type = item; plugin_item = nullptr; } CommonDisplayItem::CommonDisplayItem(IPluginItem* item) { is_plugin = true; plugin_item = item; } bool CommonDisplayItem::operator<(const CommonDisplayItem& item) const { if (is_plugin && !item.is_plugin) return false; else if (!is_plugin && item.is_plugin) return true; else if (!is_plugin) return item_type < item.item_type; else return theApp.m_plugins.GetItemIndex(plugin_item) < theApp.m_plugins.GetItemIndex(item.plugin_item); } CString CommonDisplayItem::GetItemName() const { CString item_name; if (is_plugin) { if (plugin_item != nullptr) item_name = plugin_item->GetItemName(); } else { switch (item_type) { case TDI_UP: item_name = CCommon::LoadText(IDS_UPLOAD); break; case TDI_DOWN: item_name = CCommon::LoadText(IDS_DOWNLOAD); break; case TDI_TOTAL_SPEED: item_name = CCommon::LoadText(IDS_TOTAL_NET_SPEED); break; case TDI_CPU: item_name = CCommon::LoadText(IDS_CPU_USAGE); break; case TDI_MEMORY: item_name = CCommon::LoadText(IDS_MEMORY_USAGE); break; #ifndef WITHOUT_TEMPERATURE case TDI_GPU_USAGE: item_name = CCommon::LoadText(IDS_GPU_USAGE); break; case TDI_CPU_TEMP: item_name = CCommon::LoadText(IDS_CPU_TEMPERATURE); break; case TDI_GPU_TEMP: item_name = CCommon::LoadText(IDS_GPU_TEMPERATURE); break; case TDI_HDD_TEMP: item_name = CCommon::LoadText(IDS_HDD_TEMPERATURE); break; case TDI_MAIN_BOARD_TEMP: item_name = CCommon::LoadText(IDS_MAINBOARD_TEMPERATURE); break; case TDI_HDD_USAGE: item_name = CCommon::LoadText(IDS_HDD_USAGE); break; case TDI_CPU_FREQ: item_name = CCommon::LoadText(IDS_CPU_FREQ); break; #endif default: break; } } return item_name; } bool CommonDisplayItem::operator==(const CommonDisplayItem& item) const { if (is_plugin != item.is_plugin) return false; else if (!is_plugin) return item_type == item.item_type; else return plugin_item == item.plugin_item; } ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// CTaskbarItemOrderHelper::CTaskbarItemOrderHelper(bool displayed_only) : m_displayed_only(displayed_only) { } void CTaskbarItemOrderHelper::Init() { for (const auto& item : theApp.m_plugins.AllDisplayItemsWithPlugins()) { m_all_item_in_default_order.push_back(item); } } std::vector CTaskbarItemOrderHelper::GetAllDisplayItemsWithOrder() const { std::vector items; for (auto i : m_item_order) { if (i >= 0 && i < static_cast(m_all_item_in_default_order.size())) { if (m_displayed_only && !IsItemDisplayed(m_all_item_in_default_order[i])) { continue; } items.push_back(m_all_item_in_default_order[i]); } } return items; } void CTaskbarItemOrderHelper::FromString(const std::wstring& str) { m_item_order.clear(); std::vector str_list; CCommon::StringSplit(str, L',', str_list); for (const auto& s : str_list) { m_item_order.push_back(_wtoi(s.c_str())); } NormalizeItemOrder(); } std::wstring CTaskbarItemOrderHelper::ToString() const { std::wstring result; for (int i : m_item_order) { result += std::to_wstring(i); result.push_back(L','); } if (!m_item_order.empty()) result.pop_back(); return result; } void CTaskbarItemOrderHelper::SetOrder(const vector& item_order) { m_item_order = item_order; NormalizeItemOrder(); } const vector& CTaskbarItemOrderHelper::GetItemOrderConst() const { return m_item_order; } vector& CTaskbarItemOrderHelper::GetItemOrder() { return m_item_order; } CString CTaskbarItemOrderHelper::GetItemDisplayName(CommonDisplayItem item) { if (item.is_plugin) { if (item.plugin_item != nullptr) return item.plugin_item->GetItemName(); else return CString(); } else { switch (item.item_type) { case TDI_UP: return CCommon::LoadText(IDS_UPLOAD); case TDI_DOWN: return CCommon::LoadText(IDS_DOWNLOAD); case TDI_TOTAL_SPEED: return CCommon::LoadText(IDS_TOTAL_NET_SPEED); case TDI_CPU: return CCommon::LoadText(IDS_CPU_USAGE); case TDI_MEMORY: return CCommon::LoadText(IDS_MEMORY_USAGE); case TDI_GPU_USAGE: return CCommon::LoadText(IDS_GPU_USAGE); case TDI_CPU_TEMP: return CCommon::LoadText(IDS_CPU_TEMPERATURE); case TDI_GPU_TEMP: return CCommon::LoadText(IDS_GPU_TEMPERATURE); case TDI_HDD_TEMP: return CCommon::LoadText(IDS_HDD_TEMPERATURE); case TDI_MAIN_BOARD_TEMP: return CCommon::LoadText(IDS_MAINBOARD_TEMPERATURE); case TDI_HDD_USAGE: return CCommon::LoadText(IDS_HDD_USAGE); case TDI_CPU_FREQ: return CCommon::LoadText(IDS_CPU_FREQ); default: break; } } return CString(); } bool CTaskbarItemOrderHelper::IsItemDisplayed(CommonDisplayItem item) { bool displayed = true; if (!item.is_plugin) { if ((item == TDI_CPU_TEMP || item == TDI_CPU_FREQ) && !theApp.m_general_data.IsHardwareEnable(HI_CPU)) displayed = false; if ((item == TDI_GPU_TEMP || item == TDI_GPU_USAGE) && !theApp.m_general_data.IsHardwareEnable(HI_GPU)) displayed = false; if ((item == TDI_HDD_TEMP || item == TDI_HDD_USAGE) && !theApp.m_general_data.IsHardwareEnable(HI_HDD)) displayed = false; if (item == TDI_MAIN_BOARD_TEMP && !theApp.m_general_data.IsHardwareEnable(HI_MBD)) displayed = false; } return displayed; } void CTaskbarItemOrderHelper::NormalizeItemOrder() { //检查是否有超出范围的序号 int item_num = static_cast(theApp.m_plugins.AllDisplayItemsWithPlugins().size()); for (auto iter = m_item_order.begin(); iter != m_item_order.end();) { if (*iter < 0 || *iter >= item_num) iter = m_item_order.erase(iter); else ++iter; } //删除不显示的序号 if (m_displayed_only) { for (auto iter = m_item_order.begin(); iter != m_item_order.end();) { if (*iter >= 0 && *iter < static_cast(m_all_item_in_default_order.size())) { CommonDisplayItem item = m_all_item_in_default_order[*iter]; if (!IsItemDisplayed(item)) { iter = m_item_order.erase(iter); continue; } } ++iter; } } //删除重复的序号 CCommon::RemoveVectorDuplicateItem(m_item_order); //检查是否有缺少的序号 for (int i = 0; i < item_num; i++) { auto iter = std::find(m_item_order.begin(), m_item_order.end(), i); if (iter == m_item_order.end()) m_item_order.push_back(i); } } ================================================ FILE: TrafficMonitor/TaskbarItemOrderHelper.h ================================================ #pragma once #include "PluginInterface.h" //显示的项目 enum DisplayItem { TDI_UP = 1 << 0, TDI_DOWN = 1 << 1, TDI_CPU = 1 << 2, TDI_MEMORY = 1 << 3, TDI_GPU_USAGE = 1 << 4, TDI_CPU_TEMP = 1 << 5, TDI_GPU_TEMP = 1 << 6, TDI_HDD_TEMP = 1 << 7, TDI_MAIN_BOARD_TEMP = 1 << 8, TDI_HDD_USAGE = 1 << 9, TDI_TOTAL_SPEED = 1 << 10, TDI_CPU_FREQ = 1 << 11 }; //显示的项目 struct CommonDisplayItem { bool is_plugin{}; //是否为插件项目 DisplayItem item_type{}; //内建的显示项目 IPluginItem* plugin_item{}; //插件显示项目 CommonDisplayItem() {} CommonDisplayItem(DisplayItem item); CommonDisplayItem(IPluginItem* item); bool operator<(const CommonDisplayItem&) const; bool operator==(const CommonDisplayItem&) const; CString GetItemName() const; }; //所有显示项目的集合 const std::set AllDisplayItems { TDI_UP, TDI_DOWN, TDI_CPU, TDI_MEMORY #ifndef WITHOUT_TEMPERATURE , TDI_GPU_USAGE, TDI_CPU_TEMP, TDI_GPU_TEMP, TDI_HDD_TEMP, TDI_MAIN_BOARD_TEMP, TDI_HDD_USAGE,TDI_CPU_FREQ #endif , TDI_TOTAL_SPEED }; class CTaskbarItemOrderHelper { public: CTaskbarItemOrderHelper(bool displayed_only = false); void Init(); //根据设定的顺序获取任务窗口每个显示项目 std::vector GetAllDisplayItemsWithOrder() const; void FromString(const std::wstring& str); std::wstring ToString() const; void SetOrder(const vector& item_order); const vector& GetItemOrderConst() const; vector& GetItemOrder(); static CString GetItemDisplayName(CommonDisplayItem item); static bool IsItemDisplayed(CommonDisplayItem item); private: //规范m_item_order里的项目,如果m_item_order里有序号超过了显示项目的个数,则将其移除,并在后面添加缺少的项目的序号 void NormalizeItemOrder(); private: vector m_item_order; //保存每个项目的顺序 vector m_all_item_in_default_order; //以默认顺序保存的所有显示项目 bool m_displayed_only; }; ================================================ FILE: TrafficMonitor/Test.cpp ================================================ #include "stdafx.h" #include "Test.h" #include "Common.h" #include "SkinFile.h" #include "TrafficMonitor.h" CTest::CTest() { } CTest::~CTest() { } void CTest::Test() { //TestHttpQequest(); //TestGetLicense(); //TestSkin(); //TestCrash(); //TestDate(); } void CTest::TestCommand() { //TestPlugin(); } void CTest::TestHttpQequest() { wstring result; bool rtn = CCommon::GetURL(L"https://v4.yinghualuo.cn/bejson", result, true, L"TrafficMonitor_V1.78"); int a = 0; } void CTest::TestGetLicense() { CString license_str; HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_LICENSE), _T("TEXT")); if (hRes != NULL) { HGLOBAL hglobal = LoadResource(NULL, hRes); if (hglobal != NULL) { license_str = CCommon::StrToUnicode((const char*)hglobal, true).c_str(); int a = 0; } } } void CTest::TestSkin() { CSkinFile skin; //skin.Load(L"C:\\Users\\zhong\\OneDrive\\文档\\TrafficMonitorSkin.xml"); skin.Load(L"D:\\Projects\\GitHub Project\\TrafficMonitor\\TrafficMonitor\\skins\\0默认皮肤\\skin.ini"); int a = 0; } void CTest::TestCrash() { CString* pStr = nullptr; int a = pStr->GetLength(); printf("%d", a); } void CTest::TestPlugin() { if (!theApp.m_plugins.GetPlugins().empty()) { theApp.m_plugins.GetPlugins()[0].plugin->ShowOptionsDialog(theApp.m_pMainWnd->m_hWnd); } } void CTest::TestDate() { Date d; d.year = 2021; d.month = 1; d.day = 4; int week = d.week(); int a = 0; } ================================================ FILE: TrafficMonitor/Test.h ================================================ #pragma once class CTest { public: CTest(); ~CTest(); static void Test(); static void TestCommand(); private: static void TestHttpQequest(); static void TestGetLicense(); static void TestSkin(); static void TestCrash(); static void TestPlugin(); static void TestDate(); }; ================================================ FILE: TrafficMonitor/TinyXml2Helper.cpp ================================================ #include "stdafx.h" #include "TinyXml2Helper.h" #include "Common.h" bool CTinyXml2Helper::LoadXmlFile(tinyxml2::XMLDocument& doc, const wchar_t* file_path) { //由于XMLDocument::LoadFile函数不支持Unicode,因此这里自行读取文件内容,并调用XMLDocument::Parse函数解析 size_t length; const char* xml_contents = CCommon::GetFileContent(file_path, length); auto err = doc.Parse(xml_contents, length); delete[] xml_contents; return err == tinyxml2::XML_SUCCESS; } void CTinyXml2Helper::IterateChildNode(tinyxml2::XMLElement* ele, std::function fun) { if (ele == nullptr) return; tinyxml2::XMLElement* child = ele->FirstChildElement(); if (child == nullptr) return; fun(child); while (true) { child = child->NextSiblingElement(); if (child != nullptr) fun(child); else break; } } const char * CTinyXml2Helper::ElementAttribute(tinyxml2::XMLElement * ele, const char * attr) { if (ele != nullptr) { const char* str = ele->Attribute(attr); if (str != nullptr) return str; } return ""; } const char* CTinyXml2Helper::ElementName(tinyxml2::XMLElement* ele) { if (ele != nullptr) { const char* str = ele->Name(); if (str != nullptr) return str; } return ""; } const char* CTinyXml2Helper::ElementText(tinyxml2::XMLElement* ele) { if (ele != nullptr) { const char* str = ele->GetText(); if (str != nullptr) return str; } return ""; } bool CTinyXml2Helper::StringToBool(const char* str) { string str_text{ str }; return (!str_text.empty() && str_text != "0"); } ================================================ FILE: TrafficMonitor/TinyXml2Helper.h ================================================ #pragma once #include "tinyxml2/tinyxml2.h" #include #include class CTinyXml2Helper { public: //从文件读取XML内容 static bool LoadXmlFile(tinyxml2::XMLDocument& doc, const wchar_t* file_path); //遍历一个XML节点 //fun: 一个函数对象,遍历到一个节点时被调用 static void IterateChildNode(tinyxml2::XMLElement* ele, std::function fun); //获取一个节点的属性(返回值不会为空指针,如果找不到则返回空字符串) static const char* ElementAttribute(tinyxml2::XMLElement* ele, const char* attr); //获取一个节点的名称(返回值不会为空指针,如果找不到则返回空字符串) static const char* ElementName(tinyxml2::XMLElement* ele); //获取一个节点的文本(返回值不会为空指针,如果找不到则返回空字符串) static const char* ElementText(tinyxml2::XMLElement* ele); static bool StringToBool(const char* str); }; ================================================ FILE: TrafficMonitor/TrafficMonitor.cpp ================================================  // TrafficMonitor.cpp : 定义应用程序的类行为。 // #include "stdafx.h" #include "TrafficMonitor.h" #include "TrafficMonitorDlg.h" #include "crashtool.h" #include "UpdateHelper.h" #include "Test.h" #include "WIC.h" #include "auto_start_helper.h" #include "AppAlreadyRuningDlg.h" #include "WindowsSettingHelper.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CTrafficMonitorApp BEGIN_MESSAGE_MAP(CTrafficMonitorApp, CWinApp) //ON_COMMAND(ID_HELP, &CWinApp::OnHelp) ON_COMMAND(ID_HELP, &CTrafficMonitorApp::OnHelp) ON_COMMAND(ID_FREQUENTY_ASKED_QUESTIONS, &CTrafficMonitorApp::OnFrequentyAskedQuestions) ON_COMMAND(ID_UPDATE_LOG, &CTrafficMonitorApp::OnUpdateLog) END_MESSAGE_MAP() CTrafficMonitorApp* CTrafficMonitorApp::self = NULL; // CTrafficMonitorApp 构造 CTrafficMonitorApp::CTrafficMonitorApp() { self = this; // 支持重新启动管理器 //m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART; // TODO: 在此处添加构造代码, // 将所有重要的初始化放置在 InitInstance 中 CRASHREPORT::StartCrashReport(); } void CTrafficMonitorApp::LoadConfig() { CIniHelper ini{ m_config_path }; //常规设置 m_general_data.check_update_when_start = ini.GetBool(_T("general"), _T("check_update_when_start"), true); m_general_data.allow_skin_cover_font = ini.GetBool(_T("general"), _T("allow_skin_cover_font"), true); m_general_data.allow_skin_cover_text = ini.GetBool(_T("general"), _T("allow_skin_cover_text"), true); m_general_data.language = static_cast(ini.GetInt(_T("general"), _T("language"), 0)); m_general_data.show_all_interface = ini.GetBool(L"general", L"show_all_interface", false); bool is_chinese_language{}; //当前语言是否为简体中文 if (m_general_data.language == Language::FOLLOWING_SYSTEM) is_chinese_language = CCommon::LoadText(IDS_LANGUAGE_CODE) == _T("2"); else is_chinese_language = (m_general_data.language == Language::SIMPLIFIED_CHINESE); m_general_data.update_source = ini.GetInt(L"general", L"update_source", is_chinese_language ? 1 : 0); //如果当前语言为简体,则默认更新源为Gitee,否则为GitHub //载入获取CPU利用率的方式,默认使用GetSystemTimes获取 m_general_data.m_get_cpu_usage_by_cpu_times = ini.GetBool(L"general", L"get_cpu_usage_by_cpu_times", /*m_win_version.GetMajorVersion() < 10*/ true); m_general_data.monitor_time_span = ini.GetInt(L"general", L"monitor_time_span", 1000); if (m_general_data.monitor_time_span < MONITOR_TIME_SPAN_MIN || m_general_data.monitor_time_span > MONITOR_TIME_SPAN_MAX) m_general_data.monitor_time_span = 1000; m_general_data.hard_disk_name = ini.GetString(L"general", L"hard_disk_name", L""); m_general_data.cpu_core_name = ini.GetString(L"general", L"cpu_core_name", L"Core Average"); m_general_data.hardware_monitor_item = ini.GetInt(L"general", L"hardware_monitor_item", 0); std::vector connections_hide; ini.GetStringList(L"general", L"connections_hide", connections_hide, std::vector{}); m_general_data.connections_hide.FromVector(connections_hide); //Windows10颜色模式设置 bool is_windows10_light_theme = CWindowsSettingHelper::IsWindows10LightTheme(); if (is_windows10_light_theme) CCommon::SetColorMode(ColorMode::Light); else CCommon::SetColorMode(ColorMode::Default); //主窗口设置 m_cfg_data.m_transparency = ini.GetInt(_T("config"), _T("transparency"), 80); m_main_wnd_data.m_always_on_top = ini.GetBool(_T("config"), _T("always_on_top"), true); m_main_wnd_data.m_lock_window_pos = ini.GetBool(_T("config"), _T("lock_window_pos"), false); m_general_data.show_notify_icon = ini.GetBool(_T("config"), _T("show_notify_icon"), true); m_cfg_data.m_show_more_info = ini.GetBool(_T("config"), _T("show_cpu_memory"), false); m_main_wnd_data.m_mouse_penetrate = ini.GetBool(_T("config"), _T("mouse_penetrate"), false); m_cfg_data.m_show_task_bar_wnd = ini.GetBool(_T("config"), _T("show_task_bar_wnd"), false); m_cfg_data.m_position_x = ini.GetInt(_T("config"), _T("position_x"), -1); m_cfg_data.m_position_y = ini.GetInt(_T("config"), _T("position_y"), -1); m_cfg_data.m_auto_select = ini.GetBool(_T("connection"), _T("auto_select"), true); m_cfg_data.m_select_all = ini.GetBool(_T("connection"), _T("select_all"), false); //判断皮肤是否存在 std::vector skin_files; CCommon::GetFiles((theApp.m_skin_path + L"\\*").c_str(), skin_files); bool is_skin_exist = (!skin_files.empty()); ini.LoadMainWndColors(_T("config"), _T("text_color"), m_main_wnd_data.text_colors, (is_skin_exist ? 16384 : 16777215)); //根据皮肤是否存在来设置默认的文本颜色,皮肤文件不存在时文本颜色默认为白色 m_main_wnd_data.specify_each_item_color = ini.GetBool(_T("config"), _T("specify_each_item_color"), false); m_cfg_data.m_hide_main_window = ini.GetBool(_T("config"), _T("hide_main_window"), false); m_cfg_data.m_connection_name = CCommon::UnicodeToStr(ini.GetString(L"connection", L"connection_name", L"").c_str()); m_cfg_data.m_skin_name = ini.GetString(_T("config"), _T("skin_selected"), _T("")); if (m_cfg_data.m_skin_name.substr(0, 8) == L".\\skins\\") //如果读取到的皮肤名称前面有".\\skins\\",则把它删除。(用于和前一个版本保持兼容性) m_cfg_data.m_skin_name = m_cfg_data.m_skin_name.substr(7); m_cfg_data.m_notify_icon_selected = ini.GetInt(_T("config"), _T("notify_icon_selected"), (m_win_version.IsWindows7() || m_win_version.IsWindows8Or8point1() ? 2 : m_cfg_data.m_dft_notify_icon)); //Win7/8/8.1默认使用蓝色通知区图标,因为隐藏通知区图标后白色图标会看不清,其他系统默认使用白色图标 m_cfg_data.m_notify_icon_auto_adapt = ini.GetBool(_T("config"), _T("notify_icon_auto_adapt"), true); if (m_cfg_data.m_notify_icon_auto_adapt) AutoSelectNotifyIcon(); m_main_wnd_data.swap_up_down = ini.GetBool(_T("config"), _T("swap_up_down"), false); m_main_wnd_data.hide_main_wnd_when_fullscreen = ini.GetBool(_T("config"), _T("hide_main_wnd_when_fullscreen"), true); FontInfo default_font{}; default_font.name = CCommon::LoadText(IDS_DEFAULT_FONT); default_font.size = 10; ini.LoadFontData(_T("config"), m_main_wnd_data.font, default_font); //m_main_wnd_data.font.name = ini.GetString(_T("config"), _T("font_name"), CCommon::LoadText(IDS_MICROSOFT_YAHEI)).c_str(); //m_main_wnd_data.font.size = ini.GetInt(_T("config"), _T("font_size"), 10); //载入显示文本设置 m_main_wnd_data.disp_str.Get(TDI_UP) = ini.GetString(_T("config"), L"up_string", CCommon::LoadText(IDS_UPLOAD_DISP, _T(": $"))); m_main_wnd_data.disp_str.Get(TDI_DOWN) = ini.GetString(L"config", L"down_string", CCommon::LoadText(IDS_DOWNLOAD_DISP, _T(": $"))); m_main_wnd_data.disp_str.Get(TDI_TOTAL_SPEED) = ini.GetString(L"config", L"total_speed_string", _T("↑↓: $")); m_main_wnd_data.disp_str.Get(TDI_CPU) = ini.GetString(L"config", L"cpu_string", L"CPU: $"); m_main_wnd_data.disp_str.Get(TDI_CPU_FREQ) = ini.GetString(L"config", L"cpu_freq_string", CCommon::LoadText(IDS_CPU_FREQ, _T(": $"))); m_main_wnd_data.disp_str.Get(TDI_MEMORY) = ini.GetString(L"config", L"memory_string", CCommon::LoadText(IDS_MEMORY_DISP, _T(": $"))); m_main_wnd_data.disp_str.Get(TDI_GPU_USAGE) = ini.GetString(L"config", L"gpu_string", CCommon::LoadText(IDS_GPU_DISP, _T(": $"))); m_main_wnd_data.disp_str.Get(TDI_CPU_TEMP) = ini.GetString(L"config", L"cpu_temp_string", L"CPU: $"); m_main_wnd_data.disp_str.Get(TDI_GPU_TEMP) = ini.GetString(L"config", L"gpu_temp_string", CCommon::LoadText(IDS_GPU_DISP, _T(": $"))); m_main_wnd_data.disp_str.Get(TDI_HDD_TEMP) = ini.GetString(L"config", L"hdd_temp_string", CCommon::LoadText(IDS_HDD_DISP, _T(": $"))); m_main_wnd_data.disp_str.Get(TDI_MAIN_BOARD_TEMP) = ini.GetString(L"config", L"main_board_temp_string", CCommon::LoadText(IDS_MAINBOARD_DISP, _T(": $"))); m_main_wnd_data.disp_str.Get(TDI_HDD_USAGE) = ini.GetString(L"config", L"hdd_string", CCommon::LoadText(IDS_HDD_DISP, _T(": $"))); //载入插件项目的显示文本设置 ini.LoadPluginDisplayStr(true); m_main_wnd_data.speed_short_mode = ini.GetBool(_T("config"), _T("speed_short_mode"), false); m_main_wnd_data.separate_value_unit_with_space = ini.GetBool(_T("config"), _T("separate_value_unit_with_space"), true); m_main_wnd_data.show_tool_tip = ini.GetBool(_T("config"), _T("show_tool_tip"), true); m_main_wnd_data.memory_display = static_cast(ini.GetInt(L"config", L"memory_display", static_cast(MemoryDisplay::USAGE_PERCENTAGE))); m_main_wnd_data.unit_byte = ini.GetBool(_T("config"), _T("unit_byte"), true); m_main_wnd_data.speed_unit = static_cast(ini.GetInt(_T("config"), _T("speed_unit"), 0)); m_main_wnd_data.hide_unit = ini.GetBool(_T("config"), _T("hide_unit"), false); m_main_wnd_data.hide_percent = ini.GetBool(_T("config"), _T("hide_percent"), false); m_main_wnd_data.double_click_action = static_cast(ini.GetInt(_T("config"), _T("double_click_action"), 0)); m_main_wnd_data.double_click_exe = ini.GetString(L"config", L"double_click_exe", (theApp.m_system_dir + L"\\Taskmgr.exe").c_str()); m_main_wnd_data.m_alow_out_of_border = ini.GetBool(_T("config"), _T("alow_out_of_border"), false); m_general_data.traffic_tip_enable = ini.GetBool(L"notify_tip", L"traffic_tip_enable", false); m_general_data.traffic_tip_value = ini.GetInt(L"notify_tip", L"traffic_tip_value", 200); m_general_data.traffic_tip_unit = ini.GetInt(L"notify_tip", L"traffic_tip_unit", 0); m_general_data.memory_usage_tip.enable = ini.GetBool(L"notify_tip", L"memory_usage_tip_enable", false); m_general_data.memory_usage_tip.tip_value = ini.GetInt(L"notify_tip", L"memory_tip_value", 80); m_general_data.cpu_temp_tip.enable = ini.GetBool(L"notify_tip", L"cpu_temperature_tip_enable", false); m_general_data.cpu_temp_tip.tip_value = ini.GetInt(L"notify_tip", L"cpu_temperature_tip_value", 80); m_general_data.gpu_temp_tip.enable = ini.GetBool(L"notify_tip", L"gpu_temperature_tip_enable", false); m_general_data.gpu_temp_tip.tip_value = ini.GetInt(L"notify_tip", L"gpu_temperature_tip_value", 80); m_general_data.hdd_temp_tip.enable = ini.GetBool(L"notify_tip", L"hdd_temperature_tip_enable", false); m_general_data.hdd_temp_tip.tip_value = ini.GetInt(L"notify_tip", L"hdd_temperature_tip_value", 80); m_general_data.mainboard_temp_tip.enable = ini.GetBool(L"notify_tip", L"mainboard_temperature_tip_enable", false); m_general_data.mainboard_temp_tip.tip_value = ini.GetInt(L"notify_tip", L"mainboard_temperature_tip_value", 80); //任务栏窗口设置 m_taskbar_data.back_color = ini.GetInt(_T("task_bar"), _T("task_bar_back_color"), m_taskbar_data.dft_back_color); m_taskbar_data.transparent_color = ini.GetInt(_T("task_bar"), _T("transparent_color"), m_taskbar_data.dft_transparent_color); if (CTaskbarDefaultStyle::IsTaskbarTransparent(m_taskbar_data)) //如果任务栏背景透明,则需要将颜色转换一下 { CCommon::TransparentColorConvert(m_taskbar_data.back_color); CCommon::TransparentColorConvert(m_taskbar_data.transparent_color); } m_taskbar_data.status_bar_color = ini.GetInt(_T("task_bar"), _T("status_bar_color"), m_taskbar_data.dft_status_bar_color); //m_taskbar_data.text_color = GetPrivateProfileInt(_T("task_bar"), _T("task_bar_text_color"), 0x00ffffffU, m_config_path.c_str()); ini.LoadTaskbarWndColors(_T("task_bar"), _T("task_bar_text_color"), m_taskbar_data.text_colors, m_taskbar_data.dft_text_colors); m_taskbar_data.specify_each_item_color = ini.GetBool(L"task_bar", L"specify_each_item_color", false); //m_cfg_data.m_tbar_show_cpu_memory = ini.GetBool(_T("task_bar"), _T("task_bar_show_cpu_memory"), false); m_taskbar_data.m_tbar_display_item = ini.GetInt(L"task_bar", L"tbar_display_item", TDI_UP | TDI_DOWN); //不含温度监控的版本,不显示温度监控相关项目 #ifdef WITHOUT_TEMPERATURE m_taskbar_data.m_tbar_display_item &= ~TDI_GPU_USAGE; m_taskbar_data.m_tbar_display_item &= ~TDI_CPU_TEMP; m_taskbar_data.m_tbar_display_item &= ~TDI_GPU_TEMP; m_taskbar_data.m_tbar_display_item &= ~TDI_HDD_TEMP; m_taskbar_data.m_tbar_display_item &= ~TDI_MAIN_BOARD_TEMP; m_taskbar_data.m_tbar_display_item &= ~TDI_HDD_USAGE; #endif //如果选项设置中关闭了某个硬件监控,则不显示对应的温度监控相关项目 if (!m_general_data.IsHardwareEnable(HI_CPU)) m_taskbar_data.m_tbar_display_item &= ~TDI_CPU_TEMP; if (!m_general_data.IsHardwareEnable(HI_GPU)) { m_taskbar_data.m_tbar_display_item &= ~TDI_GPU_USAGE; m_taskbar_data.m_tbar_display_item &= ~TDI_GPU_TEMP; } if (!m_general_data.IsHardwareEnable(HI_HDD)) { m_taskbar_data.m_tbar_display_item &= ~TDI_HDD_TEMP; m_taskbar_data.m_tbar_display_item &= ~TDI_HDD_USAGE; } if (!m_general_data.IsHardwareEnable(HI_MBD)) m_taskbar_data.m_tbar_display_item &= ~TDI_MAIN_BOARD_TEMP; //m_taskbar_data.swap_up_down = ini.GetBool(_T("task_bar"), _T("task_bar_swap_up_down"), false); if (m_taskbar_data.back_color == 0 && !m_taskbar_data.text_colors.empty() && m_taskbar_data.text_colors.begin()->second.label == 0) //万一读取到的背景色和文本颜色都为0(黑色),则将文本色和背景色设置成默认颜色 { m_taskbar_data.back_color = m_taskbar_data.dft_back_color; m_taskbar_data.text_colors.begin()->second.label = m_taskbar_data.dft_text_colors; } //m_taskbar_data.font.name = ini.GetString(_T("task_bar"), _T("tack_bar_font_name"), CCommon::LoadText(IDS_MICROSOFT_YAHEI)).c_str(); //m_taskbar_data.font.size = ini.GetInt(_T("task_bar"), _T("tack_bar_font_size"), 9); default_font = FontInfo{}; default_font.name = CCommon::LoadText(IDS_DEFAULT_FONT); default_font.size = 9; ini.LoadFontData(_T("task_bar"), m_taskbar_data.font, default_font); m_taskbar_data.disp_str.Get(TDI_UP) = ini.GetString(L"task_bar", L"up_string", L"↑: $"); m_taskbar_data.disp_str.Get(TDI_DOWN) = ini.GetString(L"task_bar", L"down_string", L"↓: $"); m_taskbar_data.disp_str.Get(TDI_TOTAL_SPEED) = ini.GetString(L"task_bar", L"total_speed_string", L"↑↓: $"); m_taskbar_data.disp_str.Get(TDI_CPU) = ini.GetString(L"task_bar", L"cpu_string", L"CPU: $"); m_taskbar_data.disp_str.Get(TDI_MEMORY) = ini.GetString(L"task_bar", L"memory_string", CCommon::LoadText(IDS_MEMORY_DISP, _T(": $"))); m_taskbar_data.disp_str.Get(TDI_GPU_USAGE) = ini.GetString(L"task_bar", L"gpu_string", CCommon::LoadText(IDS_GPU_DISP, _T(": $"))); m_taskbar_data.disp_str.Get(TDI_CPU_TEMP) = ini.GetString(L"task_bar", L"cpu_temp_string", L"CPU: $"); m_taskbar_data.disp_str.Get(TDI_GPU_TEMP) = ini.GetString(L"task_bar", L"gpu_temp_string", CCommon::LoadText(IDS_GPU_DISP, _T(": "))); m_taskbar_data.disp_str.Get(TDI_HDD_TEMP) = ini.GetString(L"task_bar", L"hdd_temp_string", CCommon::LoadText(IDS_HDD_DISP, _T(": "))); m_taskbar_data.disp_str.Get(TDI_MAIN_BOARD_TEMP) = ini.GetString(L"task_bar", L"main_board_temp_string", CCommon::LoadText(IDS_MAINBOARD_DISP, _T(": "))); m_taskbar_data.disp_str.Get(TDI_HDD_USAGE) = ini.GetString(L"task_bar", L"hdd_string", CCommon::LoadText(IDS_HDD_DISP, _T(": "))); m_taskbar_data.disp_str.Get(TDI_CPU_FREQ) = ini.GetString(L"task_bar", L"cpu_freq_string", CCommon::LoadText(IDS_CPU_FREQ, _T(": $"))); ini.LoadPluginDisplayStr(false); m_taskbar_data.tbar_wnd_on_left = ini.GetBool(_T("task_bar"), _T("task_bar_wnd_on_left"), false); m_taskbar_data.speed_short_mode = ini.GetBool(_T("task_bar"), _T("task_bar_speed_short_mode"), false); m_taskbar_data.tbar_wnd_snap = ini.GetBool(_T("task_bar"), _T("task_bar_wnd_snap"), false); m_taskbar_data.unit_byte = ini.GetBool(_T("task_bar"), _T("unit_byte"), true); m_taskbar_data.speed_unit = static_cast(ini.GetInt(_T("task_bar"), _T("task_bar_speed_unit"), 0)); m_taskbar_data.hide_unit = ini.GetBool(_T("task_bar"), _T("task_bar_hide_unit"), false); m_taskbar_data.hide_percent = ini.GetBool(_T("task_bar"), _T("task_bar_hide_percent"), false); m_taskbar_data.value_right_align = ini.GetBool(_T("task_bar"), _T("value_right_align"), false); m_taskbar_data.horizontal_arrange = ini.GetBool(_T("task_bar"), _T("horizontal_arrange"), false); m_taskbar_data.show_status_bar = ini.GetBool(_T("task_bar"), _T("show_status_bar"), false); m_taskbar_data.separate_value_unit_with_space = ini.GetBool(_T("task_bar"), _T("separate_value_unit_with_space"), true); m_taskbar_data.show_tool_tip = ini.GetBool(_T("task_bar"), _T("show_tool_tip"), true); m_taskbar_data.digits_number = ini.GetInt(_T("task_bar"), _T("digits_number"), 4); m_taskbar_data.memory_display = static_cast(ini.GetInt(L"task_bar", L"memory_display", static_cast(MemoryDisplay::USAGE_PERCENTAGE))); m_taskbar_data.double_click_action = static_cast(ini.GetInt(_T("task_bar"), _T("double_click_action"), 0)); m_taskbar_data.double_click_exe = ini.GetString(L"task_bar", L"double_click_exe", (theApp.m_system_dir + L"\\Taskmgr.exe").c_str()); m_taskbar_data.cm_graph_type = ini.GetBool(_T("task_bar"), _T("cm_graph_type"), true); m_taskbar_data.show_graph_dashed_box = ini.GetBool(L"task_bar", L"show_graph_dashed_box", false); m_taskbar_data.item_space = ini.GetInt(L"task_bar", L"item_space", 4); m_taskbar_data.ValidItemSpace(); if (m_win_version.IsWindows10OrLater()) //只有Win10才支持自动适应系统深色/浅色主题 m_taskbar_data.auto_adapt_light_theme = ini.GetBool(L"task_bar", L"auto_adapt_light_theme", false); else m_taskbar_data.auto_adapt_light_theme = false; m_taskbar_data.dark_default_style = ini.GetInt(L"task_bar", L"dark_default_style", 0); m_taskbar_data.light_default_style = ini.GetInt(L"task_bar", L"light_default_style", TASKBAR_DEFAULT_LIGHT_STYLE_INDEX); if (m_win_version.IsWindows8OrLater()) m_taskbar_data.auto_set_background_color = ini.GetBool(L"task_bar", L"auto_set_background_color", false); else m_taskbar_data.auto_set_background_color = false; m_taskbar_data.item_order.Init(); m_taskbar_data.item_order.FromString(ini.GetString(L"task_bar", L"item_order", L"")); m_taskbar_data.plugin_display_item.FromString(ini.GetString(L"task_bar", L"plugin_display_item", L"")); m_taskbar_data.auto_save_taskbar_color_settings_to_preset = ini.GetBool(L"task_bar", L"auto_save_taskbar_color_settings_to_preset", true); m_taskbar_data.show_netspeed_figure = ini.GetBool(L"task_bar", L"show_netspeed_figure", false); m_taskbar_data.netspeed_figure_max_value = ini.GetInt(L"task_bar", L"netspeed_figure_max_value", 512); m_taskbar_data.netspeed_figure_max_value_unit = ini.GetInt(L"task_bar", L"netspeed_figure_max_value_unit", 0); //其他设置 //m_cfg_data.m_show_internet_ip = ini.GetBool(L"connection_details", L"show_internet_ip", false); m_cfg_data.m_use_log_scale = ini.GetBool(_T("histroy_traffic"), _T("use_log_scale"), true); m_cfg_data.m_sunday_first = ini.GetBool(_T("histroy_traffic"), _T("sunday_first"), true); m_cfg_data.m_view_type = static_cast(ini.GetInt(_T("histroy_traffic"), _T("view_type"), static_cast(HistoryTrafficViewType::HV_DAY))); m_no_multistart_warning = ini.GetBool(_T("other"), _T("no_multistart_warning"), false); m_notify_interval = ini.GetInt(_T("other"), _T("notify_interval"), 60); m_exit_when_start_by_restart_manager = ini.GetBool(_T("other"), _T("exit_when_start_by_restart_manager"), true); m_debug_log = ini.GetBool(_T("other"), _T("debug_log"), false); //由于Win7系统中设置任务栏窗口透明色会导致任务栏窗口不可见,因此默认在Win7中禁用透明色的设定 m_taksbar_transparent_color_enable = ini.GetBool(L"other", L"taksbar_transparent_color_enable", !m_win_version.IsWindows7()); m_last_light_mode = ini.GetBool(L"other", L"last_light_mode", CWindowsSettingHelper::IsWindows10LightTheme()); m_show_mouse_panetrate_tip = ini.GetBool(L"other", L"show_mouse_panetrate_tip", true); m_show_dot_net_notinstalled_tip = ini.GetBool(L"other", L"show_dot_net_notinstalled_tip", true); m_cfg_data.taskbar_left_space_win11 = ini.GetInt(L"task_bar", L"taskbar_left_space_win11", 160); } void CTrafficMonitorApp::SaveConfig() { CIniHelper ini{ m_config_path }; //常规设置 ini.WriteBool(_T("general"), _T("check_update_when_start"), m_general_data.check_update_when_start); ini.WriteBool(_T("general"), _T("allow_skin_cover_font"), m_general_data.allow_skin_cover_font); ini.WriteBool(_T("general"), _T("allow_skin_cover_text"), m_general_data.allow_skin_cover_text); ini.WriteInt(_T("general"), _T("language"), static_cast(m_general_data.language)); ini.WriteBool(L"general", L"show_all_interface", m_general_data.show_all_interface); ini.WriteBool(L"general", L"get_cpu_usage_by_cpu_times", m_general_data.m_get_cpu_usage_by_cpu_times); ini.WriteInt(L"general", L"monitor_time_span", m_general_data.monitor_time_span); ini.WriteString(L"general", L"hard_disk_name", m_general_data.hard_disk_name); ini.WriteString(L"general", L"cpu_core_name", m_general_data.cpu_core_name); ini.WriteInt(L"general", L"hardware_monitor_item", m_general_data.hardware_monitor_item); ini.WriteStringList(L"general", L"connections_hide", m_general_data.connections_hide.ToVector()); //主窗口设置 ini.WriteInt(L"config", L"transparency", m_cfg_data.m_transparency); ini.WriteBool(L"config", L"always_on_top", m_main_wnd_data.m_always_on_top); ini.WriteBool(L"config", L"lock_window_pos", m_main_wnd_data.m_lock_window_pos); ini.WriteBool(L"config", L"show_notify_icon", m_general_data.show_notify_icon); ini.WriteBool(L"config", L"show_cpu_memory", m_cfg_data.m_show_more_info); ini.WriteBool(L"config", L"mouse_penetrate", m_main_wnd_data.m_mouse_penetrate); ini.WriteBool(L"config", L"show_task_bar_wnd", m_cfg_data.m_show_task_bar_wnd); ini.WriteInt(L"config", L"position_x", m_cfg_data.m_position_x); ini.WriteInt(L"config", L"position_y", m_cfg_data.m_position_y); ini.WriteBool(L"connection", L"auto_select", m_cfg_data.m_auto_select); ini.WriteBool(L"connection", L"select_all", m_cfg_data.m_select_all); ini.SaveMainWndColors(L"config", L"text_color", m_main_wnd_data.text_colors); ini.WriteBool(_T("config"), _T("specify_each_item_color"), m_main_wnd_data.specify_each_item_color); ini.WriteInt(L"config", L"hide_main_window", m_cfg_data.m_hide_main_window); ini.WriteString(L"connection", L"connection_name", CCommon::StrToUnicode(m_cfg_data.m_connection_name.c_str())); ini.WriteString(_T("config"), _T("skin_selected"), m_cfg_data.m_skin_name.c_str()); ini.WriteInt(L"config", L"notify_icon_selected", m_cfg_data.m_notify_icon_selected); ini.WriteBool(L"config", L"notify_icon_auto_adapt", m_cfg_data.m_notify_icon_auto_adapt); ini.SaveFontData(L"config", m_main_wnd_data.font); ini.WriteBool(L"config", L"swap_up_down", m_main_wnd_data.swap_up_down); ini.WriteBool(L"config", L"hide_main_wnd_when_fullscreen", m_main_wnd_data.hide_main_wnd_when_fullscreen); ini.WriteString(_T("config"), _T("up_string"), m_main_wnd_data.disp_str.Get(TDI_UP)); ini.WriteString(_T("config"), _T("down_string"), m_main_wnd_data.disp_str.Get(TDI_DOWN)); ini.WriteString(_T("config"), _T("total_speed_string"), m_main_wnd_data.disp_str.Get(TDI_TOTAL_SPEED)); ini.WriteString(_T("config"), _T("cpu_string"), m_main_wnd_data.disp_str.Get(TDI_CPU)); ini.WriteString(_T("config"), _T("memory_string"), m_main_wnd_data.disp_str.Get(TDI_MEMORY)); ini.WriteString(_T("config"), _T("gpu_string"), m_main_wnd_data.disp_str.Get(TDI_GPU_USAGE)); ini.WriteString(_T("config"), _T("cpu_temp_string"), m_main_wnd_data.disp_str.Get(TDI_CPU_TEMP)); ini.WriteString(_T("config"), _T("cpu_freq_string"), m_main_wnd_data.disp_str.Get(TDI_CPU_FREQ)); ini.WriteString(_T("config"), _T("gpu_temp_string"), m_main_wnd_data.disp_str.Get(TDI_GPU_TEMP)); ini.WriteString(_T("config"), _T("hdd_temp_string"), m_main_wnd_data.disp_str.Get(TDI_HDD_TEMP)); ini.WriteString(_T("config"), _T("main_board_temp_string"), m_main_wnd_data.disp_str.Get(TDI_MAIN_BOARD_TEMP)); ini.WriteString(_T("config"), _T("hdd_string"), m_main_wnd_data.disp_str.Get(TDI_HDD_USAGE)); ini.SavePluginDisplayStr(true); ini.WriteBool(L"config", L"speed_short_mode", m_main_wnd_data.speed_short_mode); ini.WriteBool(L"config", L"separate_value_unit_with_space", m_main_wnd_data.separate_value_unit_with_space); ini.WriteBool(L"config", L"show_tool_tip", m_main_wnd_data.show_tool_tip); ini.WriteInt(L"config", L"memory_display", static_cast(m_main_wnd_data.memory_display)); ini.WriteBool(L"config", L"unit_byte", m_main_wnd_data.unit_byte); ini.WriteInt(L"config", L"speed_unit", static_cast(m_main_wnd_data.speed_unit)); ini.WriteBool(L"config", L"hide_unit", m_main_wnd_data.hide_unit); ini.WriteBool(L"config", L"hide_percent", m_main_wnd_data.hide_percent); ini.WriteInt(L"config", L"double_click_action", static_cast(m_main_wnd_data.double_click_action)); ini.WriteString(L"config", L"double_click_exe", m_main_wnd_data.double_click_exe); ini.WriteInt(L"config", L"alow_out_of_border", m_main_wnd_data.m_alow_out_of_border); ini.WriteBool(L"notify_tip", L"traffic_tip_enable", m_general_data.traffic_tip_enable); ini.WriteInt(L"notify_tip", L"traffic_tip_value", m_general_data.traffic_tip_value); ini.WriteInt(L"notify_tip", L"traffic_tip_unit", m_general_data.traffic_tip_unit); ini.WriteBool(L"notify_tip", L"memory_usage_tip_enable", m_general_data.memory_usage_tip.enable); ini.WriteInt(L"notify_tip", L"memory_tip_value", m_general_data.memory_usage_tip.tip_value); ini.WriteBool(L"notify_tip", L"cpu_temperature_tip_enable", m_general_data.cpu_temp_tip.enable); ini.WriteInt(L"notify_tip", L"cpu_temperature_tip_value", m_general_data.cpu_temp_tip.tip_value); ini.WriteBool(L"notify_tip", L"gpu_temperature_tip_enable", m_general_data.gpu_temp_tip.enable); ini.WriteInt(L"notify_tip", L"gpu_temperature_tip_value", m_general_data.gpu_temp_tip.tip_value); ini.WriteBool(L"notify_tip", L"hdd_temperature_tip_enable", m_general_data.hdd_temp_tip.enable); ini.WriteInt(L"notify_tip", L"hdd_temperature_tip_value", m_general_data.hdd_temp_tip.tip_value); ini.WriteBool(L"notify_tip", L"mainboard_temperature_tip_enable", m_general_data.mainboard_temp_tip.enable); ini.WriteInt(L"notify_tip", L"mainboard_temperature_tip_value", m_general_data.mainboard_temp_tip.tip_value); //任务栏窗口设置 ini.WriteInt(L"task_bar", L"task_bar_back_color", m_taskbar_data.back_color); ini.WriteInt(L"task_bar", L"transparent_color", m_taskbar_data.transparent_color); ini.WriteInt(L"task_bar", L"status_bar_color", m_taskbar_data.status_bar_color); ini.SaveTaskbarWndColors(L"task_bar", L"task_bar_text_color", m_taskbar_data.text_colors); ini.WriteBool(L"task_bar", L"specify_each_item_color", m_taskbar_data.specify_each_item_color); //ini.WriteBool(L"task_bar", L"task_bar_show_cpu_memory", m_cfg_data.m_tbar_show_cpu_memory); ini.WriteInt(L"task_bar", L"tbar_display_item", m_taskbar_data.m_tbar_display_item); ini.SaveFontData(L"task_bar", m_taskbar_data.font); //ini.WriteBool(L"task_bar", L"task_bar_swap_up_down", m_taskbar_data.swap_up_down); ini.WriteString(_T("task_bar"), _T("up_string"), m_taskbar_data.disp_str.Get(TDI_UP)); ini.WriteString(_T("task_bar"), _T("down_string"), m_taskbar_data.disp_str.Get(TDI_DOWN)); ini.WriteString(_T("task_bar"), _T("total_speed_string"), m_taskbar_data.disp_str.Get(TDI_TOTAL_SPEED)); ini.WriteString(_T("task_bar"), _T("cpu_string"), m_taskbar_data.disp_str.Get(TDI_CPU)); ini.WriteString(_T("task_bar"), _T("memory_string"), m_taskbar_data.disp_str.Get(TDI_MEMORY)); ini.WriteString(_T("task_bar"), _T("gpu_string"), m_taskbar_data.disp_str.Get(TDI_GPU_USAGE)); ini.WriteString(_T("task_bar"), _T("cpu_temp_string"), m_taskbar_data.disp_str.Get(TDI_CPU_TEMP)); ini.WriteString(_T("task_bar"), _T("cpu_freq_string"), m_taskbar_data.disp_str.Get(TDI_CPU_FREQ)); ini.WriteString(_T("task_bar"), _T("gpu_temp_string"), m_taskbar_data.disp_str.Get(TDI_GPU_TEMP)); ini.WriteString(_T("task_bar"), _T("hdd_temp_string"), m_taskbar_data.disp_str.Get(TDI_HDD_TEMP)); ini.WriteString(_T("task_bar"), _T("main_board_temp_string"), m_taskbar_data.disp_str.Get(TDI_MAIN_BOARD_TEMP)); ini.WriteString(_T("task_bar"), _T("hdd_string"), m_taskbar_data.disp_str.Get(TDI_HDD_USAGE)); ini.SavePluginDisplayStr(false); ini.WriteBool(L"task_bar", L"task_bar_wnd_on_left", m_taskbar_data.tbar_wnd_on_left); ini.WriteBool(L"task_bar", L"task_bar_wnd_snap", m_taskbar_data.tbar_wnd_snap); ini.WriteBool(L"task_bar", L"task_bar_speed_short_mode", m_taskbar_data.speed_short_mode); ini.WriteBool(L"task_bar", L"unit_byte", m_taskbar_data.unit_byte); ini.WriteInt(L"task_bar", L"task_bar_speed_unit", static_cast(m_taskbar_data.speed_unit)); ini.WriteBool(L"task_bar", L"task_bar_hide_unit", m_taskbar_data.hide_unit); ini.WriteBool(L"task_bar", L"task_bar_hide_percent", m_taskbar_data.hide_percent); ini.WriteBool(L"task_bar", L"value_right_align", m_taskbar_data.value_right_align); ini.WriteBool(L"task_bar", L"horizontal_arrange", m_taskbar_data.horizontal_arrange); ini.WriteBool(L"task_bar", L"show_status_bar", m_taskbar_data.show_status_bar); ini.WriteBool(L"task_bar", L"separate_value_unit_with_space", m_taskbar_data.separate_value_unit_with_space); ini.WriteBool(L"task_bar", L"show_tool_tip", m_taskbar_data.show_tool_tip); ini.WriteInt(L"task_bar", L"digits_number", m_taskbar_data.digits_number); ini.WriteInt(L"task_bar", L"memory_display", static_cast(m_taskbar_data.memory_display)); ini.WriteInt(L"task_bar", L"double_click_action", static_cast(m_taskbar_data.double_click_action)); ini.WriteString(L"task_bar", L"double_click_exe", m_taskbar_data.double_click_exe); ini.WriteBool(L"task_bar", L"cm_graph_type", m_taskbar_data.cm_graph_type); ini.WriteBool(L"task_bar", L"show_graph_dashed_box", m_taskbar_data.show_graph_dashed_box); ini.WriteInt(L"task_bar", L"item_space", m_taskbar_data.item_space); ini.WriteBool(L"task_bar", L"auto_adapt_light_theme", m_taskbar_data.auto_adapt_light_theme); ini.WriteInt(L"task_bar", L"dark_default_style", m_taskbar_data.dark_default_style); ini.WriteInt(L"task_bar", L"light_default_style", m_taskbar_data.light_default_style); ini.WriteBool(L"task_bar", L"auto_set_background_color", m_taskbar_data.auto_set_background_color); ini.WriteString(L"task_bar", L"item_order", m_taskbar_data.item_order.ToString()); ini.WriteString(L"task_bar", L"plugin_display_item", m_taskbar_data.plugin_display_item.ToString()); ini.WriteBool(L"task_bar", L"auto_save_taskbar_color_settings_to_preset", m_taskbar_data.auto_save_taskbar_color_settings_to_preset); ini.WriteBool(L"task_bar", L"show_netspeed_figure", m_taskbar_data.show_netspeed_figure); ini.WriteInt(L"task_bar", L"netspeed_figure_max_value", m_taskbar_data.netspeed_figure_max_value); ini.WriteInt(L"task_bar", L"netspeed_figure_max_value_unit", m_taskbar_data.netspeed_figure_max_value_unit); //其他设置 //ini.WriteBool(L"connection_details", L"show_internet_ip", m_cfg_data.m_show_internet_ip); ini.WriteBool(L"histroy_traffic", L"use_log_scale", m_cfg_data.m_use_log_scale); ini.WriteBool(L"histroy_traffic", L"sunday_first", m_cfg_data.m_sunday_first); ini.WriteInt(L"histroy_traffic", L"view_type", static_cast(m_cfg_data.m_view_type)); ini.WriteBool(_T("other"), _T("no_multistart_warning"), m_no_multistart_warning); ini.WriteBool(_T("other"), _T("exit_when_start_by_restart_manager"), m_exit_when_start_by_restart_manager); ini.WriteBool(_T("other"), _T("debug_log"), m_debug_log); ini.WriteInt(_T("other"), _T("notify_interval"), m_notify_interval); ini.WriteBool(_T("other"), _T("taksbar_transparent_color_enable"), m_taksbar_transparent_color_enable); ini.WriteBool(_T("other"), _T("last_light_mode"), m_last_light_mode); ini.WriteBool(_T("other"), _T("show_mouse_panetrate_tip"), m_show_mouse_panetrate_tip); ini.WriteBool(_T("other"), _T("show_dot_net_notinstalled_tip"), m_show_dot_net_notinstalled_tip); ini.WriteString(L"config", L"plugin_disabled", m_cfg_data.plugin_disabled.ToString()); ini.WriteInt(L"task_bar", L"taskbar_left_space_win11", m_cfg_data.taskbar_left_space_win11); ini.WriteString(L"app", L"version", VERSION); //检查是否保存成功 if (!ini.Save()) { if (m_cannot_save_config_warning) { CString info; info.LoadString(IDS_CONNOT_SAVE_CONFIG_WARNING); info.Replace(_T("<%file_path%>"), m_config_path.c_str()); AfxMessageBox(info, MB_ICONWARNING); } m_cannot_save_config_warning = false; return; } } void CTrafficMonitorApp::LoadPluginDisabledSettings() { CIniHelper ini{ m_config_path }; m_cfg_data.plugin_disabled.FromString(ini.GetString(L"config", L"plugin_disabled", L"")); } void CTrafficMonitorApp::LoadGlobalConfig() { bool portable_mode_default{ false }; wstring global_cfg_path{ m_module_dir + L"global_cfg.ini" }; if (!CCommon::FileExist(global_cfg_path.c_str())) //如果global_cfg.ini不存在,则根据AppData/Roaming/TrafficMonitor目录下是否存在config.ini来判断配置文件的保存位置 { portable_mode_default = !CCommon::FileExist((m_appdata_dir + L"config.ini").c_str()); } CIniHelper ini{ global_cfg_path }; m_general_data.portable_mode = ini.GetBool(L"config", L"portable_mode", portable_mode_default); //执行一次保存操作,以检查当前目录是否有写入权限 m_module_dir_writable = ini.Save(); if (m_module_dir.find(CCommon::GetTemplateDir()) != wstring::npos) //如果当前路径是在Temp目录下,则强制将数据保存到Appdata { m_module_dir_writable = false; } if (!m_module_dir_writable) //如果当前目录没有写入权限,则设置配置保存到AppData目录 { m_general_data.portable_mode = false; } } void CTrafficMonitorApp::SaveGlobalConfig() { CIniHelper ini{ m_module_dir + L"global_cfg.ini" }; ini.WriteBool(L"config", L"portable_mode", m_general_data.portable_mode); //检查是否保存成功 if (!ini.Save()) { //if (m_cannot_save_global_config_warning) //{ // CString info; // info.LoadString(IDS_CONNOT_SAVE_CONFIG_WARNING); // info.Replace(_T("<%file_path%>"), m_module_dir.c_str()); // AfxMessageBox(info, MB_ICONWARNING); //} //m_cannot_save_global_config_warning = false; //return; } } int CTrafficMonitorApp::DPI(int pixel) { return m_dpi * pixel / 96; } void CTrafficMonitorApp::DPI(CRect& rect) { rect.left = DPI(rect.left); rect.right = DPI(rect.right); rect.top = DPI(rect.top); rect.bottom = DPI(rect.bottom); } void CTrafficMonitorApp::DPIFromWindow(CWnd* pWnd) { CWindowDC dc(pWnd); HDC hDC = dc.GetSafeHdc(); m_dpi = GetDeviceCaps(hDC, LOGPIXELSY); } void CTrafficMonitorApp::CheckUpdate(bool message) { if (m_checking_update) //如果还在检查更新,则直接返回 return; CFlagLocker update_locker(m_checking_update); CWaitCursor wait_cursor; wstring version; //程序版本 wstring link; //下载链接 wstring contents_zh_cn; //更新内容(简体中文) wstring contents_en; //更新内容(English) wstring contents_zh_tw; //更新内容(繁体中文) CUpdateHelper update_helper; update_helper.SetUpdateSource(static_cast(m_general_data.update_source)); if (!update_helper.CheckForUpdate()) { if (message) AfxMessageBox(CCommon::LoadText(IDS_CHECK_UPDATE_FAILD), MB_OK | MB_ICONWARNING); return; } version = update_helper.GetVersion(); #ifdef _M_X64 link = update_helper.GetLink64(); #else link = update_helper.GetLink(); #endif contents_zh_cn = update_helper.GetContentsZhCn(); contents_en = update_helper.GetContentsEn(); contents_zh_tw = update_helper.GetContentsZhTw(); if (version.empty() || link.empty()) { if (message) { CString info = CCommon::LoadText(IDS_CHECK_UPDATE_ERROR); info += _T("\r\nrow_data="); info += std::to_wstring(update_helper.IsRowData()).c_str(); AfxMessageBox(info, MB_OK | MB_ICONWARNING); } return; } if (version > VERSION) //如果服务器上的版本大于本地版本 { CString info; //根据语言设置选择对应语言版本的更新内容 int language_code = _ttoi(CCommon::LoadText(IDS_LANGUAGE_CODE)); wstring contents_lan; switch (language_code) { case 2: contents_lan = contents_zh_cn; break; case 3: contents_lan = contents_zh_tw; break; default: contents_lan = contents_en; break; } if (contents_lan.empty()) info.Format(CCommon::LoadText(IDS_UPDATE_AVLIABLE), version.c_str()); else info.Format(CCommon::LoadText(IDS_UPDATE_AVLIABLE2), version.c_str(), contents_lan.c_str()); if (AfxMessageBox(info, MB_YESNO | MB_ICONQUESTION) == IDYES) { ShellExecute(NULL, _T("open"), link.c_str(), NULL, NULL, SW_SHOW); //转到下载链接 } } else { if (message) AfxMessageBox(CCommon::LoadText(IDS_ALREADY_UPDATED), MB_OK | MB_ICONINFORMATION); } } void CTrafficMonitorApp::CheckUpdateInThread(bool message) { AfxBeginThread(CheckUpdateThreadFunc, (LPVOID)message); } UINT CTrafficMonitorApp::CheckUpdateThreadFunc(LPVOID lpParam) { CCommon::SetThreadLanguage(theApp.m_general_data.language); //设置线程语言 theApp.CheckUpdate(lpParam); //检查更新 return 0; } UINT CTrafficMonitorApp::InitOpenHardwareMonitorLibThreadFunc(LPVOID lpParam) { #ifndef WITHOUT_TEMPERATURE CSingleLock sync(&theApp.m_minitor_lib_critical, TRUE); theApp.m_pMonitor = OpenHardwareMonitorApi::CreateInstance(); if (theApp.m_pMonitor == nullptr) { AfxMessageBox(OpenHardwareMonitorApi::GetErrorMessage().c_str(), MB_ICONERROR | MB_OK); } //设置硬件监控的启用状态 theApp.UpdateOpenHardwareMonitorEnableState(); #endif return 0; } bool CTrafficMonitorApp::SetAutoRun(bool auto_run) { //不含温度监控的版本使用添加注册表项的方式实现开机自启动 #ifdef WITHOUT_TEMPERATURE return SetAutoRunByRegistry(auto_run); #else //包含温度监控的版本使用任务计划的方式实现开机自启动 return SetAutoRunByTaskScheduler(auto_run); #endif } bool CTrafficMonitorApp::GetAutoRun(wstring* auto_run_path) { if (auto_run_path != nullptr) auto_run_path->clear(); //不含温度监控的版本使用添加注册表项的方式实现开机自启动 #ifdef WITHOUT_TEMPERATURE CRegKey key; if (key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Run")) != ERROR_SUCCESS) { //打开注册表“Software\\Microsoft\\Windows\\CurrentVersion\\Run”失败,则返回false return false; } wchar_t buff[256]; ULONG size{ 256 }; if (key.QueryStringValue(APP_NAME, buff, &size) == ERROR_SUCCESS) //如果找到了“TrafficMonitor”键 { if (auto_run_path != nullptr) { //保存路径 *auto_run_path = buff; //去掉前后的引号 if (auto_run_path->front() == L'\"') *auto_run_path = auto_run_path->substr(1); if (auto_run_path->back() = L'\"') auto_run_path->pop_back(); } return (m_module_path_reg == buff); //如果“TrafficMonitor”的值是当前程序的路径,就返回true,否则返回false } else { return false; //没有找到“TrafficMonitor”键,返回false } #else //包含温度监控的版本使用任务计划的方式实现开机自启动 return is_auto_start_task_active_for_this_user(auto_run_path); #endif } bool CTrafficMonitorApp::SetAutoRunByRegistry(bool auto_run) { CRegKey key; //打开注册表项 if (key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Run")) != ERROR_SUCCESS) { AfxMessageBox(CCommon::LoadText(IDS_AUTORUN_FAILED_NO_KEY), MB_OK | MB_ICONWARNING); return false; } if (auto_run) //写入注册表项 { //通过注册表设置开机自启动项时删除计划任务中的自启动项 SetAutoRunByTaskScheduler(false); if (key.SetStringValue(APP_NAME, m_module_path_reg.c_str()) != ERROR_SUCCESS) { AfxMessageBox(CCommon::LoadText(IDS_AUTORUN_FAILED_NO_ACCESS), MB_OK | MB_ICONWARNING); return false; } } else //删除注册表项 { //删除前先检查注册表项是否存在,如果不存在,则直接返回 wchar_t buff[256]; ULONG size{ 256 }; if (key.QueryStringValue(APP_NAME, buff, &size) != ERROR_SUCCESS) return false; if (key.DeleteValue(APP_NAME) != ERROR_SUCCESS) { AfxMessageBox(CCommon::LoadText(IDS_AUTORUN_DELETE_FAILED), MB_OK | MB_ICONWARNING); return false; } } return true; } bool CTrafficMonitorApp::SetAutoRunByTaskScheduler(bool auto_run) { bool succeed = delete_auto_start_task_for_this_user(); //先删除开机自启动 if (auto_run) { //通过计划任务设置开机自启动项时删除注册表中的自启动项 SetAutoRunByRegistry(false); succeed = create_auto_start_task_for_this_user(true); } return succeed; } CString CTrafficMonitorApp::GetSystemInfoString() { CString info; info += _T("System Info:\r\n"); CString strTmp; strTmp.Format(_T("Windows Version: %d.%d build %d\r\n"), m_win_version.GetMajorVersion(), m_win_version.GetMinorVersion(), m_win_version.GetBuildNumber()); info += strTmp; strTmp.Format(_T("DPI: %d"), m_dpi); info += strTmp; info += _T("\r\n"); info += _T("Version: "); info += VERSION; info += _T(" "); #ifdef _M_X64 info += _T("x64"); #else info += _T("x86"); #endif #ifdef WITHOUT_TEMPERATURE info += CCommon::LoadText(_T(" ("), IDS_WITHOUT_TEMPERATURE, _T(")")); #endif info += _T("\r\nLast compiled date: "); info += CCommon::GetLastCompileTime(); return info; } void CTrafficMonitorApp::InitMenuResourse() { //载入菜单 m_main_menu.LoadMenu(IDR_MENU1); m_taskbar_menu.LoadMenu(IDR_TASK_BAR_MENU); //为菜单项添加图标 //主窗口右键菜单 CMenuIcon::AddIconToMenuItem(m_main_menu.GetSubMenu(0)->GetSafeHmenu(), 0, TRUE, GetMenuIcon(IDI_CONNECTION)); CMenuIcon::AddIconToMenuItem(m_main_menu.GetSubMenu(0)->GetSafeHmenu(), 11, TRUE, GetMenuIcon(IDI_FUNCTION)); CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_NETWORK_INFO, FALSE, GetMenuIcon(IDI_INFO)); if (!m_win_version.IsWindows11OrLater()) CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_ALWAYS_ON_TOP, FALSE, GetMenuIcon(IDI_PIN)); if (!m_win_version.IsWindows11OrLater()) CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_MOUSE_PENETRATE, FALSE, GetMenuIcon(IDI_MOUSE)); if (!m_win_version.IsWindows11OrLater()) CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_LOCK_WINDOW_POS, FALSE, GetMenuIcon(IDI_LOCK)); //if (!m_win_version.IsWindows11OrLater()) // CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_SHOW_NOTIFY_ICON, FALSE, GetMenuIcon(IDI_NOTIFY)); if (!m_win_version.IsWindows11OrLater()) CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_SHOW_CPU_MEMORY, FALSE, GetMenuIcon(IDI_MORE)); if (!m_win_version.IsWindows11OrLater()) CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_SHOW_TASK_BAR_WND, FALSE, GetMenuIcon(IDI_TASKBAR_WINDOW)); if (!m_win_version.IsWindows11OrLater()) CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_SHOW_MAIN_WND, FALSE, GetMenuIcon(IDI_MAIN_WINDOW)); CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_CHANGE_SKIN, FALSE, GetMenuIcon(IDI_SKIN)); CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_CHANGE_NOTIFY_ICON, FALSE, GetMenuIcon(IDI_NOTIFY)); CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_TRAFFIC_HISTORY, FALSE, GetMenuIcon(IDI_STATISTICS)); CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_PLUGIN_MANAGE, FALSE, GetMenuIcon(IDI_PLUGINS)); CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_OPTIONS, FALSE, GetMenuIcon(IDI_SETTINGS)); CMenuIcon::AddIconToMenuItem(m_main_menu.GetSubMenu(0)->GetSafeHmenu(), 14, TRUE, GetMenuIcon(IDI_HELP)); CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_HELP, FALSE, GetMenuIcon(IDI_HELP)); CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_APP_ABOUT, FALSE, GetMenuIcon(IDR_MAINFRAME)); CMenuIcon::AddIconToMenuItem(m_main_menu.GetSafeHmenu(), ID_APP_EXIT, FALSE, GetMenuIcon(IDI_EXIT)); //任务栏窗口右键菜单 CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSubMenu(0)->GetSafeHmenu(), 0, TRUE, GetMenuIcon(IDI_CONNECTION)); CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSafeHmenu(), ID_NETWORK_INFO, FALSE, GetMenuIcon(IDI_INFO)); CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSafeHmenu(), ID_TRAFFIC_HISTORY, FALSE, GetMenuIcon(IDI_STATISTICS)); CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSafeHmenu(), ID_DISPLAY_SETTINGS, FALSE, GetMenuIcon(IDI_ITEM)); //if (!m_win_version.IsWindows11OrLater()) // CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSafeHmenu(), ID_SHOW_NOTIFY_ICON, FALSE, GetMenuIcon(IDI_NOTIFY)); if (!m_win_version.IsWindows11OrLater()) CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSafeHmenu(), ID_SHOW_MAIN_WND, FALSE, GetMenuIcon(IDI_MAIN_WINDOW)); CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSafeHmenu(), ID_SHOW_TASK_BAR_WND, FALSE, GetMenuIcon(IDI_CLOSE)); CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSafeHmenu(), ID_OPEN_TASK_MANAGER, FALSE, GetMenuIcon(IDI_TASK_MANAGER)); CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSafeHmenu(), ID_OPTIONS2, FALSE, GetMenuIcon(IDI_SETTINGS)); CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSubMenu(0)->GetSafeHmenu(), 12, TRUE, GetMenuIcon(IDI_HELP)); CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSafeHmenu(), ID_HELP, FALSE, GetMenuIcon(IDI_HELP)); CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSafeHmenu(), ID_APP_ABOUT, FALSE, GetMenuIcon(IDR_MAINFRAME)); CMenuIcon::AddIconToMenuItem(m_taskbar_menu.GetSafeHmenu(), ID_APP_EXIT, FALSE, GetMenuIcon(IDI_EXIT)); #ifdef _DEBUG m_main_menu.GetSubMenu(0)->AppendMenu(MF_BYCOMMAND, ID_CMD_TEST, _T("Test Command")); #endif } HICON CTrafficMonitorApp::GetMenuIcon(UINT id) { auto iter = m_menu_icons.find(id); if (iter != m_menu_icons.end()) { return iter->second; } else { HICON hIcon = CCommon::LoadIconResource(id, DPI(16)); m_menu_icons[id] = hIcon; return hIcon; } } void CTrafficMonitorApp::AutoSelectNotifyIcon() { if (m_win_version.GetMajorVersion() >= 10) { bool light_mode = CWindowsSettingHelper::IsWindows10LightTheme(); if (light_mode) //浅色模式下,如果图标是白色,则改成黑色 { if (m_cfg_data.m_notify_icon_selected == 0) m_cfg_data.m_notify_icon_selected = 4; if (m_cfg_data.m_notify_icon_selected == 1) m_cfg_data.m_notify_icon_selected = 5; } else //深色模式下,如果图标是黑色,则改成白色 { if (m_cfg_data.m_notify_icon_selected == 4) m_cfg_data.m_notify_icon_selected = 0; if (m_cfg_data.m_notify_icon_selected == 5) m_cfg_data.m_notify_icon_selected = 1; } } } // 唯一的一个 CTrafficMonitorApp 对象 CTrafficMonitorApp theApp; // CTrafficMonitorApp 初始化 BOOL CTrafficMonitorApp::InitInstance() { //替换掉对话框程序的默认类名 WNDCLASS wc; ::GetClassInfo(AfxGetInstanceHandle(), _T("#32770"), &wc); //MFC默认的所有对话框的类名为#32770 wc.lpszClassName = APP_CLASS_NAME; //将对话框的类名修改为新类名 AfxRegisterClass(&wc); //设置配置文件的路径 wchar_t path[MAX_PATH]; GetModuleFileNameW(NULL, path, MAX_PATH); m_module_path = path; if (m_module_path.find(L' ') != wstring::npos) { //如果路径中有空格,则在程序路径前后添加双引号 m_module_path_reg = L'\"'; m_module_path_reg += m_module_path; m_module_path_reg += L'\"'; } else { m_module_path_reg = m_module_path; } m_module_dir = CCommon::GetModuleDir(); m_system_dir = CCommon::GetSystemDir(); m_appdata_dir = CCommon::GetAppDataConfigDir(); LoadGlobalConfig(); #ifdef _DEBUG m_config_dir = L".\\"; m_skin_path = L".\\skins"; #else if (m_general_data.portable_mode) m_config_dir = m_module_dir; else m_config_dir = m_appdata_dir; m_skin_path = m_module_dir + L"skins"; #endif //AppData里面的程序配置文件路径 m_config_path = m_config_dir + L"config.ini"; m_history_traffic_path = m_config_dir + L"history_traffic.dat"; m_log_path = m_config_dir + L"error.log"; //#ifndef _DEBUG // //原来的、程序所在目录下的配置文件的路径 // wstring config_path_old = m_module_dir + L"config.ini"; // wstring history_traffic_path_old = m_module_dir + L"history_traffic.dat"; // wstring log_path_old = m_module_dir + L"error.log"; // //如果程序所在目录下含有配置文件,则将其移动到AppData对应的目录下面 // CCommon::MoveAFile(config_path_old.c_str(), m_config_path.c_str()); // CCommon::MoveAFile(history_traffic_path_old.c_str(), m_history_traffic_path.c_str()); // CCommon::MoveAFile(log_path_old.c_str(), m_log_path.c_str()); //#endif // !_DEBUG bool is_windows10_fall_creator = m_win_version.IsWindows10FallCreatorOrLater(); //载入插件 LoadPluginDisabledSettings(); m_plugins.LoadPlugins(); //向插件传递配置文件的路径 wstring plugin_dir; #ifdef _DEBUG plugin_dir = m_module_dir; #else plugin_dir = m_config_dir; #endif plugin_dir += L"plugins\\"; m_plugins.EnumPlugin([&](ITMPlugin* plugin) { if (plugin->GetAPIVersion() >= 2) { CreateDirectory(plugin_dir.c_str(), NULL); //如果plugins不存在,则创建它 plugin->OnExtenedInfo(ITMPlugin::EI_CONFIG_DIR, plugin_dir.c_str()); } }); //从ini文件载入设置 LoadConfig(); //初始化界面语言 CCommon::SetThreadLanguage(m_general_data.language); //wstring cmd_line{ m_lpCmdLine }; //bool is_restart{ cmd_line.find(L"RestartByRestartManager") != wstring::npos }; //如果命令行参数中含有字符串“RestartByRestartManager”则说明程序是被Windows重新启动的 ////bool when_start{ CCommon::WhenStart(m_no_multistart_warning_time) }; //if (m_exit_when_start_by_restart_manager && is_restart && is_windows10_fall_creator) //当前Windows版本是秋季创意者更新时,如果程序被重新启动,则直接退出程序 //{ // //AfxMessageBox(_T("调试信息:程序已被Windows的重启管理器重新启动。")); // return FALSE; //} //检查是否已有实例正在运行 LPCTSTR mutex_name{}; #ifdef _DEBUG mutex_name = _T("TrafficMonitor-e8Ahk24HP6JC8hDy"); #else mutex_name = _T("TrafficMonitor-1419J3XLKL1w8OZc"); #endif HANDLE hMutex = ::CreateMutex(NULL, TRUE, mutex_name); if (hMutex != NULL) { if (GetLastError() == ERROR_ALREADY_EXISTS) { //char buff[128]; //string cmd_line_str{ CCommon::UnicodeToStr(cmd_line.c_str()) }; //sprintf_s(buff, "when_start=%d, m_no_multistart_warning=%d, cmd_line=%s", when_start, m_no_multistart_warning, cmd_line_str.c_str()); //CCommon::WriteLog(buff, _T(".\\start.log")); if (!m_no_multistart_warning) { //查找已存在TrafficMonitor进程的主窗口的句柄 HWND exist_handel = ::FindWindow(APP_CLASS_NAME, NULL); if (exist_handel != NULL) { //弹出“TrafficMonitor已在运行”对话框 CAppAlreadyRuningDlg dlg(exist_handel); dlg.DoModal(); } else { AfxMessageBox(CCommon::LoadText(IDS_AN_INSTANCE_RUNNING)); } } return FALSE; } } m_taskbar_default_style.LoadConfig(); //SaveConfig(); // 如果一个运行在 Windows XP 上的应用程序清单指定要 // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, //则需要 InitCommonControlsEx()。 否则,将无法创建窗口。 INITCOMMONCONTROLSEX InitCtrls; InitCtrls.dwSize = sizeof(InitCtrls); // 将它设置为包括所有要在应用程序中使用的 // 公共控件类。 InitCtrls.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&InitCtrls); CWinApp::InitInstance(); AfxEnableControlContainer(); // 创建 shell 管理器,以防对话框包含 // 任何 shell 树视图控件或 shell 列表视图控件。 CShellManager* pShellManager = new CShellManager; // 激活“Windows Native”视觉管理器,以便在 MFC 控件中启用主题 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows)); // 标准初始化 // 如果未使用这些功能并希望减小 // 最终可执行文件的大小,则应移除下列 // 不需要的特定初始化例程 // 更改用于存储设置的注册表项 // TODO: 应适当修改该字符串, // 例如修改为公司或组织名 //SetRegistryKey(_T("应用程序向导生成的本地应用程序")); //暂不使用注册表保存数据 //启动时检查更新 #ifndef _DEBUG //DEBUG下不在启动时检查更新 if (m_general_data.check_update_when_start) { CheckUpdateInThread(false); } #endif // !_DEBUG #ifndef WITHOUT_TEMPERATURE //检测是否安装.net framework 4.5 if (!CWindowsSettingHelper::IsDotNetFramework4Point5Installed()) { if (theApp.m_show_dot_net_notinstalled_tip) { if (AfxMessageBox(CCommon::LoadText(IDS_DOTNET_NOT_INSTALLED_TIP), MB_OKCANCEL | MB_ICONWARNING) == IDCANCEL) //点击“取消”不再提示 { theApp.m_show_dot_net_notinstalled_tip = false; SaveConfig(); } } } else { //如果没有开启任何一项的硬件监控,则不初始化OpenHardwareMonitor if (theApp.m_general_data.IsHardwareEnable(HI_CPU) || theApp.m_general_data.IsHardwareEnable(HI_GPU) || theApp.m_general_data.IsHardwareEnable(HI_HDD) || theApp.m_general_data.IsHardwareEnable(HI_MBD)) { //启动初始化OpenHardwareMonitor的线程。由于OpenHardwareMonitor初始化需要一定的时间,为了防止启动时程序卡顿,将其放到后台线程中处理 InitOpenHardwareLibInThread(); } } #endif //执行测试代码 #ifdef _DEBUG CTest::Test(); #endif SendSettingsToPlugin(); CTrafficMonitorDlg dlg; m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: 在此放置处理何时用 // “确定”来关闭对话框的代码 } else if (nResponse == IDCANCEL) { // TODO: 在此放置处理何时用 // “取消”来关闭对话框的代码 } else if (nResponse == -1) { TRACE(traceAppMsg, 0, "警告: 对话框创建失败,应用程序将意外终止。\n"); TRACE(traceAppMsg, 0, "警告: 如果您在对话框上使用 MFC 控件,则无法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n"); } // 删除上面创建的 shell 管理器。 if (pShellManager != NULL) { delete pShellManager; } #ifndef _AFXDLL ControlBarCleanUp(); #endif // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, // 而不是启动应用程序的消息泵。 return FALSE; } void CTrafficMonitorApp::InitOpenHardwareLibInThread() { #ifndef WITHOUT_TEMPERATURE AfxBeginThread(InitOpenHardwareMonitorLibThreadFunc, NULL); #endif } void CTrafficMonitorApp::UpdateOpenHardwareMonitorEnableState() { #ifndef WITHOUT_TEMPERATURE if (m_pMonitor != nullptr) { CSingleLock sync(&theApp.m_minitor_lib_critical, TRUE); m_pMonitor->SetCpuEnable(m_general_data.IsHardwareEnable(HI_CPU)); m_pMonitor->SetGpuEnable(m_general_data.IsHardwareEnable(HI_GPU)); m_pMonitor->SetHddEnable(m_general_data.IsHardwareEnable(HI_HDD)); m_pMonitor->SetMainboardEnable(m_general_data.IsHardwareEnable(HI_MBD)); } #endif } //void CTrafficMonitorApp::UpdateTaskbarWndMenu() //{ // //获取“显示设置”子菜单 // CMenu* pMenu = m_taskbar_menu.GetSubMenu(0)->GetSubMenu(5); // ASSERT(pMenu != nullptr); // if (pMenu != nullptr) // { // //将ID_SHOW_MEMORY_USAGE后面的所有菜单项删除 // if (pMenu->GetMenuItemCount() > 4) // { // int start_pos = CCommon::GetMenuItemPosition(pMenu, ID_SHOW_MEMORY_USAGE) + 1; // while (pMenu->GetMenuItemCount() > start_pos) // { // pMenu->DeleteMenu(start_pos, MF_BYPOSITION); // } // } // // //添加温度相关菜单项 //#ifndef WITHOUT_TEMPERATURE // if (m_general_data.IsHardwareEnable(HI_GPU)) // pMenu->AppendMenu(MF_STRING | MF_ENABLED, ID_SHOW_GPU, CCommon::LoadText(IDS_GPU_USAGE)); // if (m_general_data.IsHardwareEnable(HI_CPU)) // pMenu->AppendMenu(MF_STRING | MF_ENABLED, ID_SHOW_CPU_TEMPERATURE, CCommon::LoadText(IDS_CPU_TEMPERATURE)); // if (m_general_data.IsHardwareEnable(HI_GPU)) // pMenu->AppendMenu(MF_STRING | MF_ENABLED, ID_SHOW_GPU_TEMPERATURE, CCommon::LoadText(IDS_GPU_TEMPERATURE)); // if (m_general_data.IsHardwareEnable(HI_HDD)) // pMenu->AppendMenu(MF_STRING | MF_ENABLED, ID_SHOW_HDD_TEMPERATURE, CCommon::LoadText(IDS_HDD_TEMPERATURE)); // if (m_general_data.IsHardwareEnable(HI_MBD)) // pMenu->AppendMenu(MF_STRING | MF_ENABLED, ID_SHOW_MAIN_BOARD_TEMPERATURE, CCommon::LoadText(IDS_MAINBOARD_TEMPERATURE)); // if (m_general_data.IsHardwareEnable(HI_HDD)) // pMenu->AppendMenu(MF_STRING | MF_ENABLED, ID_SHOW_HDD, CCommon::LoadText(IDS_HDD_USAGE)); //#endif // // pMenu->AppendMenu(MF_STRING | MF_ENABLED, ID_SHOW_TOTAL_SPEED, CCommon::LoadText(IDS_TOTAL_NET_SPEED)); // // //添加插件菜单项 // if (!m_plugins.GetPluginItems().empty()) // pMenu->AppendMenu(MF_SEPARATOR); // int plugin_index = 0; // for (const auto& plugin_item : m_plugins.GetPluginItems()) // { // pMenu->AppendMenu(MF_STRING | MF_ENABLED, ID_SHOW_PLUGIN_ITEM_START + plugin_index, plugin_item->GetItemName()); // plugin_index++; // } // } //} bool CTrafficMonitorApp::IsForceShowNotifyIcon() { return ((!m_cfg_data.m_show_task_bar_wnd /*|| m_win_version.IsWindows11OrLater()*/) && (m_cfg_data.m_hide_main_window || m_main_wnd_data.m_mouse_penetrate)); //如果没有显示任务栏窗口,且隐藏了主窗口或设置了鼠标穿透,则禁用“显示通知区图标”菜单项 } std::wstring CTrafficMonitorApp::GetPlauginTooltipInfo() const { std::wstring tip_info; for (const auto& item : m_plugins.GetPlugins()) { if (item.plugin != nullptr && item.plugin->GetAPIVersion() >= 2) { std::wstring plugin_tooltip = item.plugin->GetTooltipInfo(); if (!plugin_tooltip.empty()) { tip_info += L"\r\n"; tip_info += plugin_tooltip.c_str(); } } } return tip_info; } bool CTrafficMonitorApp::IsTaksbarItemDisplayed(CommonDisplayItem item) const { if (item.is_plugin) { if (item.plugin_item != nullptr) return m_taskbar_data.plugin_display_item.Contains(item.plugin_item->GetItemId()); } else { return m_taskbar_data.m_tbar_display_item & item.item_type; } return false; } void CTrafficMonitorApp::SendSettingsToPlugin() { for (const auto& plugin_info : m_plugins.GetPlugins()) { if (plugin_info.plugin != nullptr && plugin_info.plugin->GetAPIVersion() >= 2) { plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_NAIN_WND_NET_SPEED_SHORT_MODE, std::to_wstring(m_main_wnd_data.speed_short_mode).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_MAIN_WND_SPERATE_WITH_SPACE, std::to_wstring(m_main_wnd_data.separate_value_unit_with_space).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_MAIN_WND_UNIT_BYTE, std::to_wstring(m_main_wnd_data.unit_byte).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_MAIN_WND_UNIT_SELECT, std::to_wstring(static_cast(m_main_wnd_data.speed_unit)).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_MAIN_WND_NOT_SHOW_UNIT, std::to_wstring(m_main_wnd_data.hide_unit).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_MAIN_WND_NOT_SHOW_PERCENT, std::to_wstring(m_main_wnd_data.hide_percent).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_TASKBAR_WND_NET_SPEED_SHORT_MODE, std::to_wstring(m_taskbar_data.speed_short_mode).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_TASKBAR_WND_SPERATE_WITH_SPACE, std::to_wstring(m_taskbar_data.separate_value_unit_with_space).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_TASKBAR_WND_VALUE_RIGHT_ALIGN, std::to_wstring(m_taskbar_data.value_right_align).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_TASKBAR_WND_NET_SPEED_WIDTH, std::to_wstring(m_taskbar_data.digits_number).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_TASKBAR_WND_UNIT_BYTE, std::to_wstring(m_taskbar_data.unit_byte).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_TASKBAR_WND_UNIT_SELECT, std::to_wstring(static_cast(m_taskbar_data.speed_unit)).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_TASKBAR_WND_NOT_SHOW_UNIT, std::to_wstring(m_taskbar_data.hide_unit).c_str()); plugin_info.plugin->OnExtenedInfo(ITMPlugin::EI_TASKBAR_WND_NOT_SHOW_PERCENT, std::to_wstring(m_taskbar_data.hide_percent).c_str()); } } } void CTrafficMonitorApp::OnHelp() { // TODO: 在此添加命令处理程序代码 ShellExecute(NULL, _T("open"), _T("https://github.com/zhongyang219/TrafficMonitor/wiki"), NULL, NULL, SW_SHOW); } void CTrafficMonitorApp::OnFrequentyAskedQuestions() { // TODO: 在此添加命令处理程序代码 CString url_domain; if (static_cast(m_general_data.update_source) == CUpdateHelper::UpdateSource::GiteeSource) url_domain = _T("gitee.com"); else url_domain = _T("github.com"); CString language_code{ CCommon::LoadText(IDS_LANGUAGE_CODE) }; CString file_name; if (language_code == _T("2")) file_name = _T("Help.md"); else file_name = _T("Help_en-us.md"); CString url; url.Format(_T("https://%s/zhongyang219/TrafficMonitor/blob/master/%s"), url_domain.GetString(), file_name.GetString()); ShellExecute(NULL, _T("open"), url, NULL, NULL, SW_SHOW); } void CTrafficMonitorApp::OnUpdateLog() { // TODO: 在此添加命令处理程序代码 CString url_domain; if (static_cast(m_general_data.update_source) == CUpdateHelper::UpdateSource::GiteeSource) url_domain = _T("gitee.com"); else url_domain = _T("github.com"); CString language_code{ CCommon::LoadText(IDS_LANGUAGE_CODE) }; CString file_name; if (language_code == _T("2")) file_name = _T("update_log.md"); else if (language_code == _T("3")) file_name = _T("update_log_zh-tw.md"); else file_name = _T("update_log_en-us.md"); CString url; url.Format(_T("https://%s/zhongyang219/TrafficMonitor/blob/master/UpdateLog/%s"), url_domain.GetString(), file_name.GetString()); ShellExecute(NULL, _T("open"), url, NULL, NULL, SW_SHOW); } ================================================ FILE: TrafficMonitor/TrafficMonitor.h ================================================  // TrafficMonitor.h : PROJECT_NAME 应用程序的主头文件 // #pragma once #ifndef __AFXWIN_H__ #error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件" #endif #include "resource.h" // 主符号 #include "Common.h" #include "IniHelper.h" #include "WinVersionHelper.h" #include "SimpleXML.h" #include "TaskbarDefaultStyle.h" #include #include "OpenHardwareMonitor/OpenHardwareMonitorApi.h" #include "PluginManager.h" // CTrafficMonitorApp: // 有关此类的实现,请参阅 TrafficMonitor.cpp // class CTrafficMonitorApp : public CWinApp { public: //各种路径 static CTrafficMonitorApp* self; wstring m_module_dir; //程序exe文件的目录 wstring m_appdata_dir; wstring m_module_path; //程序exe文件的路径 wstring m_module_path_reg; //用于作为写入注册表开机自项的exe文件的路径(如果路径中有空格,加上引号) wstring m_config_path; wstring m_history_traffic_path; wstring m_log_path; wstring m_skin_path; wstring m_system_dir; wstring m_config_dir; //以下数据定义为App类中的公共成员,以便于在主对话框和任务栏窗口中都能访问 unsigned __int64 m_in_speed{}; //下载速度 unsigned __int64 m_out_speed{}; //上传速度 int m_cpu_usage{ -1 }; //CPU利用率 int m_memory_usage{ -1 }; //内存利用率 int m_used_memory{}; //可用物理内存(单位为KB) int m_total_memory{}; //物理内存总量(单位为KB) float m_cpu_temperature{ -1 }; //CPU温度 float m_cpu_freq{ -1 }; //CPU 频率 float m_gpu_temperature{ -1 }; //显卡温度 float m_hdd_temperature{ -1 }; //硬盘温度 float m_main_board_temperature{ -1 }; //主板温度 int m_gpu_usage{ -1 }; //显卡利用率 int m_hdd_usage{ -1 }; //硬盘利用率 unsigned __int64 m_today_up_traffic{}; //今天已使用的上传流量 unsigned __int64 m_today_down_traffic{}; //今天已使用的下载流量 bool m_cannot_save_config_warning{ true }; //指示是否会在无法保存设置时弹出提示框 bool m_cannot_save_global_config_warning{ true }; //指示是否会在无法保存设置时弹出提示框 bool m_module_dir_writable{ true }; //指示程序所在目录是否可写 //选项设置数据 MainWndSettingData m_main_wnd_data; TaskBarSettingData m_taskbar_data; GeneralSettingData m_general_data; //其他设置数据 MainConfigData m_cfg_data; int m_notify_interval; //弹出通知消息的时间间隔 bool m_debug_log{}; bool m_taksbar_transparent_color_enable{}; bool m_last_light_mode{}; bool m_show_mouse_panetrate_tip{}; //是否显示开启“鼠标穿透”时的提示消息。 bool m_show_dot_net_notinstalled_tip{}; bool m_is_windows11_taskbar{ false }; //是否为Windows11的任务栏 //bool m_is_windows10_fall_creator; CWinVersionHelper m_win_version; //当前Windows的版本 HICON m_notify_icons[MAX_NOTIFY_ICON]; CTaskbarDefaultStyle m_taskbar_default_style; CPluginManager m_plugins; CMenu m_main_menu; CMenu m_taskbar_menu; #ifndef WITHOUT_TEMPERATURE //OpenHardwareMonitor 接口的指针 std::shared_ptr m_pMonitor{}; #endif // !WITHOUT_TEMPERATURE CCriticalSection m_minitor_lib_critical; //用于访问OpenHardwareMonitor进行线程同步的临界区对象 //CCriticalSection m_lftable_critical; //用于访问LfTable2进行线程同步的临界区对象 public: CTrafficMonitorApp(); void LoadConfig(); void SaveConfig(); void LoadPluginDisabledSettings(); void LoadGlobalConfig(); void SaveGlobalConfig(); int DPI(int pixel); void DPI(CRect& rect); void DPIFromWindow(CWnd* pWnd); int GetDpi() const { return m_dpi; } void SetDPI(int dpi) { m_dpi = dpi; } void CheckUpdate(bool message); //检查更新,如果message为true,则在检查时弹出提示信息 void CheckUpdateInThread(bool message); //在后台线程中检查更新 //启动时检查更新线程函数 static UINT CheckUpdateThreadFunc(LPVOID lpParam); static UINT InitOpenHardwareMonitorLibThreadFunc(LPVOID lpParam); bool SetAutoRun(bool auto_run); bool GetAutoRun(wstring* auto_run_path); //判断是否开机自动进行,如果是,将开机自动运行的路径写入auto_run_path bool SetAutoRunByRegistry(bool auto_run); //通过注册表实现开机自启动 bool SetAutoRunByTaskScheduler(bool auto_run); //通过任务计划实现开机自启动 //获取系统信息文本 CString GetSystemInfoString(); void InitMenuResourse(); //获取一个图标资源,如果资源还未加载,会自动加载。 //由于本函数中使用了CTrafficMonitorApp::DPI函数,因此本函数必须确保在CTrafficMonitorApp::DPIFromWindow之后调用 HICON GetMenuIcon(UINT id); void AutoSelectNotifyIcon(); bool IsCheckingForUpdate() const { return m_checking_update; } //是否正在检查更新 void InitOpenHardwareLibInThread(); //开启一个后台线程初始化OpenHardwareMonitor void UpdateOpenHardwareMonitorEnableState(); //更新硬件监控的启用/禁用状态 //void UpdateTaskbarWndMenu(); //更新任务栏窗口右键菜单 bool IsForceShowNotifyIcon(); //是否需要强制显示通知区图标 std::wstring GetPlauginTooltipInfo() const; bool IsTaksbarItemDisplayed(CommonDisplayItem item) const; void SendSettingsToPlugin(); //向所有插件发送当前的选项设置 private: //int m_no_multistart_warning_time{}; //用于设置在开机后多长时间内不弹出“已经有一个程序正在运行”的警告提示 bool m_no_multistart_warning{}; //如果为false,则永远都不会弹出“已经有一个程序正在运行”的警告提示 bool m_exit_when_start_by_restart_manager{ true }; //如果程序被Windows重启管理器重新启动,则退出程序 int m_dpi{ 96 }; bool m_checking_update{ false }; //是否正在检查更新 std::map m_menu_icons; //菜单图标资源。key是图标资源的ID,vlaue是图标的句柄 // 重写 public: virtual BOOL InitInstance(); // 实现 DECLARE_MESSAGE_MAP() afx_msg void OnHelp(); afx_msg void OnFrequentyAskedQuestions(); afx_msg void OnUpdateLog(); }; extern CTrafficMonitorApp theApp; ================================================ FILE: TrafficMonitor/TrafficMonitor.vcxproj ================================================  Debug (lite) Win32 Debug (lite) x64 Debug Win32 Release (lite) Win32 Release (lite) x64 Release Win32 Debug x64 Release x64 {09483BED-B1E9-4827-8120-A18302C84AA8} TrafficMonitor 10.0 MFCProj Application true v142 Unicode Dynamic Application true v142 Unicode Dynamic Application false v142 true Unicode Dynamic Application false v142 true Unicode Dynamic Application true v142 Unicode Dynamic Application true v142 Unicode Dynamic Application false v142 true Unicode Dynamic Application false v142 true Unicode Dynamic true $(SolutionDir)Bin\$(Configuration)\ $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)lib\;$(OutDir);$(LibraryPath) true $(SolutionDir)Bin\$(Configuration)\ $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)lib\;$(OutDir);$(LibraryPath) true $(SolutionDir)Bin\$(Platform)\$(Configuration)\ $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)lib\x64;$(OutDir);$(LibraryPath) true $(SolutionDir)Bin\$(Platform)\$(Configuration)\ $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)lib\x64;$(OutDir);$(LibraryPath) false $(SolutionDir)Bin\$(Configuration)\ $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)lib\;$(OutDir);$(LibraryPath) false $(SolutionDir)Bin\$(Configuration)\ $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)lib\;$(OutDir);$(LibraryPath) false $(SolutionDir)Bin\$(Platform)\$(Configuration)\ $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)lib\x64;$(OutDir);$(LibraryPath) false $(SolutionDir)Bin\$(Platform)\$(Configuration)\ $(ProjectDir)..\include;$(IncludePath) $(SolutionDir)lib\x64;$(OutDir);$(LibraryPath) Use Level3 Disabled WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) true false Windows OpenHardwareMonitorApi.lib;%(AdditionalDependencies) RequireAdministrator false true _DEBUG;%(PreprocessorDefinitions) 0x0804 _DEBUG;%(PreprocessorDefinitions) $(IntDir);%(AdditionalIncludeDirectories) print_compile_time.bat Use Level3 Disabled WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions);WITHOUT_TEMPERATURE true false Windows %(AdditionalDependencies) false true _DEBUG;%(PreprocessorDefinitions) 0x0804 _DEBUG;%(PreprocessorDefinitions) $(IntDir);%(AdditionalIncludeDirectories) print_compile_time.bat Use Level3 Disabled _WINDOWS;_DEBUG;%(PreprocessorDefinitions) true Windows OpenHardwareMonitorApi.lib;%(AdditionalDependencies) RequireAdministrator false true _DEBUG;%(PreprocessorDefinitions) 0x0804 _DEBUG;%(PreprocessorDefinitions) $(IntDir);%(AdditionalIncludeDirectories) print_compile_time.bat Use Level3 Disabled _WINDOWS;_DEBUG;%(PreprocessorDefinitions);WITHOUT_TEMPERATURE true Windows %(AdditionalDependencies) false true _DEBUG;%(PreprocessorDefinitions) 0x0804 _DEBUG;%(PreprocessorDefinitions) $(IntDir);%(AdditionalIncludeDirectories) print_compile_time.bat Level3 Use MaxSpeed true true WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) true $(ExternalCompilerOptions) %(AdditionalOptions) Windows true true OpenHardwareMonitorApi.lib;%(AdditionalDependencies) RequireAdministrator false true NDEBUG;%(PreprocessorDefinitions) 0x0804 NDEBUG;%(PreprocessorDefinitions) $(IntDir);%(AdditionalIncludeDirectories) print_compile_time.bat Level3 Use MaxSpeed true true WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions);WITHOUT_TEMPERATURE true $(ExternalCompilerOptions) %(AdditionalOptions) Windows true true %(AdditionalDependencies) false true NDEBUG;%(PreprocessorDefinitions) 0x0804 NDEBUG;%(PreprocessorDefinitions) $(IntDir);%(AdditionalIncludeDirectories) print_compile_time.bat Level3 Use MaxSpeed true true _WINDOWS;NDEBUG;%(PreprocessorDefinitions) true Windows true true OpenHardwareMonitorApi.lib;%(AdditionalDependencies) RequireAdministrator false true NDEBUG;%(PreprocessorDefinitions) 0x0804 NDEBUG;%(PreprocessorDefinitions) $(IntDir);%(AdditionalIncludeDirectories) print_compile_time.bat Level3 Use MaxSpeed true true _WINDOWS;NDEBUG;%(PreprocessorDefinitions);WITHOUT_TEMPERATURE true Windows true true %(AdditionalDependencies) false true NDEBUG;%(PreprocessorDefinitions) 0x0804 NDEBUG;%(PreprocessorDefinitions) $(IntDir);%(AdditionalIncludeDirectories) print_compile_time.bat Create Create Create Create Create Create Create Create NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing ================================================ FILE: TrafficMonitor/TrafficMonitor.vcxproj.filters ================================================  {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {296f91e9-59c8-4e1c-9281-b3a5aad240d8} {ccda107e-9fc9-493f-991e-b5a9f7dfe2f5} {4745c17a-24c6-46a2-a075-b93654aae464} {19e2ade9-e461-4885-aa2e-7774b60ebc42} {3a1e6295-c622-4708-b984-c5e7d05db5df} {22456594-86cd-4c0e-8ab9-e45cc6d78121} {ee6e7f72-a080-4020-92ff-432b8dcdad2f} {9085ed32-5818-45d1-836b-bae3c63952d0} {98909116-8f3b-47d0-8e3f-ef90b29a2acc} {feb21fbc-174b-4c26-aaa7-9f4b5e6ddd99} {cb7cc4d3-21ca-46e1-ab0e-a35ca66a5603} {79053472-785c-4667-a4f9-8b06a83ef04f} {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {5db79e4d-ccae-4347-8e35-bea54fc5a0a7} {eedf8a29-f4cb-4c66-a019-593c9dfd81ae} {adb67f17-86da-401c-981c-c6f49a1f52ac} {7f523bbb-ec3f-4626-b1d8-ad45c2467dd0} {c4eace17-d9e5-43bf-8e13-30680c7c80be} {e63367cf-7c0d-4822-ac30-0f484e65f26d} {5d1d612c-7ef4-498c-9d8f-ad11555faa80} {1c3d2e37-c54d-429a-ac6f-efe82f02902c} {974cdadc-b70f-420b-b28b-c09a0686077c} {66fdf1ef-3bc4-445a-b08e-4cd121d3455a} {6fce899f-3e92-40c2-a69b-ffcfb4a4c19f} {9fa66474-d19b-4357-9813-e511bb20c722} {75cd7f4d-06b2-467e-9960-994560da6e7b} {dd5aaacf-0f59-47ca-a738-250b15c6bbbb} {1f240f1b-347d-4281-a4cf-18bfebfacb6b} {8c35a0e3-e526-4f2f-9bc2-ed74dd37b238} {dd737159-8653-44d0-bf51-f0e3afad4e5c} {e5835851-f8d8-47dd-9669-f70b6f424386} {12448ccc-0fa7-4f50-8261-dcb04f068e39} {645d28e7-da22-44f8-8e33-894109dde4b0} {1ca17ad5-07ba-4361-bbeb-fdc5047697fc} {2b0e9f5d-dbce-4ba7-a158-7d9b705fcc02} {926ebc77-cc7f-431a-896d-3a4019b41991} {6f91f987-8834-4e89-b14e-d3ae15040848} {d2389f34-94a7-409a-97d0-47890e629c20} {2393c651-03a5-467c-a927-a3e99fdc48c4} {5bf9c8c3-2115-4e6d-897c-432303615271} {df6d5fed-e1e8-4538-b028-f046ac67ad3f} {2f6c60c6-eed6-4cad-8a1f-8759efb79d1d} {b6c785d6-4031-46d1-b224-4dd87a34404e} {74012c97-afb7-4e09-8b11-4e2945c37449} {44872bda-27ce-407a-b5a7-fa9524bfb83c} {f2a40ca2-c391-46a6-8508-b2f8c30c68a2} {ece2a796-fdd6-49e1-987e-11968b3f56a6} {2ee3ad9e-4dc0-4ca4-91b1-2c6225bebd63} {20b159a6-36ec-4d11-97c3-86e7c1501088} {68b8c93d-e1b6-4d3d-a8af-5a19d413a96e} {abe84b35-de18-4853-9545-65354fb3d22f} {c164ccd7-eb7c-465c-8828-d7a38eab573c} {24b802e1-bc90-4f4c-8862-0ba6310f05f1} {22cfb8c5-2d79-4f91-add4-fb393e20475e} {bc164584-be21-4a91-9af5-772d61ed9529} {f7dd3288-085a-4de2-9f83-d8ba2f3eff47} {dbacfb68-1e03-4bcb-a08b-e87ba558985f} {554c1c22-3662-416f-9a24-ad76bfb5eecd} {cecf73f6-6479-4ce2-aefe-879c9363ab24} {8a6deeaa-91ab-4c85-b293-ab1844f3ef82} {46dd548a-c66e-4a37-8767-6f9767125287} 资源文件 源文件和头文件\头文件 源文件和头文件\头文件 源文件和头文件\派生的控件类\StaticEx 源文件和头文件\TaskBarDlg 源文件和头文件\TrafficMonitor 源文件和头文件\TrafficMonitorDlg 源文件和头文件\stdafx 源文件和头文件\对话框类\DonateDlg 源文件和头文件\对话框类\选项设置对话框 源文件和头文件\对话框类\选项设置对话框 源文件和头文件\对话框类\选项设置对话框 源文件和头文件\对话框类\选项设置对话框 源文件和头文件\对话框类\HistoryTrafficDlg 源文件和头文件\对话框类\NetworkInfoDlg 源文件和头文件\对话框类\SkinDlg 源文件和头文件\对话框类\IconSelectDlg 源文件和头文件\派生的控件类\PictureStatic 源文件和头文件\对话框类\SkinDlg 源文件和头文件\公共的类\Common 源文件和头文件\公共的类\DrawCommon 源文件和头文件\派生的控件类\SpinEdit 源文件和头文件\派生的控件类\TabDlg 源文件和头文件\派生的控件类\ColorStatic 源文件和头文件\公共的类\IniHelper 源文件和头文件\对话框类\颜色设置对话框 源文件和头文件\派生的控件类\LinkStatic 源文件和头文件\对话框类\颜色设置对话框 源文件和头文件\对话框类\HistoryTrafficDlg 源文件和头文件\对话框类\HistoryTrafficDlg 源文件和头文件\公共的类\CalendarHelper 源文件和头文件\公共的类\AdapterCommon 源文件和头文件\公共的类\WinVersionHelper 源文件和头文件\对话框类\AboutDlg 源文件和头文件\公共的类\SimpleXML 源文件和头文件\对话框类\颜色设置对话框\MFCColorDialogEx 源文件和头文件\派生的控件类\CTabCtrlEx 源文件和头文件\公共的类\CrashTool 源文件和头文件\对话框类\MessageDlg 源文件和头文件\公共的类\CVariant 源文件和头文件\公共的类\DrawCommon 源文件和头文件\公共的类\UpdateHelper 源文件和头文件\公共的类\CPUUsage 源文件和头文件\对话框类\BaseDialog 源文件和头文件\公共的类\TaskbarDefaultStyle 源文件和头文件\对话框类\选项设置对话框\AutoAdaptSettingsDlg 源文件和头文件\公共的类\HistoryTrafficFile 测试 源文件和头文件\公共的类\WIC 源文件和头文件\对话框类\选项设置对话框\DisplayTextSettingDlg 源文件和头文件\派生的控件类\HistoryTrafficListCtrl 源文件和头文件\派生的控件类\ListCtrlEx 源文件和头文件\公共的类\SkinFile 源文件和头文件\公共的类\TinyXml2Helper 源文件和头文件\公共的类\FilePathHelper 源文件和头文件\公共的类\auto_start_helper 源文件和头文件\派生的控件类\ColorSettingListCtrl 源文件和头文件\派生的控件类\CComboBox2 源文件和头文件\公共的类\HighResolutionTimer 源文件和头文件\公共的类\tinyxml2 源文件和头文件\公共的类\TaskbarItemOrderHelper 源文件和头文件\对话框类\选项设置对话框\SetItemOrderDlg 源文件和头文件\头文件 源文件和头文件\公共的类\PluginManager 源文件和头文件\对话框类\PluginManagerDlg 源文件和头文件\对话框类\PluginManagerDlg 源文件和头文件\公共的类\CommonData 源文件和头文件\对话框类\AppAlreadyRuningDlg 源文件和头文件\对话框类\选项设置对话框\SelectConnectionsDlg 源文件和头文件\公共的类\WindowsSettingHelper 源文件和头文件\派生的控件类\StaticEx 源文件和头文件\TaskBarDlg 源文件和头文件\TrafficMonitor 源文件和头文件\TrafficMonitorDlg 源文件和头文件\stdafx 源文件和头文件\对话框类\DonateDlg 源文件和头文件\对话框类\选项设置对话框 源文件和头文件\对话框类\选项设置对话框 源文件和头文件\对话框类\选项设置对话框 源文件和头文件\对话框类\选项设置对话框 源文件和头文件\对话框类\HistoryTrafficDlg 源文件和头文件\对话框类\NetworkInfoDlg 源文件和头文件\对话框类\SkinDlg 源文件和头文件\对话框类\IconSelectDlg 源文件和头文件\派生的控件类\PictureStatic 源文件和头文件\对话框类\SkinDlg 源文件和头文件\公共的类\Common 源文件和头文件\公共的类\DrawCommon 源文件和头文件\派生的控件类\SpinEdit 源文件和头文件\派生的控件类\TabDlg 源文件和头文件\派生的控件类\ColorStatic 源文件和头文件\公共的类\IniHelper 源文件和头文件\对话框类\颜色设置对话框 源文件和头文件\派生的控件类\LinkStatic 源文件和头文件\对话框类\颜色设置对话框 源文件和头文件\对话框类\HistoryTrafficDlg 源文件和头文件\对话框类\HistoryTrafficDlg 源文件和头文件\公共的类\CalendarHelper 源文件和头文件\公共的类\AdapterCommon 源文件和头文件\公共的类\WinVersionHelper 源文件和头文件\对话框类\AboutDlg 源文件和头文件\公共的类\SimpleXML 源文件和头文件\对话框类\颜色设置对话框\MFCColorDialogEx 源文件和头文件\派生的控件类\CTabCtrlEx 源文件和头文件\公共的类\CrashTool 源文件和头文件\对话框类\MessageDlg 源文件和头文件\公共的类\CVariant 源文件和头文件\公共的类\DrawCommon 源文件和头文件\公共的类\UpdateHelper 源文件和头文件\公共的类\CPUUsage 源文件和头文件\对话框类\BaseDialog 源文件和头文件\公共的类\TaskbarDefaultStyle 源文件和头文件\对话框类\选项设置对话框\AutoAdaptSettingsDlg 源文件和头文件\公共的类\HistoryTrafficFile 测试 源文件和头文件\公共的类\WIC 源文件和头文件\对话框类\选项设置对话框\DisplayTextSettingDlg 源文件和头文件\派生的控件类\HistoryTrafficListCtrl 源文件和头文件\派生的控件类\ListCtrlEx 源文件和头文件\公共的类\SkinFile 源文件和头文件\公共的类\TinyXml2Helper 源文件和头文件\公共的类\FilePathHelper 源文件和头文件\公共的类\auto_start_helper 源文件和头文件\派生的控件类\ColorSettingListCtrl 源文件和头文件\派生的控件类\CComboBox2 源文件和头文件\公共的类\tinyxml2 源文件和头文件\公共的类\TaskbarItemOrderHelper 源文件和头文件\对话框类\选项设置对话框\SetItemOrderDlg 源文件和头文件\公共的类\PluginManager 源文件和头文件\对话框类\PluginManagerDlg 源文件和头文件\对话框类\PluginManagerDlg 源文件和头文件\公共的类\CommonData 源文件和头文件\对话框类\AppAlreadyRuningDlg 源文件和头文件\对话框类\选项设置对话框\SelectConnectionsDlg 源文件和头文件\公共的类\WindowsSettingHelper 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 资源文件 ================================================ FILE: TrafficMonitor/TrafficMonitorDlg.cpp ================================================  // TrafficMonitorDlg.cpp : 实现文件 // #include "stdafx.h" #include "TrafficMonitor.h" #include "TrafficMonitorDlg.h" #include "afxdialogex.h" #include "Test.h" #include "PluginManagerDlg.h" #include "SetItemOrderDlg.h" #include "WindowsSettingHelper.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CTrafficMonitorDlg 对话框 //静态成员初始化 unsigned int CTrafficMonitorDlg::m_WM_TASKBARCREATED{ ::RegisterWindowMessage(_T("TaskbarCreated")) }; //注册任务栏建立的消息 CTrafficMonitorDlg::CTrafficMonitorDlg(CWnd* pParent /*=NULL*/) : CDialog(IDD_TRAFFICMONITOR_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_desktop_dc = ::GetDC(NULL); } CTrafficMonitorDlg::~CTrafficMonitorDlg() { free(m_pIfTable); if (m_tBarDlg != nullptr) { delete m_tBarDlg; m_tBarDlg = nullptr; } ::ReleaseDC(NULL, m_desktop_dc); } void CTrafficMonitorDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CTrafficMonitorDlg, CDialog) ON_WM_QUERYDRAGICON() ON_WM_TIMER() ON_WM_RBUTTONUP() ON_WM_LBUTTONDOWN() ON_COMMAND(ID_NETWORK_INFO, &CTrafficMonitorDlg::OnNetworkInfo) ON_COMMAND(ID_ALWAYS_ON_TOP, &CTrafficMonitorDlg::OnAlwaysOnTop) ON_WM_INITMENUPOPUP() ON_COMMAND(ID_TRANSPARENCY_100, &CTrafficMonitorDlg::OnTransparency100) ON_COMMAND(ID_TRANSPARENCY_80, &CTrafficMonitorDlg::OnTransparency80) ON_COMMAND(ID_TRANSPARENCY_60, &CTrafficMonitorDlg::OnTransparency60) ON_COMMAND(ID_TRANSPARENCY_40, &CTrafficMonitorDlg::OnTransparency40) ON_WM_CLOSE() ON_WM_INITMENU() ON_COMMAND(ID_LOCK_WINDOW_POS, &CTrafficMonitorDlg::OnLockWindowPos) ON_WM_MOVE() ON_MESSAGE(MY_WM_NOTIFYICON, &CTrafficMonitorDlg::OnNotifyIcon) ON_COMMAND(ID_SHOW_NOTIFY_ICON, &CTrafficMonitorDlg::OnShowNotifyIcon) ON_WM_DESTROY() ON_COMMAND(ID_SHOW_CPU_MEMORY, &CTrafficMonitorDlg::OnShowCpuMemory) ON_COMMAND(ID_MOUSE_PENETRATE, &CTrafficMonitorDlg::OnMousePenetrate) ON_COMMAND(ID_SHOW_TASK_BAR_WND, &CTrafficMonitorDlg::OnShowTaskBarWnd) ON_COMMAND(ID_APP_ABOUT, &CTrafficMonitorDlg::OnAppAbout) ON_COMMAND(ID_SHOW_CPU_MEMORY2, &CTrafficMonitorDlg::OnShowCpuMemory2) ON_COMMAND(ID_SHOW_MAIN_WND, &CTrafficMonitorDlg::OnShowMainWnd) ON_COMMAND(ID_CHANGE_SKIN, &CTrafficMonitorDlg::OnChangeSkin) ON_REGISTERED_MESSAGE(m_WM_TASKBARCREATED, &CTrafficMonitorDlg::OnTaskBarCreated) ON_COMMAND(ID_TRAFFIC_HISTORY, &CTrafficMonitorDlg::OnTrafficHistory) ON_WM_MOUSEMOVE() ON_WM_LBUTTONDBLCLK() ON_COMMAND(ID_OPTIONS, &CTrafficMonitorDlg::OnOptions) ON_COMMAND(ID_OPTIONS2, &CTrafficMonitorDlg::OnOptions2) ON_MESSAGE(WM_EXITMENULOOP, &CTrafficMonitorDlg::OnExitmenuloop) ON_COMMAND(ID_CHANGE_NOTIFY_ICON, &CTrafficMonitorDlg::OnChangeNotifyIcon) ON_COMMAND(ID_ALOW_OUT_OF_BORDER, &CTrafficMonitorDlg::OnAlowOutOfBorder) ON_COMMAND(ID_CHECK_UPDATE, &CTrafficMonitorDlg::OnCheckUpdate) ON_MESSAGE(WM_TASKBAR_MENU_POPED_UP, &CTrafficMonitorDlg::OnTaskbarMenuPopedUp) ON_COMMAND(ID_SHOW_NET_SPEED, &CTrafficMonitorDlg::OnShowNetSpeed) ON_WM_QUERYENDSESSION() ON_WM_PAINT() ON_MESSAGE(WM_DPICHANGED, &CTrafficMonitorDlg::OnDpichanged) ON_MESSAGE(WM_TASKBAR_WND_CLOSED, &CTrafficMonitorDlg::OnTaskbarWndClosed) ON_MESSAGE(WM_MONITOR_INFO_UPDATED, &CTrafficMonitorDlg::OnMonitorInfoUpdated) ON_MESSAGE(WM_DISPLAYCHANGE, &CTrafficMonitorDlg::OnDisplaychange) ON_WM_EXITSIZEMOVE() ON_COMMAND(ID_PLUGIN_MANAGE, &CTrafficMonitorDlg::OnPluginManage) ON_MESSAGE(WM_REOPEN_TASKBAR_WND, &CTrafficMonitorDlg::OnReopenTaksbarWnd) ON_COMMAND(ID_OPEN_TASK_MANAGER, &CTrafficMonitorDlg::OnOpenTaskManager) ON_MESSAGE(WM_SETTINGS_APPLIED, &CTrafficMonitorDlg::OnSettingsApplied) ON_COMMAND(ID_DISPLAY_SETTINGS, &CTrafficMonitorDlg::OnDisplaySettings) ON_WM_LBUTTONUP() ON_COMMAND(ID_REFRESH_CONNECTION_LIST, &CTrafficMonitorDlg::OnRefreshConnectionList) END_MESSAGE_MAP() CString CTrafficMonitorDlg::GetMouseTipsInfo() { CString tip_info; CString temp; temp.Format(_T("%s: %s\r\n (%s: %s/%s: %s)"), CCommon::LoadText(IDS_TRAFFIC_USED_TODAY), CCommon::KBytesToString((theApp.m_today_up_traffic + theApp.m_today_down_traffic) / 1024u), CCommon::LoadText(IDS_UPLOAD), CCommon::KBytesToString(theApp.m_today_up_traffic / 1024u), CCommon::LoadText(IDS_DOWNLOAD), CCommon::KBytesToString(theApp.m_today_down_traffic / 1024u) ); tip_info += temp; const CSkinFile::Layout& skin_layout{ theApp.m_cfg_data.m_show_more_info ? m_skin.GetLayoutInfo().layout_l : m_skin.GetLayoutInfo().layout_s }; //当前的皮肤布局 if (!skin_layout.GetItem(TDI_UP).show) //如果主窗口中没有显示上传速度,则在提示信息中显示上传速度 { temp.Format(_T("\r\n%s: %s/s"), CCommon::LoadText(IDS_UPLOAD), CCommon::DataSizeToString(theApp.m_out_speed, theApp.m_main_wnd_data)); tip_info += temp; } if (!skin_layout.GetItem(TDI_DOWN).show) { temp.Format(_T("\r\n%s: %s/s"), CCommon::LoadText(IDS_DOWNLOAD), CCommon::DataSizeToString(theApp.m_in_speed, theApp.m_main_wnd_data)); tip_info += temp; } if (!skin_layout.GetItem(TDI_CPU).show) { temp.Format(_T("\r\n%s: %d %%"), CCommon::LoadText(IDS_CPU_USAGE), theApp.m_cpu_usage); tip_info += temp; } if (!skin_layout.GetItem(TDI_MEMORY).show) { temp.Format(_T("\r\n%s: %s/%s (%d %%)"), CCommon::LoadText(IDS_MEMORY_USAGE), CCommon::KBytesToString(theApp.m_used_memory), CCommon::KBytesToString(theApp.m_total_memory), theApp.m_memory_usage); tip_info += temp; } else { temp.Format(_T("\r\n%s: %s/%s"), CCommon::LoadText(IDS_MEMORY_USAGE), CCommon::KBytesToString(theApp.m_used_memory), CCommon::KBytesToString(theApp.m_total_memory)); tip_info += temp; } #ifndef WITHOUT_TEMPERATURE if (IsTemperatureNeeded()) { if (theApp.m_general_data.IsHardwareEnable(HI_GPU) && !skin_layout.GetItem(TDI_GPU_USAGE).show && theApp.m_gpu_usage >= 0) { temp.Format(_T("\r\n%s: %d %%"), CCommon::LoadText(IDS_GPU_USAGE), theApp.m_gpu_usage); tip_info += temp; } if (theApp.m_general_data.IsHardwareEnable(HI_GPU) && !skin_layout.GetItem(TDI_CPU_FREQ).show && theApp.m_cpu_freq >= 0) { temp.Format(_T("\r\n%s: %d %%"), CCommon::LoadText(IDS_CPU_FREQ), theApp.m_cpu_freq); tip_info += temp; } if (theApp.m_general_data.IsHardwareEnable(HI_CPU) && !skin_layout.GetItem(TDI_CPU_TEMP).show && theApp.m_cpu_temperature > 0) { temp.Format(_T("\r\n%s: %s"), CCommon::LoadText(IDS_CPU_TEMPERATURE), CCommon::TemperatureToString(theApp.m_cpu_temperature, theApp.m_main_wnd_data)); tip_info += temp; } if (theApp.m_general_data.IsHardwareEnable(HI_GPU) && !skin_layout.GetItem(TDI_GPU_TEMP).show && theApp.m_gpu_temperature > 0) { temp.Format(_T("\r\n%s: %s"), CCommon::LoadText(IDS_GPU_TEMPERATURE), CCommon::TemperatureToString(theApp.m_gpu_temperature, theApp.m_main_wnd_data)); tip_info += temp; } if (theApp.m_general_data.IsHardwareEnable(HI_HDD) && !skin_layout.GetItem(TDI_HDD_TEMP).show && theApp.m_hdd_temperature > 0) { temp.Format(_T("\r\n%s: %s"), CCommon::LoadText(IDS_HDD_TEMPERATURE), CCommon::TemperatureToString(theApp.m_hdd_temperature, theApp.m_main_wnd_data)); tip_info += temp; } if (theApp.m_general_data.IsHardwareEnable(HI_MBD) && !skin_layout.GetItem(TDI_MAIN_BOARD_TEMP).show && theApp.m_main_board_temperature > 0) { temp.Format(_T("\r\n%s: %s"), CCommon::LoadText(IDS_MAINBOARD_TEMPERATURE), CCommon::TemperatureToString(theApp.m_main_board_temperature, theApp.m_main_wnd_data)); tip_info += temp; } if (theApp.m_general_data.IsHardwareEnable(HI_HDD) && !skin_layout.GetItem(TDI_HDD_USAGE).show && theApp.m_hdd_usage >= 0) { temp.Format(_T("\r\n%s: %d %%"), CCommon::LoadText(IDS_HDD_USAGE), theApp.m_hdd_usage); tip_info += temp; } } #endif //添加插件项目的鼠标提示 tip_info += theApp.GetPlauginTooltipInfo().c_str(); return tip_info; } void CTrafficMonitorDlg::SetTransparency() { SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED); SetLayeredWindowAttributes(0, theApp.m_cfg_data.m_transparency * 255 / 100, LWA_ALPHA); //透明度取值范围为0~255 } void CTrafficMonitorDlg::SetTransparency(int transparency) { SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED); SetLayeredWindowAttributes(0, transparency * 255 / 100, LWA_ALPHA); //透明度取值范围为0~255 } void CTrafficMonitorDlg::SetAlwaysOnTop() { //if (!m_is_foreground_fullscreen || (m_is_foreground_fullscreen && !theApp.m_main_wnd_data.hide_main_wnd_when_fullscreen)) //{ // if (m_always_on_top) // SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); //设置置顶 // else // SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); //取消置顶 //} if (theApp.m_cfg_data.m_hide_main_window) return; else if (theApp.m_main_wnd_data.hide_main_wnd_when_fullscreen && m_is_foreground_fullscreen) //当设置有程序全屏时隐藏悬浮窗且有程序在全屏运行时,不执行置顶操作 return; if (theApp.m_main_wnd_data.m_always_on_top) SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); //设置置顶 else SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); //取消置顶 } void CTrafficMonitorDlg::SetMousePenetrate() { if (theApp.m_main_wnd_data.m_mouse_penetrate) { SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_TRANSPARENT); //设置鼠标穿透 } else { SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) & (~WS_EX_TRANSPARENT)); //取消鼠标穿透 } } POINT CTrafficMonitorDlg::CalculateWindowMoveOffset(CRect rect, bool screen_changed) { POINT mov{}; // 所需偏移量 if (m_screen_rects.size() != 0) { // 确保窗口完整在一个监视器内并且可见,判断移动距离并向所需移动距离较小的方向移动 LONG mov_xy = 0; // 记录移动距离 int i = 0; for (auto& a : m_screen_rects) { LONG x = 0, y = 0; if (rect.left < a.left) // 需要向右移动 x = a.left - rect.left; if (rect.top < a.top) // 需要向下移动 y = a.top - rect.top; //防止连接新屏幕时 m_last_screen_rects 的数量小于 m_screen_rects 的数量导致访问到过大的索引 if (i >= m_last_screen_rects.size()) { break; } CRect last_screen_rect = m_last_screen_rects[i]; if (screen_changed && a != last_screen_rect) { float proportion_width = (float)rect.left / (last_screen_rect.right - rect.Width()); float proportion_height = (float)rect.top / (last_screen_rect.bottom - rect.Height()); x = (a.right - rect.Width()) * proportion_width - rect.left; y = (a.bottom - rect.Height()) * proportion_height - rect.top; } else { if (rect.right > a.right) // 需要向左移动 x = a.right - rect.right; if (rect.bottom > a.bottom) // 需要向上移动 y = a.bottom - rect.bottom; } if (x == 0 && y == 0) // 窗口已在一个监视器内 { mov.x = 0; mov.y = 0; break; } else if (abs(x) + abs(y) < mov_xy || mov_xy == 0) { mov.x = x; mov.y = y; mov_xy = abs(x) + abs(y); } i++; } } return mov; } void CTrafficMonitorDlg::CheckWindowPos(bool screen_changed) { if (!theApp.m_main_wnd_data.m_alow_out_of_border) { CRect rect; GetWindowRect(rect); MoveWindow(rect + CalculateWindowMoveOffset(rect, screen_changed)); } } void CTrafficMonitorDlg::GetScreenSize() { m_screen_size.cx = GetSystemMetrics(SM_CXSCREEN); m_screen_size.cy = GetSystemMetrics(SM_CYSCREEN); //::SystemParametersInfo(SPI_GETWORKAREA, 0, &m_screen_rect, 0); // 获得工作区大小 //获取所有屏幕工作区的大小 m_last_screen_rects = m_screen_rects; m_screen_rects.clear(); Monitors monitors; for (auto& a : monitors.monitorinfos) { m_screen_rects.push_back(a.rcWork); } } void CTrafficMonitorDlg::AutoSelect() { unsigned __int64 max_in_out_bytes{}; unsigned __int64 in_out_bytes; //m_connection_selected = m_connections[0].index; m_connection_selected = 0; //自动选择连接时,查找已发送和已接收字节数之和最多的那个连接,并将其设置为当前查看的连接 for (size_t i{}; i < m_connections.size(); i++) { auto table = GetConnectIfTable(i); if (table.dwOperStatus == IF_OPER_STATUS_OPERATIONAL) //只选择网络状态为正常的连接 { in_out_bytes = table.dwInOctets + table.dwOutOctets; if (in_out_bytes > max_in_out_bytes) { max_in_out_bytes = in_out_bytes; m_connection_selected = i; } } } theApp.m_cfg_data.m_connection_name = GetConnection(m_connection_selected).description_2; m_connection_change_flag = true; } void CTrafficMonitorDlg::IniConnection() { //为m_pIfTable开辟所需大小的内存 free(m_pIfTable); m_dwSize = sizeof(MIB_IFTABLE); m_pIfTable = (MIB_IFTABLE*)malloc(m_dwSize); int rtn; rtn = GetIfTable(m_pIfTable, &m_dwSize, FALSE); if (rtn == ERROR_INSUFFICIENT_BUFFER) //如果函数返回值为ERROR_INSUFFICIENT_BUFFER,说明m_pIfTable的大小不够 { free(m_pIfTable); m_pIfTable = (MIB_IFTABLE*)malloc(m_dwSize); //用新的大小重新开辟一块内存 } GetIfTable(m_pIfTable, &m_dwSize, FALSE); //获取当前所有的连接,并保存到m_connections容器中 if (!theApp.m_general_data.show_all_interface) { m_connections.clear(); vector connections; CAdapterCommon::GetAdapterInfo(connections); for (const auto& item : connections) { if (!theApp.m_general_data.connections_hide.Contains(CCommon::StrToUnicode(item.description.c_str()))) m_connections.push_back(item); } CAdapterCommon::GetIfTableInfo(m_connections, m_pIfTable); } else { CAdapterCommon::GetAllIfTableInfo(m_connections, m_pIfTable); } //如果在设置了“显示所有网络连接”时设置了“选择全部”,则改为“自动选择” if (theApp.m_general_data.show_all_interface && theApp.m_cfg_data.m_select_all) { theApp.m_cfg_data.m_select_all = false; theApp.m_cfg_data.m_auto_select = true; } //写入调试日志 if (theApp.m_debug_log) { CString log_str; log_str += _T("正在初始化网络连接...\n"); log_str += _T("连接列表:\n"); for (size_t i{}; i < m_connections.size(); i++) { log_str += m_connections[i].description.c_str(); log_str += _T(", "); log_str += CCommon::IntToString(m_connections[i].index); log_str += _T("\n"); } log_str += _T("IfTable:\n"); for (size_t i{}; i < m_pIfTable->dwNumEntries; i++) { log_str += CCommon::IntToString(i); log_str += _T(" "); log_str += (const char*)m_pIfTable->table[i].bDescr; log_str += _T("\n"); } CCommon::WriteLog(log_str, (theApp.m_config_dir + L".\\connections.log").c_str()); } //if (m_connection_selected < 0 || m_connection_selected >= m_connections.size() || m_auto_select) // AutoSelect(); //选择网络连接 if (theApp.m_cfg_data.m_auto_select) //自动选择 { if (m_restart_cnt != -1) //当m_restart_cnt不等于-1时,即不是第一次初始化时,需要延时5秒再重新初始化连接 { KillTimer(DELAY_TIMER); SetTimer(DELAY_TIMER, 5000, NULL); } else { AutoSelect(); } } else //查找网络名为上次选择的连接 { m_connection_selected = 0; for (size_t i{}; i < m_connections.size(); i++) { if (m_connections[i].description_2 == m_connection_name_preferd) m_connection_selected = i; } } if (m_connection_selected < 0 || m_connection_selected >= m_connections.size()) m_connection_selected = 0; theApp.m_cfg_data.m_connection_name = GetConnection(m_connection_selected).description_2; //根据已获取到的连接在菜单中添加相应项目 CMenu* select_connection_menu = theApp.m_main_menu.GetSubMenu(0)->GetSubMenu(0); //设置“选择网络连接”子菜单项 IniConnectionMenu(select_connection_menu); //向“选择网卡”子菜单项添加项目 IniTaskBarConnectionMenu(); //初始化任务栏窗口中的“选择网络连接”子菜单项 m_restart_cnt++; //记录初始化次数 m_connection_change_flag = true; } MIB_IFROW CTrafficMonitorDlg::GetConnectIfTable(int connection_index) { if (connection_index >= 0 && connection_index < static_cast(m_connections.size())) { int index = m_connections[connection_index].index; if (m_pIfTable != nullptr && index >= 0 && index < m_pIfTable->dwNumEntries) return m_pIfTable->table[index]; } return MIB_IFROW(); } NetWorkConection CTrafficMonitorDlg::GetConnection(int connection_index) { if (connection_index >= 0 && connection_index < static_cast(m_connections.size())) return m_connections[connection_index]; else return NetWorkConection(); } void CTrafficMonitorDlg::IniConnectionMenu(CMenu* pMenu) { ASSERT(pMenu != nullptr); if (pMenu != nullptr) { //先将ID_SELECT_ALL_CONNECTION后面的所有菜单项删除 int start_pos = CCommon::GetMenuItemPosition(pMenu, ID_SELECT_ALL_CONNECTION) + 1; while (pMenu->GetMenuItemCount() > start_pos) { pMenu->DeleteMenu(start_pos, MF_BYPOSITION); } CString connection_descr; for (size_t i{}; i < m_connections.size(); i++) { connection_descr = CCommon::StrToUnicode(m_connections[i].description.c_str()).c_str(); pMenu->AppendMenu(MF_STRING | MF_ENABLED, ID_SELECT_ALL_CONNECTION + i + 1, connection_descr); } //添加“刷新网络列表”命令 pMenu->AppendMenu(MF_SEPARATOR); pMenu->AppendMenu(MF_STRING | MF_ENABLED, ID_REFRESH_CONNECTION_LIST, CCommon::LoadText(IDS_REFRESH_CONNECTION_LIST)); } } void CTrafficMonitorDlg::IniTaskBarConnectionMenu() { CMenu* select_connection_menu = theApp.m_taskbar_menu.GetSubMenu(0)->GetSubMenu(0); //设置“选择网络连接”子菜单项 IniConnectionMenu(select_connection_menu); //向“选择网卡”子菜单项添加项目 } void CTrafficMonitorDlg::SetConnectionMenuState(CMenu* pMenu) { if (theApp.m_cfg_data.m_select_all) pMenu->CheckMenuRadioItem(0, m_connections.size() + 1, 1, MF_BYPOSITION | MF_CHECKED); else if (theApp.m_cfg_data.m_auto_select) //m_auto_select为true时为自动选择,选中菜单的第1项 pMenu->CheckMenuRadioItem(0, m_connections.size() + 1, 0, MF_BYPOSITION | MF_CHECKED); else //m_auto_select为false时非自动选择,根据m_connection_selected的值选择对应的项 pMenu->CheckMenuRadioItem(0, m_connections.size() + 1, m_connection_selected + 2, MF_BYPOSITION | MF_CHECKED); } void CTrafficMonitorDlg::CloseTaskBarWnd() { if (m_tBarDlg != nullptr) { if (IsTaskbarWndValid()) m_tBarDlg->OnCancel(); delete m_tBarDlg; m_tBarDlg = nullptr; } } void CTrafficMonitorDlg::OpenTaskBarWnd() { m_tBarDlg = new CTaskBarDlg; m_tBarDlg->Create(IDD_TASK_BAR_DIALOG, this); m_tBarDlg->ShowWindow(SW_SHOW); //m_tBarDlg->ShowInfo(); //IniTaskBarConnectionMenu(); } void CTrafficMonitorDlg::AddNotifyIcon() { if (theApp.m_cfg_data.m_show_task_bar_wnd) CloseTaskBarWnd(); //添加通知栏图标 ::Shell_NotifyIcon(NIM_ADD, &m_ntIcon); if (theApp.m_cfg_data.m_show_task_bar_wnd) OpenTaskBarWnd(); } void CTrafficMonitorDlg::DeleteNotifyIcon() { if (theApp.m_cfg_data.m_show_task_bar_wnd) CloseTaskBarWnd(); //删除通知栏图标 ::Shell_NotifyIcon(NIM_DELETE, &m_ntIcon); if (theApp.m_cfg_data.m_show_task_bar_wnd) OpenTaskBarWnd(); } void CTrafficMonitorDlg::ShowNotifyTip(const wchar_t* title, const wchar_t* message) { //要显示通知区提示,必须先将通知区图标显示出来 if (!theApp.m_general_data.show_notify_icon) { //添加通知栏图标 AddNotifyIcon(); theApp.m_general_data.show_notify_icon = true; } //显示通知提示 m_ntIcon.uFlags |= NIF_INFO; //wcscpy_s(m_ntIcon.szInfo, message ? message : _T("")); //wcscpy_s(m_ntIcon.szInfoTitle, title ? title : _T("")); CCommon::WStringCopy(m_ntIcon.szInfo, 256, message); CCommon::WStringCopy(m_ntIcon.szInfoTitle, 64, title); ::Shell_NotifyIcon(NIM_MODIFY, &m_ntIcon); m_ntIcon.uFlags &= ~NIF_INFO; } void CTrafficMonitorDlg::UpdateNotifyIconTip() { CString strTip; //鼠标指向图标时显示的提示 #ifdef _DEBUG strTip = CCommon::LoadText(IDS_TRAFFICMONITOR, _T(" (Debug)")); #else strTip = CCommon::LoadText(IDS_TRAFFICMONITOR); #endif CString in_speed = CCommon::DataSizeToString(theApp.m_in_speed); CString out_speed = CCommon::DataSizeToString(theApp.m_out_speed); strTip += CCommon::StringFormat(_T("\r\n<%1%>: <%2%>/s"), { CCommon::LoadText(IDS_UPLOAD), out_speed }); strTip += CCommon::StringFormat(_T("\r\n<%1%>: <%2%>/s"), { CCommon::LoadText(IDS_DOWNLOAD), in_speed }); strTip += CCommon::StringFormat(_T("\r\nCPU: <%1%> %"), { theApp.m_cpu_usage }); strTip += CCommon::StringFormat(_T("\r\n<%1%>: <%2%> %"), { CCommon::LoadText(IDS_MEMORY), theApp.m_memory_usage }); if (IsTemperatureNeeded()) { if (theApp.m_general_data.IsHardwareEnable(HI_GPU) && theApp.m_gpu_usage >= 0) strTip += CCommon::StringFormat(_T("\r\n<%1%>: <%2%> %"), { CCommon::LoadText(IDS_GPU_USAGE), theApp.m_gpu_usage }); if (theApp.m_general_data.IsHardwareEnable(HI_CPU) && theApp.m_cpu_temperature > 0) strTip += CCommon::StringFormat(_T("\r\n<%1%>: <%2%> °C"), { CCommon::LoadText(IDS_CPU_TEMPERATURE), static_cast(theApp.m_cpu_temperature) }); if (theApp.m_general_data.IsHardwareEnable(HI_GPU) && theApp.m_gpu_temperature > 0) strTip += CCommon::StringFormat(_T("\r\n<%1%>: <%2%> °C"), { CCommon::LoadText(IDS_GPU_TEMPERATURE), static_cast(theApp.m_gpu_temperature) }); if (theApp.m_general_data.IsHardwareEnable(HI_HDD) && theApp.m_hdd_temperature > 0) strTip += CCommon::StringFormat(_T("\r\n<%1%>: <%2%> °C"), { CCommon::LoadText(IDS_HDD_TEMPERATURE), static_cast(theApp.m_hdd_temperature) }); if (theApp.m_general_data.IsHardwareEnable(HI_MBD) && theApp.m_main_board_temperature > 0) strTip += CCommon::StringFormat(_T("\r\n<%1%>: <%2%> °C"), { CCommon::LoadText(IDS_MAINBOARD_TEMPERATURE), static_cast(theApp.m_main_board_temperature) }); if (theApp.m_general_data.IsHardwareEnable(HI_HDD) && theApp.m_hdd_usage >= 0) strTip += CCommon::StringFormat(_T("\r\n<%1%>: <%2%> %"), { CCommon::LoadText(IDS_HDD_USAGE), theApp.m_hdd_usage }); } CCommon::WStringCopy(m_ntIcon.szTip, 128, strTip); ::Shell_NotifyIcon(NIM_MODIFY, &m_ntIcon); } void CTrafficMonitorDlg::SaveHistoryTraffic() { m_history_traffic.Save(); } void CTrafficMonitorDlg::LoadHistoryTraffic() { m_history_traffic.Load(); CHistoryTrafficFile backup_file(theApp.m_history_traffic_path + L".bak"); backup_file.LoadSize(); //读取备份文件中流量记录的数量 if (backup_file.Size() > m_history_traffic.Size()) //如果备份文件中流量记录的数量大于当前的数量,则从备份文件中恢复 { backup_file.Load(); size_t size_before = m_history_traffic.Size(); m_history_traffic.Merge(backup_file, true); CString log_info = CCommon::LoadTextFormat(IDS_HISTORY_TRAFFIC_LOST_ERROR_LOG, { size_before, backup_file.Size() }); CCommon::WriteLog(log_info, theApp.m_log_path.c_str()); } theApp.m_today_up_traffic = m_history_traffic.GetTodayUpTraffic(); theApp.m_today_down_traffic = m_history_traffic.GetTodayDownTraffic(); } void CTrafficMonitorDlg::BackupHistoryTrafficFile() { CHistoryTrafficFile backup_file(theApp.m_history_traffic_path + L".bak"); CHistoryTrafficFile latest_file(theApp.m_history_traffic_path); backup_file.LoadSize(); latest_file.LoadSize(); if (backup_file.Size() < latest_file.Size()) { CopyFile(latest_file.GetFilePath().c_str(), backup_file.GetFilePath().c_str(), FALSE); } } void CTrafficMonitorDlg::_OnOptions(int tab) { COptionsDlg optionsDlg(tab, this); //将选项设置数据传递给选项设置对话框 if (COptionsDlg::GetUniqueHandel(OPTION_DLG_NAME) == NULL) //确保此时选项设置对话框已经关闭 { optionsDlg.m_tab1_dlg.m_data = theApp.m_main_wnd_data; optionsDlg.m_tab2_dlg.m_data = theApp.m_taskbar_data; optionsDlg.m_tab3_dlg.m_data = theApp.m_general_data; optionsDlg.m_tab1_dlg.m_text_disable = m_skin.GetLayoutInfo().no_label; } if (optionsDlg.DoModal() == IDOK) { ApplySettings(optionsDlg); } } void CTrafficMonitorDlg::ApplySettings(COptionsDlg& optionsDlg) { bool is_hardware_monitor_item_changed = (optionsDlg.m_tab3_dlg.m_data.hardware_monitor_item != theApp.m_general_data.hardware_monitor_item); bool is_always_on_top_changed = (optionsDlg.m_tab1_dlg.m_data.m_always_on_top != theApp.m_main_wnd_data.m_always_on_top); bool is_mouse_penerate_changed = (optionsDlg.m_tab1_dlg.m_data.m_mouse_penetrate != theApp.m_main_wnd_data.m_mouse_penetrate); bool is_alow_out_of_border_changed = (optionsDlg.m_tab1_dlg.m_data.m_alow_out_of_border != theApp.m_main_wnd_data.m_alow_out_of_border); bool is_show_notify_icon_changed = (optionsDlg.m_tab3_dlg.m_data.show_notify_icon != theApp.m_general_data.show_notify_icon); bool is_connections_hide_changed = (optionsDlg.m_tab3_dlg.m_data.connections_hide.data() != theApp.m_general_data.connections_hide.data()); theApp.m_main_wnd_data = optionsDlg.m_tab1_dlg.m_data; theApp.m_taskbar_data = optionsDlg.m_tab2_dlg.m_data; theApp.m_general_data = optionsDlg.m_tab3_dlg.m_data; theApp.SendSettingsToPlugin(); CGeneralSettingsDlg::CheckTaskbarDisplayItem(); SetTextFont(); //CTaskBarDlg::SaveConfig(); if (IsTaskbarWndValid()) { m_tBarDlg->ApplySettings(); //如果更改了任务栏窗口字体或显示的文本,则任务栏窗口可能要变化,于是关闭再打开任务栏窗口 CloseTaskBarWnd(); OpenTaskBarWnd(); } if (optionsDlg.m_tab3_dlg.IsAutoRunModified()) { if (!theApp.SetAutoRun(theApp.m_general_data.auto_run)) MessageBox(CCommon::LoadText(IDS_SET_AUTO_RUN_FAILED_WARNING), NULL, MB_ICONWARNING | MB_OK); } if (optionsDlg.m_tab3_dlg.IsShowAllInterfaceModified() || is_connections_hide_changed) IniConnection(); if (optionsDlg.m_tab3_dlg.IsMonitorTimeSpanModified()) //如果监控时间间隔改变了,则重设定时器 { KillTimer(MONITOR_TIMER); SetTimer(MONITOR_TIMER, theApp.m_general_data.monitor_time_span, NULL); //m_timer.KillTimer(); //m_timer.CreateTimer((DWORD_PTR)this, theApp.m_general_data.monitor_time_span, MonitorThreadCallback); } //设置获取CPU利用率的方式 m_cpu_usage.SetUseCPUTimes(theApp.m_general_data.m_get_cpu_usage_by_cpu_times); #ifndef WITHOUT_TEMPERATURE if (is_hardware_monitor_item_changed) { //如果关闭了硬件监控,则析构硬件监控类 if (theApp.m_general_data.hardware_monitor_item == 0) { CSingleLock sync(&theApp.m_minitor_lib_critical, TRUE); theApp.m_pMonitor.reset(); } else if (theApp.m_pMonitor != nullptr) { theApp.UpdateOpenHardwareMonitorEnableState(); } else if (IsTemperatureNeeded()) { theApp.InitOpenHardwareLibInThread(); } //更新任务栏窗口右键菜单 //theApp.UpdateTaskbarWndMenu(); } #endif if (is_always_on_top_changed) { SetAlwaysOnTop(); } if (is_mouse_penerate_changed) { SetMousePenetrate(); if (!theApp.m_general_data.show_notify_icon && theApp.IsForceShowNotifyIcon()) //鼠标穿透时,如果通知图标没有显示,则将它显示出来,否则无法呼出右键菜单 { //添加通知栏图标 AddNotifyIcon(); theApp.m_general_data.show_notify_icon = true; } } if (is_alow_out_of_border_changed) { CheckWindowPos(); } if (is_show_notify_icon_changed) { if (theApp.IsForceShowNotifyIcon()) theApp.m_general_data.show_notify_icon = true; if (theApp.m_general_data.show_notify_icon) AddNotifyIcon(); else DeleteNotifyIcon(); } theApp.SaveConfig(); theApp.SaveGlobalConfig(); } void CTrafficMonitorDlg::SetItemPosition() { if (theApp.m_cfg_data.m_show_more_info) { SetWindowPos(nullptr, 0, 0, m_skin.GetLayoutInfo().layout_l.width, m_skin.GetLayoutInfo().layout_l.height, SWP_NOMOVE | SWP_NOZORDER); } else { SetWindowPos(nullptr, 0, 0, m_skin.GetLayoutInfo().layout_s.width, m_skin.GetLayoutInfo().layout_s.height, SWP_NOMOVE | SWP_NOZORDER); } } void CTrafficMonitorDlg::LoadSkinLayout() { wstring skin_cfg_path{ theApp.m_skin_path + m_skins[m_skin_selected] + L"\\skin.xml" }; if (!CCommon::FileExist(skin_cfg_path.c_str())) skin_cfg_path = theApp.m_skin_path + m_skins[m_skin_selected] + L"\\skin.ini"; m_skin.Load(skin_cfg_path); if (m_skin.GetLayoutInfo().no_label) //如果皮肤布局不显示文本,则不允许交换上传和下载的位置,因为上传和下载的位置已经固定在皮肤中了 theApp.m_main_wnd_data.swap_up_down = false; } void CTrafficMonitorDlg::LoadBackGroundImage() { CImage img_tmp; CSize image_size; if (theApp.m_cfg_data.m_show_more_info) { image_size.SetSize(m_skin.GetLayoutInfo().layout_l.width, m_skin.GetLayoutInfo().layout_l.height); } else { image_size.SetSize(m_skin.GetLayoutInfo().layout_s.width, m_skin.GetLayoutInfo().layout_s.height); } //创建窗口区域 CImage img_mask; //载入掩码图片 if (theApp.m_cfg_data.m_show_more_info) img_tmp.Load((theApp.m_skin_path + m_skins[m_skin_selected] + BACKGROUND_MASK_L).c_str()); else img_tmp.Load((theApp.m_skin_path + m_skins[m_skin_selected] + BACKGROUND_MASK_S).c_str()); CRgn wnd_rgn; if (!img_tmp.IsNull()) { CDrawCommon::BitmapStretch(&img_tmp, &img_mask, image_size); //拉伸掩码图片 CBitmap bitmap; bitmap.Attach(img_mask); CDrawCommon::GetRegionFromImage(wnd_rgn, bitmap, 128); //从掩码图片获得窗口的区域 bitmap.Detach(); } else { wnd_rgn.CreateRectRgnIndirect(CRect(CPoint(0, 0), image_size)); //载入掩码图片失败,则使用窗口大小作为窗口区域 } //避免获取到的窗口区域为空 CRgn empty_rgn; empty_rgn.CreateRectRgnIndirect(CRect{}); //创建一个空的CRgn对象 if (wnd_rgn.EqualRgn(&empty_rgn)) wnd_rgn.SetRectRgn(CRect(CPoint(0, 0), image_size)); //如果获取到的窗口区域为空,则使用窗口大小作为窗口区域 SetWindowRgn(wnd_rgn, TRUE); //设置窗口区域 wnd_rgn.DeleteObject(); empty_rgn.DeleteObject(); } void CTrafficMonitorDlg::SetTextFont() { if (m_font.m_hObject) //如果m_font已经关联了一个字体资源对象,则释放它 m_font.DeleteObject(); theApp.m_main_wnd_data.font.Create(m_font, theApp.GetDpi()); } bool CTrafficMonitorDlg::IsTaskbarWndValid() const { return m_tBarDlg != nullptr && ::IsWindow(m_tBarDlg->GetSafeHwnd()); } void CTrafficMonitorDlg::TaskbarShowHideItem(DisplayItem type) { if (IsTaskbarWndValid()) { bool show = (theApp.m_taskbar_data.m_tbar_display_item & type); if (show) { theApp.m_taskbar_data.m_tbar_display_item &= ~type; } else { theApp.m_taskbar_data.m_tbar_display_item |= type; } CloseTaskBarWnd(); OpenTaskBarWnd(); } } void CTrafficMonitorDlg::CheckClickedItem(CPoint point) { const CSkinFile::Layout& skin_layout{ theApp.m_cfg_data.m_show_more_info ? m_skin.GetLayoutInfo().layout_l : m_skin.GetLayoutInfo().layout_s }; //当前的皮肤布局 for (const auto& layout_item : skin_layout.layout_items) { CRect rect(CPoint(layout_item.second.x, layout_item.second.y), CSize(layout_item.second.width, m_skin.GetLayoutInfo().text_height)); if (rect.PtInRect(point)) { m_clicked_item = layout_item.first; break; } } } bool CTrafficMonitorDlg::IsTemperatureNeeded() const { //判断是否需要从OpenHardwareMonitor获取信息。 ////只有主窗口和任务栏窗口中CPU温度、显卡利用率、显卡温度、硬盘温度和主板温度中至少有一个要显示,才返回true //bool needed = false; //if (theApp.m_cfg_data.m_show_task_bar_wnd && IsTaskbarWndValid()) //{ // needed |= m_tBarDlg->IsShowCpuTemperature(); // needed |= m_tBarDlg->IsShowGpu(); // needed |= m_tBarDlg->IsShowGpuTemperature(); // needed |= m_tBarDlg->IsShowHddTemperature(); // needed |= m_tBarDlg->IsShowMainboardTemperature(); // needed |= (::IsWindow(m_tBarDlg->m_tool_tips.GetSafeHwnd()) && m_tBarDlg->m_tool_tips.IsWindowVisible()); //} //if (!theApp.m_cfg_data.m_hide_main_window) //{ // const CSkinFile::Layout& skin_layout{ theApp.m_cfg_data.m_show_more_info ? m_skin.GetLayoutInfo().layout_l : m_skin.GetLayoutInfo().layout_s }; //当前的皮肤布局 // needed |= skin_layout.GetItem(TDI_CPU_TEMP).show; // needed |= skin_layout.GetItem(TDI_GPU_USAGE).show; // needed |= skin_layout.GetItem(TDI_GPU_TEMP).show; // needed |= skin_layout.GetItem(TDI_HDD_TEMP).show; // needed |= skin_layout.GetItem(TDI_MAIN_BOARD_TEMP).show; // needed |= (::IsWindow(m_tool_tips.GetSafeHwnd()) && m_tool_tips.IsWindowVisible()); //} //return needed; return theApp.m_general_data.IsHardwareEnable(HI_CPU) || theApp.m_general_data.IsHardwareEnable(HI_GPU) || theApp.m_general_data.IsHardwareEnable(HI_HDD) || theApp.m_general_data.IsHardwareEnable(HI_MBD); } // CTrafficMonitorDlg 消息处理程序 BOOL CTrafficMonitorDlg::OnInitDialog() { CDialog::OnInitDialog(); // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 SetWindowText(APP_NAME); //设置隐藏任务栏图标 ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW); theApp.DPIFromWindow(this); //获取屏幕大小 GetScreenSize(); m_last_screen_rects = m_screen_rects; //::SystemParametersInfo(SPI_GETWORKAREA, 0, &m_screen_rect, 0); // 获得工作区大小 //初始化菜单 theApp.InitMenuResourse(); //theApp.UpdateTaskbarWndMenu(); //设置窗口透明度 SetTransparency(); IniConnection(); //初始化连接 //如果启动时设置了鼠标穿透或隐藏主窗口,并且没有显示任务栏窗口,则显示通知区图标 if ((theApp.m_main_wnd_data.m_mouse_penetrate || theApp.m_cfg_data.m_hide_main_window) && !theApp.m_cfg_data.m_show_task_bar_wnd) theApp.m_general_data.show_notify_icon = true; //载入通知区图标 theApp.m_notify_icons[0] = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_NOFITY_ICON), IMAGE_ICON, theApp.DPI(16), theApp.DPI(16), LR_DEFAULTCOLOR | LR_CREATEDIBSECTION); theApp.m_notify_icons[1] = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_NOFITY_ICON2), IMAGE_ICON, theApp.DPI(16), theApp.DPI(16), LR_DEFAULTCOLOR | LR_CREATEDIBSECTION); theApp.m_notify_icons[2] = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_NOFITY_ICON3), IMAGE_ICON, theApp.DPI(16), theApp.DPI(16), LR_DEFAULTCOLOR | LR_CREATEDIBSECTION); theApp.m_notify_icons[3] = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, theApp.DPI(16), theApp.DPI(16), LR_DEFAULTCOLOR | LR_CREATEDIBSECTION); theApp.m_notify_icons[4] = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_NOFITY_ICON4), IMAGE_ICON, theApp.DPI(16), theApp.DPI(16), LR_DEFAULTCOLOR | LR_CREATEDIBSECTION); theApp.m_notify_icons[5] = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_NOTIFY_ICON5), IMAGE_ICON, theApp.DPI(16), theApp.DPI(16), LR_DEFAULTCOLOR | LR_CREATEDIBSECTION); //设置通知区域图标 m_ntIcon.cbSize = sizeof(NOTIFYICONDATA); //该结构体变量的大小 if (theApp.m_cfg_data.m_notify_icon_selected < 0 || theApp.m_cfg_data.m_notify_icon_selected >= MAX_NOTIFY_ICON) theApp.m_cfg_data.m_notify_icon_selected = 0; m_ntIcon.hIcon = theApp.m_notify_icons[theApp.m_cfg_data.m_notify_icon_selected]; //设置图标 m_ntIcon.hWnd = this->m_hWnd; //接收托盘图标通知消息的窗口句柄 CString atip; //鼠标指向图标时显示的提示 #ifdef _DEBUG atip = CCommon::LoadText(IDS_TRAFFICMONITOR, _T(" (Debug)")); #else atip = CCommon::LoadText(IDS_TRAFFICMONITOR); #endif //wcscpy_s(m_ntIcon.szTip, 128, strTip); CCommon::WStringCopy(m_ntIcon.szTip, 128, atip.GetString()); m_ntIcon.uCallbackMessage = MY_WM_NOTIFYICON; //应用程序定义的消息ID号 m_ntIcon.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; //图标的属性:设置成员uCallbackMessage、hIcon、szTip有效 if (theApp.m_general_data.show_notify_icon) ::Shell_NotifyIcon(NIM_ADD, &m_ntIcon); //在系统通知区域增加这个图标 //载入流量历史记录 LoadHistoryTraffic(); //设置1000毫秒触发的定时器 SetTimer(MAIN_TIMER, 1000, NULL); SetTimer(MONITOR_TIMER, theApp.m_general_data.monitor_time_span, NULL); //m_timer.CreateTimer((DWORD_PTR)this, theApp.m_general_data.monitor_time_span, MonitorThreadCallback); //初始化皮肤 CCommon::GetFiles((theApp.m_skin_path + L"\\*").c_str(), [&](const wstring& file_name) { wstring file_name1 = L'\\' + file_name; if (CCommon::IsFolder(theApp.m_skin_path + file_name1)) m_skins.push_back(file_name1); }); if (m_skins.empty()) m_skins.push_back(L""); m_skin_selected = 0; for (unsigned int i{}; i < m_skins.size(); i++) { if (m_skins[i] == theApp.m_cfg_data.m_skin_name) m_skin_selected = i; } //根据当前选择的皮肤获取布局数据 LoadSkinLayout(); //初始化窗口位置 SetItemPosition(); if (theApp.m_cfg_data.m_position_x != -1 && theApp.m_cfg_data.m_position_y != -1) SetWindowPos(nullptr, theApp.m_cfg_data.m_position_x, theApp.m_cfg_data.m_position_y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); CheckWindowPos(); //载入背景图片 LoadBackGroundImage(); //设置字体 SetTextFont(); //获取启动时的时间 GetLocalTime(&m_start_time); //初始化鼠标提示 m_tool_tips.Create(this, TTS_ALWAYSTIP); m_tool_tips.SetMaxTipWidth(600); m_tool_tips.AddTool(this, _T("")); //设置获取CPU利用率的方式 m_cpu_usage.SetUseCPUTimes(theApp.m_general_data.m_get_cpu_usage_by_cpu_times); //如果程序启动时设置了隐藏主窗口,或窗口的位置在左上角,则先将其不透明度设为0 if (theApp.m_cfg_data.m_hide_main_window || (theApp.m_cfg_data.m_position_x == 0 && theApp.m_cfg_data.m_position_y == 0)) SetTransparency(0); SetTimer(TASKBAR_TIMER, 100, NULL); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CTrafficMonitorDlg::OnQueryDragIcon() { return static_cast(m_hIcon); } //计算指定秒数的时间内Monitor定时器会触发的次数 static int GetMonitorTimerCount(int second) { return second * 1000 / theApp.m_general_data.monitor_time_span; } UINT CTrafficMonitorDlg::MonitorThreadCallback(LPVOID dwUser) { CTrafficMonitorDlg* pThis = (CTrafficMonitorDlg*)dwUser; CFlagLocker flag_locker(pThis->m_is_monitor_thread_runing); //获取网络连接速度 int rtn{}; auto getLfTable = [&]() { __try { rtn = GetIfTable(pThis->m_pIfTable, &pThis->m_dwSize, FALSE); } __except (EXCEPTION_EXECUTE_HANDLER) { free(pThis->m_pIfTable); pThis->m_dwSize = sizeof(MIB_IFTABLE); pThis->m_pIfTable = (MIB_IFTABLE*)malloc(pThis->m_dwSize); rtn = GetIfTable(pThis->m_pIfTable, &pThis->m_dwSize, FALSE); if (rtn == ERROR_INSUFFICIENT_BUFFER) //如果函数返回值为ERROR_INSUFFICIENT_BUFFER,说明m_pIfTable的大小不够 { free(pThis->m_pIfTable); pThis->m_pIfTable = (MIB_IFTABLE*)malloc(pThis->m_dwSize); //用新的大小重新开辟一块内存 } GetIfTable(pThis->m_pIfTable, &pThis->m_dwSize, FALSE); } }; getLfTable(); if (!theApp.m_cfg_data.m_select_all) //获取当前选中连接的网速 { auto table = pThis->GetConnectIfTable(pThis->m_connection_selected); pThis->m_in_bytes = table.dwInOctets; pThis->m_out_bytes = table.dwOutOctets; } else //获取全部连接的网速 { pThis->m_in_bytes = 0; pThis->m_out_bytes = 0; for (size_t i{}; i < pThis->m_connections.size(); i++) { auto table = pThis->GetConnectIfTable(i); //if (i > 0 && m_pIfTable->table[m_connections[i].index].dwInOctets == m_pIfTable->table[m_connections[i - 1].index].dwInOctets // && m_pIfTable->table[m_connections[i].index].dwOutOctets == m_pIfTable->table[m_connections[i - 1].index].dwOutOctets) // continue; //连接列表中可能会有相同的连接,统计所有连接的网速时,忽略掉已发送和已接收字节数完全相同的连接 pThis->m_in_bytes += table.dwInOctets; pThis->m_out_bytes += table.dwOutOctets; } } unsigned __int64 cur_in_speed{}, cur_out_speed{}; //本次监控时间间隔内的上传和下载速度 //如果发送和接收的字节数为0或上次发送和接收的字节数为0或当前连接已改变时,网速无效 if ((pThis->m_in_bytes == 0 && pThis->m_out_bytes == 0) || (pThis->m_last_in_bytes == 0 && pThis->m_last_out_bytes == 0) || pThis->m_connection_change_flag || pThis->m_last_in_bytes > pThis->m_in_bytes || pThis->m_last_out_bytes > pThis->m_out_bytes) { cur_in_speed = 0; cur_out_speed = 0; } else { cur_in_speed = pThis->m_in_bytes - pThis->m_last_in_bytes; cur_out_speed = pThis->m_out_bytes - pThis->m_last_out_bytes; } ////如果大于1GB/s,说明可能产生了异常,网速无效 //if (cur_in_speed > 1073741824) // cur_in_speed = 0; //if (cur_out_speed > 1073741824) // cur_out_speed = 0; //将当前监控时间间隔的流量转换成每秒时间间隔内的流量 theApp.m_in_speed = static_cast(cur_in_speed * 1000 / theApp.m_general_data.monitor_time_span); theApp.m_out_speed = static_cast(cur_out_speed * 1000 / theApp.m_general_data.monitor_time_span); pThis->m_connection_change_flag = false; //清除连接发生变化的标志 pThis->m_last_in_bytes = pThis->m_in_bytes; pThis->m_last_out_bytes = pThis->m_out_bytes; //处于自动选择状态时,如果连续30秒没有网速,则可能自动选择的网络不对,此时执行一次自动选择 if (theApp.m_cfg_data.m_auto_select) { if (cur_in_speed == 0 && cur_out_speed == 0) pThis->m_zero_speed_cnt++; else pThis->m_zero_speed_cnt = 0; if (pThis->m_zero_speed_cnt >= GetMonitorTimerCount(30)) { pThis->AutoSelect(); pThis->m_zero_speed_cnt = 0; } } //检测当前日期是否改变,如果已改变,就向历史流量列表插入一个新的日期 SYSTEMTIME current_time; GetLocalTime(¤t_time); if (pThis->m_history_traffic.GetTraffics()[0].day != current_time.wDay) { HistoryTraffic traffic; traffic.year = current_time.wYear; traffic.month = current_time.wMonth; traffic.day = current_time.wDay; traffic.mixed = false; pThis->m_history_traffic.GetTraffics().push_front(traffic); theApp.m_today_up_traffic = 0; theApp.m_today_down_traffic = 0; } //统计今天已使用的流量 theApp.m_today_up_traffic += cur_out_speed; theApp.m_today_down_traffic += cur_in_speed; pThis->m_history_traffic.GetTraffics()[0].up_kBytes = theApp.m_today_up_traffic / 1024u; pThis->m_history_traffic.GetTraffics()[0].down_kBytes = theApp.m_today_down_traffic / 1024u; //每隔30秒保存一次流量历史记录 if (pThis->m_monitor_time_cnt % GetMonitorTimerCount(30) == GetMonitorTimerCount(30) - 1) { static unsigned __int64 last_today_kbytes; if (pThis->m_history_traffic.GetTraffics()[0].kBytes() - last_today_kbytes >= 100u) //只有当流量变化超过100KB时才保存历史流量记录,防止磁盘写入过于频繁 { pThis->SaveHistoryTraffic(); last_today_kbytes = pThis->m_history_traffic.GetTraffics()[0].kBytes(); } } if (rtn == ERROR_INSUFFICIENT_BUFFER) { pThis->IniConnection(); CString info; info.LoadString(IDS_INSUFFICIENT_BUFFER); info.Replace(_T("<%cnt%>"), CCommon::IntToString(pThis->m_restart_cnt)); CCommon::WriteLog(info, theApp.m_log_path.c_str()); } if (pThis->m_monitor_time_cnt % GetMonitorTimerCount(3) == GetMonitorTimerCount(3) - 1) { //重新获取当前连接数量 static DWORD last_interface_num = -1; DWORD interface_num; GetNumberOfInterfaces(&interface_num); if (last_interface_num != -1 && interface_num != last_interface_num) //如果连接数发生变化,则重新初始化连接 { if (theApp.m_debug_log) { CString info; info.LoadString(IDS_CONNECTION_NUM_CHANGED); info.Replace(_T("<%before%>"), CCommon::IntToString(last_interface_num)); info.Replace(_T("<%after%>"), CCommon::IntToString(interface_num)); info.Replace(_T("<%cnt%>"), CCommon::IntToString(pThis->m_restart_cnt + 1)); CCommon::WriteLog(info, theApp.m_log_path.c_str()); } pThis->IniConnection(); last_interface_num = interface_num; } string descr; descr = (const char*)pThis->GetConnectIfTable(pThis->m_connection_selected).bDescr; if (descr != theApp.m_cfg_data.m_connection_name) { //写入额外的调试信息 if (theApp.m_debug_log) { CString log_str; log_str = _T("连接名称不匹配:\r\n"); log_str += _T("IfTable description: "); log_str += descr.c_str(); log_str += _T("\r\nm_connection_name: "); log_str += theApp.m_cfg_data.m_connection_name.c_str(); CCommon::WriteLog(log_str, (theApp.m_config_dir + L".\\connections.log").c_str()); } pThis->IniConnection(); CString info; info.LoadString(IDS_CONNECTION_NOT_MATCH); info.Replace(_T("<%cnt%>"), CCommon::IntToString(pThis->m_restart_cnt)); CCommon::WriteLog(info, theApp.m_log_path.c_str()); } } ////只有主窗口和任务栏窗口至少有一个显示时才执行下面的处理 //if (!theApp.m_cfg_data.m_hide_main_window || theApp.m_cfg_data.m_show_task_bar_wnd) //{ //获取CPU使用率 theApp.m_cpu_usage = pThis->m_cpu_usage.GetCPUUsage(); //获取内存利用率 MEMORYSTATUSEX statex; statex.dwLength = sizeof(statex); GlobalMemoryStatusEx(&statex); theApp.m_memory_usage = statex.dwMemoryLoad; theApp.m_used_memory = static_cast((statex.ullTotalPhys - statex.ullAvailPhys) / 1024); theApp.m_total_memory = static_cast(statex.ullTotalPhys / 1024); #ifndef WITHOUT_TEMPERATURE //获取温度 if (pThis->IsTemperatureNeeded() && theApp.m_pMonitor != nullptr) { CSingleLock sync(&theApp.m_minitor_lib_critical, TRUE); auto getHardwareInfo = []() { __try { theApp.m_pMonitor->GetHardwareInfo(); } __except (EXCEPTION_EXECUTE_HANDLER) { AfxMessageBox(IDS_HARDWARE_INFO_ACQUIRE_FAILED_ERROR, MB_ICONERROR | MB_OK); } }; getHardwareInfo(); auto monitor_error_message{ OpenHardwareMonitorApi::GetErrorMessage() }; if (!monitor_error_message.empty()) { AfxMessageBox(monitor_error_message.c_str(), MB_ICONERROR | MB_OK); } //theApp.m_cpu_temperature = theApp.m_pMonitor->CpuTemperature(); theApp.m_gpu_temperature = theApp.m_pMonitor->GpuTemperature(); //theApp.m_hdd_temperature = theApp.m_pMonitor->HDDTemperature(); theApp.m_main_board_temperature = theApp.m_pMonitor->MainboardTemperature(); theApp.m_gpu_usage = theApp.m_pMonitor->GpuUsage(); theApp.m_cpu_freq = theApp.m_pMonitor->CpuFreq(); //获取CPU温度 if (!theApp.m_pMonitor->AllCpuTemperature().empty()) { if (theApp.m_general_data.cpu_core_name == CCommon::LoadText(IDS_AVREAGE_TEMPERATURE).GetString()) //如果选择了平均温度 { theApp.m_cpu_temperature = theApp.m_pMonitor->CpuTemperature(); } else { auto iter = theApp.m_pMonitor->AllCpuTemperature().find(theApp.m_general_data.cpu_core_name); if (iter == theApp.m_pMonitor->AllCpuTemperature().end()) { iter = theApp.m_pMonitor->AllCpuTemperature().begin(); theApp.m_general_data.cpu_core_name = iter->first; } theApp.m_cpu_temperature = iter->second; } } else { theApp.m_cpu_temperature = -1; } //获取硬盘温度 if (!theApp.m_pMonitor->AllHDDTemperature().empty()) { auto iter = theApp.m_pMonitor->AllHDDTemperature().find(theApp.m_general_data.hard_disk_name); if (iter == theApp.m_pMonitor->AllHDDTemperature().end()) { iter = theApp.m_pMonitor->AllHDDTemperature().begin(); theApp.m_general_data.hard_disk_name = iter->first; } theApp.m_hdd_temperature = iter->second; } else { theApp.m_hdd_temperature = -1; } //获取硬盘利用率 if (!theApp.m_pMonitor->AllHDDUsage().empty()) { auto iter = theApp.m_pMonitor->AllHDDUsage().find(theApp.m_general_data.hard_disk_name); if (iter == theApp.m_pMonitor->AllHDDUsage().end()) { iter = theApp.m_pMonitor->AllHDDUsage().begin(); theApp.m_general_data.hard_disk_name = iter->first; } theApp.m_hdd_usage = iter->second; } else { theApp.m_hdd_usage = -1; } } else { theApp.m_cpu_temperature = -1; theApp.m_gpu_temperature = -1; theApp.m_hdd_temperature = -1; theApp.m_main_board_temperature = -1; theApp.m_gpu_usage = -1; theApp.m_hdd_usage = -1; } #endif //通知插件获取数据,以及向插件传递监控数据 for (const auto& plugin_info : theApp.m_plugins.GetPlugins()) { if (plugin_info.plugin != nullptr) { plugin_info.plugin->DataRequired(); ITMPlugin::MonitorInfo monitor_info; monitor_info.up_speed = theApp.m_out_speed; monitor_info.down_speed = theApp.m_in_speed; monitor_info.cpu_usage = theApp.m_cpu_usage; monitor_info.memory_usage = theApp.m_memory_usage; monitor_info.gpu_usage = theApp.m_gpu_usage; monitor_info.hdd_usage = theApp.m_hdd_usage; monitor_info.cpu_temperature = theApp.m_cpu_temperature; monitor_info.gpu_temperature = theApp.m_gpu_temperature; monitor_info.hdd_temperature = theApp.m_hdd_temperature; monitor_info.cpu_freq = theApp.m_cpu_freq; monitor_info.main_board_temperature = theApp.m_main_board_temperature; plugin_info.plugin->OnMonitorInfo(monitor_info); } } //} pThis->m_monitor_time_cnt++; //发送监控信息更新消息 pThis->SendMessage(WM_MONITOR_INFO_UPDATED); return 0; } void CTrafficMonitorDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (nIDEvent == MONITOR_TIMER) { if (!m_is_monitor_thread_runing) //确保线程已退出 AfxBeginThread(MonitorThreadCallback, (LPVOID)this); } if (nIDEvent == MAIN_TIMER) { if (m_first_start) //这个if语句在程序启动后1秒执行 { //将设置窗口置顶的处理放在这里是用于解决 //放在初始化函数中可能会出现设置置顶无效的问题 SetAlwaysOnTop(); //设置窗口置顶 SetMousePenetrate(); //设置鼠标穿透 if (theApp.m_cfg_data.m_hide_main_window) //设置隐藏主窗口 ShowWindow(SW_HIDE); //打开任务栏窗口 if (theApp.m_cfg_data.m_show_task_bar_wnd && m_tBarDlg == nullptr) OpenTaskBarWnd(); //如果窗口的位置为(0, 0),则在初始化时MoveWindow函数无效,此时再移动一次窗口 if (theApp.m_cfg_data.m_position_x == 0 && theApp.m_cfg_data.m_position_y == 0) { SetWindowPos(nullptr, theApp.m_cfg_data.m_position_x, theApp.m_cfg_data.m_position_y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } SetTransparency(); //重新设置窗口不透明度 m_first_start = false; } if (theApp.m_main_wnd_data.m_always_on_top && !theApp.m_cfg_data.m_hide_main_window) { //每隔1秒钟就判断一下前台窗口是否全屏 m_is_foreground_fullscreen = CCommon::IsForegroundFullscreen(); if (theApp.m_main_wnd_data.hide_main_wnd_when_fullscreen) //当设置了全屏时隐藏悬浮窗时 { if (m_is_foreground_fullscreen || theApp.m_cfg_data.m_hide_main_window) ShowWindow(SW_HIDE); else ShowWindow(SW_RESTORE); } else //如果没有设置全屏时隐藏悬浮窗,则如果有程序进入全屏状态,则设置一次窗口置顶 { static bool last_foreground_fullscreen; if (!last_foreground_fullscreen && m_is_foreground_fullscreen) { SetAlwaysOnTop(); } last_foreground_fullscreen = m_is_foreground_fullscreen; } } if (!m_menu_popuped) { //程序启动后若干秒的时候根据设置重新执行“总是置顶”、“鼠标穿透”和“隐藏主窗口”的操作,防止设置没有生效 if (m_timer_cnt == 5 || m_timer_cnt == 9) { if (!theApp.m_cfg_data.m_hide_main_window) { SetAlwaysOnTop(); SetMousePenetrate(); } else { ShowWindow(SW_HIDE); } } if (m_timer_cnt % 300 == 299 && !theApp.m_cfg_data.m_hide_main_window && theApp.m_main_wnd_data.m_always_on_top) { SetAlwaysOnTop(); //每5分钟执行一次设置窗口置顶 } } if (m_timer_cnt % 30 == 26) //每隔30秒钟检测一次窗口位置,当窗口位置发生变化时保存设置 { static int last_pos_x{ -1 }, last_pos_y{ -1 }; if (last_pos_x != theApp.m_cfg_data.m_position_x || last_pos_y != theApp.m_cfg_data.m_position_y) { theApp.SaveConfig(); last_pos_x = theApp.m_cfg_data.m_position_x; last_pos_y = theApp.m_cfg_data.m_position_y; } } if (m_timer_cnt % 2 == 1) //每隔2秒钟获取一次屏幕区域 { GetScreenSize(); CheckWindowPos(); } //只有主窗口和任务栏窗口至少有一个显示时才执行下面的处理 if (!theApp.m_cfg_data.m_hide_main_window || theApp.m_cfg_data.m_show_task_bar_wnd) { //每隔10秒钟检测一次是否可以嵌入任务栏 if (IsTaskbarWndValid() && m_timer_cnt % 10 == 1) { if (m_tBarDlg->GetCannotInsertToTaskBar() && m_insert_to_taskbar_cnt < MAX_INSERT_TO_TASKBAR_CNT) { CloseTaskBarWnd(); OpenTaskBarWnd(); m_insert_to_taskbar_cnt++; if (m_insert_to_taskbar_cnt == MAX_INSERT_TO_TASKBAR_CNT) { if (m_tBarDlg->GetCannotInsertToTaskBar() && m_cannot_intsert_to_task_bar_warning) //确保提示信息只弹出一次 { //写入错误日志 CString info; info.LoadString(IDS_CONNOT_INSERT_TO_TASKBAR_ERROR_LOG); info.Replace(_T("<%cnt%>"), CCommon::IntToString(m_insert_to_taskbar_cnt)); info.Replace(_T("<%error_code%>"), CCommon::IntToString(m_tBarDlg->GetErrorCode())); CCommon::WriteLog(info, theApp.m_log_path.c_str()); //弹出错误信息 MessageBox(CCommon::LoadText(IDS_CONNOT_INSERT_TO_TASKBAR, CCommon::IntToString(m_tBarDlg->GetErrorCode())), NULL, MB_ICONWARNING); m_cannot_intsert_to_task_bar_warning = false; } } } if (!m_tBarDlg->GetCannotInsertToTaskBar()) { m_insert_to_taskbar_cnt = 0; } } } //检查是否需要弹出鼠标提示 //setting_data: 消息提示的设置数据 //value: 当前的值 //last_value: 传递一个static或可以在此lambda表达式调用结束后继续存在的变量,用于保存上一次的值 //notify_time: 传递一个static或可以在此lambda表达式调用结束后继续存在的变量,用于记录上次弹出提示的时间(定时器触发次数) //tip_str: 要提示的消息 auto checkNotifyTip = [&](GeneralSettingData::NotifyTipSettings setting_data, int value, int& last_value, int& notify_time, LPCTSTR tip_str) { if (setting_data.enable) { if (last_value < setting_data.tip_value && value >= setting_data.tip_value && (m_timer_cnt - notify_time > static_cast(theApp.m_notify_interval))) { ShowNotifyTip(CCommon::LoadText(_T("TrafficMonitor "), IDS_NOTIFY), tip_str); notify_time = m_timer_cnt; } last_value = value; } }; //检查是否要弹出内存使用率超出提示 CString info; info.Format(CCommon::LoadText(IDS_MEMORY_UDAGE_EXCEED, _T(" %d%%!")), theApp.m_memory_usage); static int last_memory_usage; static int memory_usage_notify_time{ -theApp.m_notify_interval }; //记录上次弹出提示时的时间 checkNotifyTip(theApp.m_general_data.memory_usage_tip, theApp.m_memory_usage, last_memory_usage, memory_usage_notify_time, info.GetString()); //检查是否要弹出CPU温度使用率超出提示 info.Format(CCommon::LoadText(IDS_CPU_TEMPERATURE_EXCEED, _T(" %d°C!")), static_cast(theApp.m_cpu_temperature)); static int last_cpu_temp; static int cpu_temp_notify_time{ -theApp.m_notify_interval }; //记录上次弹出提示时的时间 checkNotifyTip(theApp.m_general_data.cpu_temp_tip, theApp.m_cpu_temperature, last_cpu_temp, cpu_temp_notify_time, info.GetString()); //检查是否要弹出显卡温度使用率超出提示 info.Format(CCommon::LoadText(IDS_GPU_TEMPERATURE_EXCEED, _T(" %d°C!")), static_cast(theApp.m_gpu_temperature)); static int last_gpu_temp; static int gpu_temp_notify_time{ -theApp.m_notify_interval }; //记录上次弹出提示时的时间 checkNotifyTip(theApp.m_general_data.gpu_temp_tip, theApp.m_gpu_temperature, last_gpu_temp, gpu_temp_notify_time, info.GetString()); //检查是否要弹出硬盘温度使用率超出提示 info.Format(CCommon::LoadText(IDS_HDD_TEMPERATURE_EXCEED, _T(" %d°C!")), static_cast(theApp.m_hdd_temperature)); static int last_hdd_temp; static int hdd_temp_notify_time{ -theApp.m_notify_interval }; //记录上次弹出提示时的时间 checkNotifyTip(theApp.m_general_data.hdd_temp_tip, theApp.m_hdd_temperature, last_hdd_temp, hdd_temp_notify_time, info.GetString()); //检查是否要弹出主板温度使用率超出提示 info.Format(CCommon::LoadText(IDS_MBD_TEMPERATURE_EXCEED, _T(" %d°C!")), static_cast(theApp.m_main_board_temperature)); static int last_main_board_temp; static int main_board_temp_notify_time{ -theApp.m_notify_interval }; //记录上次弹出提示时的时间 checkNotifyTip(theApp.m_general_data.mainboard_temp_tip, theApp.m_main_board_temperature, last_main_board_temp, main_board_temp_notify_time, info.GetString()); //检查是否要弹出流量使用超出提示 if (theApp.m_general_data.traffic_tip_enable) { static __int64 last_today_traffic; __int64 traffic_tip_value; if (theApp.m_general_data.traffic_tip_unit == 0) traffic_tip_value = static_cast<__int64>(theApp.m_general_data.traffic_tip_value) * 1024 * 1024; else traffic_tip_value = static_cast<__int64>(theApp.m_general_data.traffic_tip_value) * 1024 * 1024 * 1024; __int64 today_traffic = theApp.m_today_up_traffic + theApp.m_today_down_traffic; if (last_today_traffic < traffic_tip_value && today_traffic >= traffic_tip_value) { CString info = CCommon::LoadText(IDS_TODAY_TRAFFIC_EXCEED, CCommon::DataSizeToString(today_traffic)); ShowNotifyTip(CCommon::LoadText(_T("TrafficMonitor "), IDS_NOTIFY), info.GetString()); } last_today_traffic = today_traffic; } CWindowsSettingHelper::CheckWindows10LightTheme(); //每隔1秒钟检查一下当前系统是否为白色主题 //根据当前Win10颜色模式自动切换任务栏颜色 bool light_mode = CWindowsSettingHelper::IsWindows10LightTheme(); if (theApp.m_last_light_mode != light_mode) { theApp.m_last_light_mode = light_mode; bool restart_taskbar_dlg{ false }; if (theApp.m_taskbar_data.auto_adapt_light_theme) { int style_index = CWindowsSettingHelper::IsWindows10LightTheme() ? theApp.m_taskbar_data.light_default_style : theApp.m_taskbar_data.dark_default_style; theApp.m_taskbar_default_style.ApplyDefaultStyle(style_index, theApp.m_taskbar_data); theApp.SaveConfig(); restart_taskbar_dlg = true; } bool is_taskbar_transparent{ CTaskbarDefaultStyle::IsTaskbarTransparent(theApp.m_taskbar_data) }; if (!is_taskbar_transparent) { CTaskbarDefaultStyle::SetTaskabrTransparent(false, theApp.m_taskbar_data); restart_taskbar_dlg = true; } if (restart_taskbar_dlg && IsTaskbarWndValid()) { //m_tBarDlg->ApplyWindowTransparentColor(); CloseTaskBarWnd(); OpenTaskBarWnd(); //写入调试日志 if (theApp.m_debug_log) { CString log_str; log_str += _T("检测到 Windows10 深浅色变化。\n"); log_str += _T("IsWindows10LightTheme: "); log_str += std::to_wstring(light_mode).c_str(); log_str += _T("\n"); log_str += _T("auto_adapt_light_theme: "); log_str += std::to_wstring(theApp.m_taskbar_data.auto_adapt_light_theme).c_str(); log_str += _T("\n"); log_str += _T("is_taskbar_transparent: "); log_str += std::to_wstring(is_taskbar_transparent).c_str(); log_str += _T("\n"); log_str += _T("taskbar_back_color: "); log_str += std::to_wstring(theApp.m_taskbar_data.back_color).c_str(); log_str += _T("\n"); log_str += _T("taskbar_transparent_color: "); log_str += std::to_wstring(theApp.m_taskbar_data.transparent_color).c_str(); log_str += _T("\n"); log_str += _T("taskbar_text_colors: "); for (const auto& item : theApp.m_taskbar_data.text_colors) { log_str += std::to_wstring(item.second.label).c_str(); log_str += _T('|'); log_str += std::to_wstring(item.second.value).c_str(); log_str += _T(", "); } log_str += _T("\n"); CCommon::WriteLog(log_str, (theApp.m_config_dir + L".\\debug.log").c_str()); } } //根据当前Win10颜色模式自动切换通知区图标 if (theApp.m_cfg_data.m_notify_icon_auto_adapt) { int notify_icon_selected = theApp.m_cfg_data.m_notify_icon_selected; theApp.AutoSelectNotifyIcon(); if (notify_icon_selected != theApp.m_cfg_data.m_notify_icon_selected) { m_ntIcon.hIcon = theApp.m_notify_icons[theApp.m_cfg_data.m_notify_icon_selected]; if (theApp.m_general_data.show_notify_icon) { DeleteNotifyIcon(); AddNotifyIcon(); } } } } //根据任务栏颜色自动设置任务栏窗口背景色 if (theApp.m_taskbar_data.auto_set_background_color && theApp.m_win_version.IsWindows8OrLater() && IsTaskbarWndValid() && theApp.m_taskbar_data.transparent_color != 0 && !m_is_foreground_fullscreen) { CRect rect; ::GetWindowRect(m_tBarDlg->GetSafeHwnd(), rect); int pointx{ rect.left - 1 }; if (theApp.m_taskbar_data.tbar_wnd_on_left && m_tBarDlg->IsTasksbarOnTopOrBottom()) pointx = rect.right + 1; int pointy = rect.bottom; if (pointx < 0) pointx = 0; if (pointx >= m_screen_size.cx) pointx = m_screen_size.cx - 1; if (pointy < 0) pointy = 0; if (pointy >= m_screen_size.cy) pointy = m_screen_size.cy - 1; COLORREF color = ::GetPixel(m_desktop_dc, pointx, pointy); //取任务栏窗口左侧1像素处的颜色作为背景色 if (!CCommon::IsColorSimilar(color, theApp.m_taskbar_data.back_color) && (/*CWindowsSettingHelper::IsWindows10LightTheme() ||*/ color != 0)) { bool is_taskbar_transparent{ CTaskbarDefaultStyle::IsTaskbarTransparent(theApp.m_taskbar_data) }; theApp.m_taskbar_data.back_color = color; CTaskbarDefaultStyle::SetTaskabrTransparent(is_taskbar_transparent, theApp.m_taskbar_data); if (is_taskbar_transparent) m_tBarDlg->ApplyWindowTransparentColor(); } } //当检测到背景色和文字颜色都为黑色写入错误日志 static bool erro_log_write{ false }; if (theApp.m_taskbar_data.back_color == 0 && !theApp.m_taskbar_data.text_colors.empty() && theApp.m_taskbar_data.text_colors.begin()->second.label == 0) { if (!erro_log_write) { CString log_str; log_str.Format(_T("检查到背景色和文字颜色都为黑色。IsWindows10LightTheme: %d, 系统启动时间:%d/%.2d/%.2d %.2d:%.2d:%.2d"), light_mode, m_start_time.wYear, m_start_time.wMonth, m_start_time.wDay, m_start_time.wHour, m_start_time.wMinute, m_start_time.wSecond); CCommon::WriteLog(log_str, theApp.m_log_path.c_str()); erro_log_write = true; } } else { erro_log_write = false; } UpdateNotifyIconTip(); m_timer_cnt++; } if (nIDEvent == DELAY_TIMER) { AutoSelect(); KillTimer(DELAY_TIMER); } if (nIDEvent == TASKBAR_TIMER) { if (IsTaskbarWndValid()) { m_tBarDlg->AdjustWindowPos(); m_tBarDlg->Invalidate(FALSE); } } CDialog::OnTimer(nIDEvent); } void CTrafficMonitorDlg::OnRButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CheckClickedItem(point); if (m_clicked_item.is_plugin && m_clicked_item.plugin_item != nullptr) { ITMPlugin* plugin = theApp.m_plugins.GetPluginByItem(m_clicked_item.plugin_item); if (plugin != nullptr && plugin->GetAPIVersion() >= 3) { if (m_clicked_item.plugin_item->OnMouseEvent(IPluginItem::MT_RCLICKED, point.x, point.y, (void*)GetSafeHwnd(), 0) != 0) return; } } //设置点击鼠标右键弹出菜单 CMenu* pContextMenu = theApp.m_main_menu.GetSubMenu(0); //获取第一个弹出菜单,所以第一个菜单必须有子菜单 CPoint point1; //定义一个用于确定光标位置的位置 GetCursorPos(&point1); //获取当前光标的位置,以便使得菜单可以跟随光标 //设置默认菜单项 switch (theApp.m_main_wnd_data.double_click_action) { case DoubleClickAction::CONNECTION_INFO: pContextMenu->SetDefaultItem(ID_NETWORK_INFO); break; //case DoubleClickAction::HISTORY_TRAFFIC: // pContextMenu->SetDefaultItem(ID_TRAFFIC_HISTORY); // break; case DoubleClickAction::SHOW_MORE_INFO: pContextMenu->SetDefaultItem(ID_SHOW_CPU_MEMORY); break; case DoubleClickAction::OPTIONS: pContextMenu->SetDefaultItem(ID_OPTIONS); break; //case DoubleClickAction::CHANGE_SKIN: // pContextMenu->SetDefaultItem(ID_CHANGE_SKIN); // break; default: pContextMenu->SetDefaultItem(-1); break; } pContextMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, this); //在指定位置显示弹出菜单 CDialog::OnRButtonUp(nFlags, point1); } void CTrafficMonitorDlg::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //在未锁定窗口位置时允许通过点击窗口内部来拖动窗口 if (!theApp.m_main_wnd_data.m_lock_window_pos) PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y)); CDialog::OnLButtonDown(nFlags, point); } void CTrafficMonitorDlg::OnNetworkInfo() { // TODO: 在此添加命令处理程序代码 //弹出“连接详情”对话框 CNetworkInfoDlg aDlg(m_connections, m_pIfTable->table, m_connection_selected); ////向CNetworkInfoDlg类传递自启动以来已发送和接收的字节数 //aDlg.m_in_bytes = m_pIfTable->table[m_connections[m_connection_selected].index].dwInOctets - m_connections[m_connection_selected].in_bytes; //aDlg.m_out_bytes = m_pIfTable->table[m_connections[m_connection_selected].index].dwOutOctets - m_connections[m_connection_selected].out_bytes; aDlg.m_start_time = m_start_time; aDlg.DoModal(); //SetAlwaysOnTop(); //由于在“连接详情”对话框内设置了取消窗口置顶,所有在对话框关闭后,重新设置窗口置顶 if (m_tBarDlg != nullptr) m_tBarDlg->m_tool_tips.SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); //重新设置任务栏窗口的提示信息置顶 } void CTrafficMonitorDlg::OnAlwaysOnTop() { // TODO: 在此添加命令处理程序代码 theApp.m_main_wnd_data.m_always_on_top = !theApp.m_main_wnd_data.m_always_on_top; SetAlwaysOnTop(); theApp.SaveConfig(); } void CTrafficMonitorDlg::OnTransparency100() { // TODO: 在此添加命令处理程序代码 theApp.m_cfg_data.m_transparency = 100; SetTransparency(); theApp.SaveConfig(); } void CTrafficMonitorDlg::OnTransparency80() { // TODO: 在此添加命令处理程序代码 theApp.m_cfg_data.m_transparency = 80; SetTransparency(); theApp.SaveConfig(); } void CTrafficMonitorDlg::OnTransparency60() { // TODO: 在此添加命令处理程序代码 theApp.m_cfg_data.m_transparency = 60; SetTransparency(); theApp.SaveConfig(); } void CTrafficMonitorDlg::OnTransparency40() { // TODO: 在此添加命令处理程序代码 theApp.m_cfg_data.m_transparency = 40; SetTransparency(); theApp.SaveConfig(); } void CTrafficMonitorDlg::OnClose() { // TODO: 在此添加消息处理程序代码和/或调用默认值 theApp.m_cannot_save_config_warning = true; theApp.m_cannot_save_global_config_warning = true; theApp.SaveConfig(); //退出前保存设置到ini文件 theApp.SaveGlobalConfig(); SaveHistoryTraffic(); BackupHistoryTrafficFile(); if (IsTaskbarWndValid()) m_tBarDlg->OnCancel(); //确保在退出前关闭所有窗口 for (const auto& item : CBaseDialog::AllUniqueHandels()) { ::SendMessage(item.second, WM_COMMAND, IDCANCEL, 0); } CDialog::OnClose(); } BOOL CTrafficMonitorDlg::OnCommand(WPARAM wParam, LPARAM lParam) { // TODO: 在此添加专用代码和/或调用基类 UINT uMsg = LOWORD(wParam); if (uMsg == ID_SELECT_ALL_CONNECTION) { theApp.m_cfg_data.m_select_all = true; theApp.m_cfg_data.m_auto_select = false; m_connection_change_flag = true; } //选择了“选择网络连接”子菜单中项目时的处理 if (uMsg == ID_SELETE_CONNECTION) //选择了“自动选择”菜单项 { AutoSelect(); theApp.m_cfg_data.m_auto_select = true; theApp.m_cfg_data.m_select_all = false; theApp.SaveConfig(); m_connection_change_flag = true; } if (uMsg > ID_SELECT_ALL_CONNECTION && uMsg <= ID_SELECT_ALL_CONNECTION + m_connections.size()) //选择了一个网络连接 { m_connection_selected = uMsg - ID_SELECT_ALL_CONNECTION - 1; theApp.m_cfg_data.m_connection_name = GetConnection(m_connection_selected).description_2; m_connection_name_preferd = theApp.m_cfg_data.m_connection_name; theApp.m_cfg_data.m_auto_select = false; theApp.m_cfg_data.m_select_all = false; theApp.SaveConfig(); m_connection_change_flag = true; } #ifdef DEBUG if (uMsg == ID_CMD_TEST) { CTest::TestCommand(); } #endif // DEBUG return CDialog::OnCommand(wParam, lParam); } void CTrafficMonitorDlg::OnInitMenu(CMenu* pMenu) { CDialog::OnInitMenu(pMenu); // TODO: 在此处添加消息处理程序代码 m_menu_popuped = true; pMenu->CheckMenuItem(ID_ALWAYS_ON_TOP, MF_BYCOMMAND | (theApp.m_main_wnd_data.m_always_on_top ? MF_CHECKED : MF_UNCHECKED)); pMenu->CheckMenuItem(ID_LOCK_WINDOW_POS, MF_BYCOMMAND | (theApp.m_main_wnd_data.m_lock_window_pos ? MF_CHECKED : MF_UNCHECKED)); pMenu->CheckMenuItem(ID_SHOW_CPU_MEMORY, MF_BYCOMMAND | (theApp.m_cfg_data.m_show_more_info ? MF_CHECKED : MF_UNCHECKED)); pMenu->CheckMenuItem(ID_MOUSE_PENETRATE, MF_BYCOMMAND | (theApp.m_main_wnd_data.m_mouse_penetrate ? MF_CHECKED : MF_UNCHECKED)); pMenu->CheckMenuItem(ID_SHOW_TASK_BAR_WND, MF_BYCOMMAND | (theApp.m_cfg_data.m_show_task_bar_wnd ? MF_CHECKED : MF_UNCHECKED)); pMenu->CheckMenuItem(ID_SHOW_MAIN_WND, MF_BYCOMMAND | (!theApp.m_cfg_data.m_hide_main_window ? MF_CHECKED : MF_UNCHECKED)); pMenu->CheckMenuItem(ID_ALOW_OUT_OF_BORDER, MF_BYCOMMAND | (theApp.m_main_wnd_data.m_alow_out_of_border ? MF_CHECKED : MF_UNCHECKED)); //设置“选择连接”子菜单项中各单选项的选择状态 CMenu* select_connection_menu = theApp.m_main_menu.GetSubMenu(0)->GetSubMenu(0); SetConnectionMenuState(select_connection_menu); //设置“窗口不透明度”子菜单下各单选项的选择状态 switch (theApp.m_cfg_data.m_transparency) { case 100: pMenu->CheckMenuRadioItem(ID_TRANSPARENCY_100, ID_TRANSPARENCY_40, ID_TRANSPARENCY_100, MF_BYCOMMAND | MF_CHECKED); break; case 80: pMenu->CheckMenuRadioItem(ID_TRANSPARENCY_100, ID_TRANSPARENCY_40, ID_TRANSPARENCY_80, MF_BYCOMMAND | MF_CHECKED); break; case 60: pMenu->CheckMenuRadioItem(ID_TRANSPARENCY_100, ID_TRANSPARENCY_40, ID_TRANSPARENCY_60, MF_BYCOMMAND | MF_CHECKED); break; case 40: pMenu->CheckMenuRadioItem(ID_TRANSPARENCY_100, ID_TRANSPARENCY_40, ID_TRANSPARENCY_40, MF_BYCOMMAND | MF_CHECKED); break; default: break; } if (theApp.IsForceShowNotifyIcon()) //如果没有显示任务栏窗口,且隐藏了主窗口或设置了鼠标穿透,则禁用“显示通知区图标”菜单项 pMenu->EnableMenuItem(ID_SHOW_NOTIFY_ICON, MF_BYCOMMAND | MF_GRAYED); else pMenu->EnableMenuItem(ID_SHOW_NOTIFY_ICON, MF_BYCOMMAND | MF_ENABLED); pMenu->EnableMenuItem(ID_SELECT_ALL_CONNECTION, MF_BYCOMMAND | (theApp.m_general_data.show_all_interface ? MF_GRAYED : MF_ENABLED)); pMenu->EnableMenuItem(ID_CHECK_UPDATE, MF_BYCOMMAND | (theApp.IsCheckingForUpdate() ? MF_GRAYED : MF_ENABLED)); //pMenu->SetDefaultItem(ID_NETWORK_INFO); } BOOL CTrafficMonitorDlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 //屏蔽按回车键和ESC键退出 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) return TRUE; if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) return TRUE; if (theApp.m_main_wnd_data.show_tool_tip && m_tool_tips.GetSafeHwnd()) { m_tool_tips.RelayEvent(pMsg); } return CDialog::PreTranslateMessage(pMsg); } void CTrafficMonitorDlg::OnLockWindowPos() { // TODO: 在此添加命令处理程序代码 theApp.m_main_wnd_data.m_lock_window_pos = !theApp.m_main_wnd_data.m_lock_window_pos; theApp.SaveConfig(); } void CTrafficMonitorDlg::OnMove(int x, int y) { CDialog::OnMove(x, y); // TODO: 在此处添加消息处理程序代码 if (!m_first_start) { theApp.m_cfg_data.m_position_x = x; theApp.m_cfg_data.m_position_y = y; } ////确保窗口不会超出屏幕范围 //CheckWindowPos(); } afx_msg LRESULT CTrafficMonitorDlg::OnNotifyIcon(WPARAM wParam, LPARAM lParam) { bool dialog_exist{ false }; HWND handle{}; if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONUP || lParam == WM_LBUTTONDBLCLK) { for (const auto& item : CBaseDialog::AllUniqueHandels()) { if (IsWindow(item.second)) { dialog_exist = true; handle = item.second; break; } } } if (lParam == WM_LBUTTONDOWN) { if (!theApp.m_cfg_data.m_hide_main_window) { if (dialog_exist) //有打开的对话框时,点击通知区图标后将焦点设置到对话框 { ::SetForegroundWindow(handle); } else //没有打开的对话框时,则显示主窗口 { ShowWindow(SW_RESTORE); theApp.m_cfg_data.m_hide_main_window = false; SetForegroundWindow(); SetAlwaysOnTop(); CheckWindowPos(); theApp.SaveConfig(); } } } if (lParam == WM_RBUTTONUP) { if (dialog_exist) //有打开的对话框时,点击通知区图标后将焦点设置到对话框 { ::SetForegroundWindow(handle); } else { //在通知区点击右键弹出右键菜单 if (IsTaskbarWndValid()) //如果显示了任务栏窗口,则在右击了通知区图标后将焦点设置到任务栏窗口 m_tBarDlg->SetForegroundWindow(); else //否则将焦点设置到主窗口 SetForegroundWindow(); CPoint point1; //定义一个用于确定光标位置的位置 GetCursorPos(&point1); //获取当前光标的位置,以便使得菜单可以跟随光标 theApp.m_main_menu.GetSubMenu(0)->SetDefaultItem(-1); //设置没有默认菜单项 theApp.m_main_menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point1.x, point1.y, this); //在指定位置显示弹出菜单 CheckWindowPos(); } } if (lParam == WM_LBUTTONDBLCLK) { if (dialog_exist) //有打开的对话框时,点击通知区图标后将焦点设置到对话框 { ::SetForegroundWindow(handle); } else //没有打开的对话框时,则显示主窗口 { ShowWindow(SW_RESTORE); theApp.m_cfg_data.m_hide_main_window = false; SetForegroundWindow(); SetAlwaysOnTop(); CheckWindowPos(); theApp.SaveConfig(); } } return 0; } void CTrafficMonitorDlg::OnShowNotifyIcon() { // TODO: 在此添加命令处理程序代码 if (theApp.m_general_data.show_notify_icon) { DeleteNotifyIcon(); theApp.m_general_data.show_notify_icon = false; } else { AddNotifyIcon(); theApp.m_general_data.show_notify_icon = true; } theApp.SaveConfig(); } void CTrafficMonitorDlg::OnDestroy() { CDialog::OnDestroy(); //程序退出时删除通知栏图标 ::Shell_NotifyIcon(NIM_DELETE, &m_ntIcon); // TODO: 在此处添加消息处理程序代码 } void CTrafficMonitorDlg::OnShowCpuMemory() { // TODO: 在此添加命令处理程序代码 CRect rect; GetWindowRect(rect); theApp.m_cfg_data.m_show_more_info = !theApp.m_cfg_data.m_show_more_info; if (theApp.m_cfg_data.m_show_more_info) { rect.right = rect.left + m_skin.GetLayoutInfo().layout_l.width; rect.bottom = rect.top + m_skin.GetLayoutInfo().layout_l.width; MoveWindow(rect); CheckWindowPos(); } else { rect.right = rect.left + m_skin.GetLayoutInfo().layout_s.width; rect.bottom = rect.top + m_skin.GetLayoutInfo().layout_s.height; MoveWindow(rect); CheckWindowPos(); } LoadBackGroundImage(); SetItemPosition(); Invalidate(FALSE); theApp.SaveConfig(); } //任务栏窗口切换显示CPU和内存利用率时的处理 void CTrafficMonitorDlg::OnShowCpuMemory2() { // TODO: 在此添加命令处理程序代码 if (m_tBarDlg != nullptr) { bool show_cpu_memory = ((theApp.m_taskbar_data.m_tbar_display_item & TDI_CPU) || (theApp.m_taskbar_data.m_tbar_display_item & TDI_MEMORY)); if (show_cpu_memory) { theApp.m_taskbar_data.m_tbar_display_item &= ~TDI_CPU; theApp.m_taskbar_data.m_tbar_display_item &= ~TDI_MEMORY; } else { theApp.m_taskbar_data.m_tbar_display_item |= TDI_CPU; theApp.m_taskbar_data.m_tbar_display_item |= TDI_MEMORY; } //theApp.m_cfg_data.m_tbar_show_cpu_memory = !theApp.m_cfg_data.m_tbar_show_cpu_memory; //切换显示CPU和内存利用率时,删除任务栏窗口,再重新显示 CloseTaskBarWnd(); OpenTaskBarWnd(); } } void CTrafficMonitorDlg::OnMousePenetrate() { // TODO: 在此添加命令处理程序代码 theApp.m_main_wnd_data.m_mouse_penetrate = !theApp.m_main_wnd_data.m_mouse_penetrate; SetMousePenetrate(); if (!theApp.m_general_data.show_notify_icon && theApp.IsForceShowNotifyIcon()) //鼠标穿透时,如果通知图标没有显示,则将它显示出来,否则无法呼出右键菜单 { //添加通知栏图标 AddNotifyIcon(); theApp.m_general_data.show_notify_icon = true; } //设置鼠标穿透后,弹出消息提示用户如何关闭鼠标穿透 if (theApp.m_main_wnd_data.m_mouse_penetrate && theApp.m_show_mouse_panetrate_tip) { if (MessageBox(CCommon::LoadText(IDS_MOUSE_PENETRATE_TIP_INFO), NULL, MB_ICONINFORMATION | MB_OKCANCEL) == IDCANCEL) //点击“取消”后不再提示 { theApp.m_show_mouse_panetrate_tip = false; } } theApp.SaveConfig(); } void CTrafficMonitorDlg::OnShowTaskBarWnd() { // TODO: 在此添加命令处理程序代码 if (m_tBarDlg != nullptr) { CloseTaskBarWnd(); } if (!theApp.m_cfg_data.m_show_task_bar_wnd) { theApp.m_cfg_data.m_show_task_bar_wnd = true; OpenTaskBarWnd(); } else { theApp.m_cfg_data.m_show_task_bar_wnd = false; //关闭任务栏窗口后,如果没有显示通知区图标,且没有显示主窗口或设置了鼠标穿透,则将通知区图标显示出来 if (!theApp.m_general_data.show_notify_icon && theApp.IsForceShowNotifyIcon()) { AddNotifyIcon(); theApp.m_general_data.show_notify_icon = true; } } theApp.SaveConfig(); } void CTrafficMonitorDlg::OnAppAbout() { // TODO: 在此添加命令处理程序代码 //弹出“关于”对话框 CAboutDlg aDlg; aDlg.DoModal(); } //当资源管理器重启时会触发此消息 LRESULT CTrafficMonitorDlg::OnTaskBarCreated(WPARAM wParam, LPARAM lParam) { if (m_tBarDlg != nullptr) { CloseTaskBarWnd(); if (theApp.m_general_data.show_notify_icon) { //重新添加通知栏图标 ::Shell_NotifyIcon(NIM_ADD, &m_ntIcon); } OpenTaskBarWnd(); } else { if (theApp.m_general_data.show_notify_icon) ::Shell_NotifyIcon(NIM_ADD, &m_ntIcon); } return LRESULT(); } void CTrafficMonitorDlg::OnShowMainWnd() { // TODO: 在此添加命令处理程序代码 if (!theApp.m_cfg_data.m_hide_main_window) { ShowWindow(SW_HIDE); theApp.m_cfg_data.m_hide_main_window = true; //隐藏主窗口后,如果没有显示通知栏图标,则将其显示出来 if (!theApp.m_general_data.show_notify_icon && theApp.IsForceShowNotifyIcon()) { AddNotifyIcon(); theApp.m_general_data.show_notify_icon = true; } } else { ShowWindow(SW_RESTORE); theApp.m_cfg_data.m_hide_main_window = false; } theApp.SaveConfig(); } void CTrafficMonitorDlg::OnChangeSkin() { // TODO: 在此添加命令处理程序代码 CSkinDlg skinDlg; //初始化CSkinDlg对象的数据 skinDlg.m_skins = m_skins; skinDlg.m_skin_selected = m_skin_selected; skinDlg.m_pFont = &m_font; if (skinDlg.DoModal() == IDOK) { m_skin_selected = skinDlg.m_skin_selected; theApp.m_cfg_data.m_skin_name = m_skins[m_skin_selected]; //获取皮肤布局 LoadSkinLayout(); //载入背景图片 LoadBackGroundImage(); //获取皮肤的文字颜色 theApp.m_main_wnd_data.specify_each_item_color = skinDlg.GetSkinData().GetSkinInfo().specify_each_item_color; int i{}; for (const auto& item : theApp.m_plugins.AllDisplayItemsWithPlugins()) { theApp.m_main_wnd_data.text_colors[item] = skinDlg.GetSkinData().GetSkinInfo().TextColor(i); i++; } //SetTextColor(); //获取皮肤的字体 if (theApp.m_general_data.allow_skin_cover_font) { if (!skinDlg.GetSkinData().GetSkinInfo().font_info.name.IsEmpty()) { theApp.m_main_wnd_data.font.name = skinDlg.GetSkinData().GetSkinInfo().font_info.name; theApp.m_main_wnd_data.font.bold = skinDlg.GetSkinData().GetSkinInfo().font_info.bold; theApp.m_main_wnd_data.font.italic = skinDlg.GetSkinData().GetSkinInfo().font_info.italic; theApp.m_main_wnd_data.font.underline = skinDlg.GetSkinData().GetSkinInfo().font_info.underline; theApp.m_main_wnd_data.font.strike_out = skinDlg.GetSkinData().GetSkinInfo().font_info.strike_out; } if (skinDlg.GetSkinData().GetSkinInfo().font_info.size >= MIN_FONT_SIZE && skinDlg.GetSkinData().GetSkinInfo().font_info.size <= MAX_FONT_SIZE) theApp.m_main_wnd_data.font.size = skinDlg.GetSkinData().GetSkinInfo().font_info.size; SetTextFont(); } //获取项目的显示文本 if (theApp.m_general_data.allow_skin_cover_text && !skinDlg.GetSkinData().GetLayoutInfo().no_label) { theApp.m_main_wnd_data.disp_str = skinDlg.GetSkinData().GetSkinInfo().display_text; } SetItemPosition(); Invalidate(FALSE); //更换皮肤后立即刷新窗口信息 theApp.SaveConfig(); } } void CTrafficMonitorDlg::OnTrafficHistory() { // TODO: 在此添加命令处理程序代码 CHistoryTrafficDlg historyDlg(m_history_traffic.GetTraffics()); historyDlg.DoModal(); } void CTrafficMonitorDlg::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CDialog::OnMouseMove(nFlags, point); } void CTrafficMonitorDlg::OnLButtonDblClk(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CheckClickedItem(point); if (m_clicked_item.is_plugin && m_clicked_item.plugin_item != nullptr) { ITMPlugin* plugin = theApp.m_plugins.GetPluginByItem(m_clicked_item.plugin_item); if (plugin != nullptr && plugin->GetAPIVersion() >= 3) { if (m_clicked_item.plugin_item->OnMouseEvent(IPluginItem::MT_DBCLICKED, point.x, point.y, (void*)GetSafeHwnd(), 0) != 0) return; } } switch (theApp.m_main_wnd_data.double_click_action) { case DoubleClickAction::CONNECTION_INFO: OnNetworkInfo(); //双击后弹出“连接详情”对话框 break; case DoubleClickAction::HISTORY_TRAFFIC: OnTrafficHistory(); //双击后弹出“历史流量统计”对话框 break; case DoubleClickAction::SHOW_MORE_INFO: OnShowCpuMemory(); //切换显示CPU和内存利用率 break; case DoubleClickAction::OPTIONS: OnOptions(); //双击后弹出“选项设置”对话框 break; case DoubleClickAction::TASK_MANAGER: ShellExecuteW(NULL, _T("open"), (theApp.m_system_dir + L"\\Taskmgr.exe").c_str(), NULL, NULL, SW_NORMAL); //打开任务管理器 break; case DoubleClickAction::SEPCIFIC_APP: ShellExecuteW(NULL, _T("open"), (theApp.m_main_wnd_data.double_click_exe).c_str(), NULL, NULL, SW_NORMAL); //打开指定程序,默认任务管理器 break; case DoubleClickAction::CHANGE_SKIN: OnChangeSkin(); //双击后弹出“更换皮肤”对话框 break; default: break; } CDialog::OnLButtonDblClk(nFlags, point); } void CTrafficMonitorDlg::OnOptions() { // TODO: 在此添加命令处理程序代码 _OnOptions(0); } //通过任务栏窗口的右键菜单打开“选项”对话框 void CTrafficMonitorDlg::OnOptions2() { // TODO: 在此添加命令处理程序代码 //判断任务栏窗口中点击的项目是否是插件项目 if (IsTaskbarWndValid() && m_tBarDlg->GetClickedItem().is_plugin) { //找到对应的插件 ITMPlugin* plugin = theApp.m_plugins.GetPluginByItem(m_tBarDlg->GetClickedItem().plugin_item); if (plugin != nullptr) { //显示插件的选项设置 auto rtn = plugin->ShowOptionsDialog(GetSafeHwnd()); if (rtn == ITMPlugin::OR_OPTION_CHANGED) //选项设置有更改,重新打开任务栏窗口 { CloseTaskBarWnd(); OpenTaskBarWnd(); } if (rtn != ITMPlugin::OR_OPTION_NOT_PROVIDED) return; } } _OnOptions(1); } afx_msg LRESULT CTrafficMonitorDlg::OnExitmenuloop(WPARAM wParam, LPARAM lParam) { m_menu_popuped = false; return 0; } void CTrafficMonitorDlg::OnChangeNotifyIcon() { // TODO: 在此添加命令处理程序代码 CIconSelectDlg dlg(theApp.m_cfg_data.m_notify_icon_selected); dlg.SetAutoAdaptNotifyIcon(theApp.m_cfg_data.m_notify_icon_auto_adapt); if (dlg.DoModal() == IDOK) { theApp.m_cfg_data.m_notify_icon_selected = dlg.GetIconSelected(); theApp.m_cfg_data.m_notify_icon_auto_adapt = dlg.AutoAdaptNotifyIcon(); m_ntIcon.hIcon = theApp.m_notify_icons[theApp.m_cfg_data.m_notify_icon_selected]; if (theApp.m_cfg_data.m_notify_icon_auto_adapt) theApp.AutoSelectNotifyIcon(); if (theApp.m_general_data.show_notify_icon) { DeleteNotifyIcon(); AddNotifyIcon(); } theApp.SaveConfig(); } } void CTrafficMonitorDlg::OnAlowOutOfBorder() { // TODO: 在此添加命令处理程序代码 theApp.m_main_wnd_data.m_alow_out_of_border = !theApp.m_main_wnd_data.m_alow_out_of_border; CheckWindowPos(); } void CTrafficMonitorDlg::OnCheckUpdate() { // TODO: 在此添加命令处理程序代码 theApp.CheckUpdateInThread(true); } afx_msg LRESULT CTrafficMonitorDlg::OnTaskbarMenuPopedUp(WPARAM wParam, LPARAM lParam) { //设置“选择连接”子菜单项中各单选项的选择状态 CMenu* select_connection_menu = theApp.m_taskbar_menu.GetSubMenu(0)->GetSubMenu(0); SetConnectionMenuState(select_connection_menu); return 0; } //任务栏窗口切换显示网速时的处理 void CTrafficMonitorDlg::OnShowNetSpeed() { // TODO: 在此添加命令处理程序代码 if (m_tBarDlg != nullptr) { bool show_net_speed = ((theApp.m_taskbar_data.m_tbar_display_item & TDI_UP) || (theApp.m_taskbar_data.m_tbar_display_item & TDI_DOWN)); if (show_net_speed) { theApp.m_taskbar_data.m_tbar_display_item &= ~TDI_UP; theApp.m_taskbar_data.m_tbar_display_item &= ~TDI_DOWN; } else { theApp.m_taskbar_data.m_tbar_display_item |= TDI_UP; theApp.m_taskbar_data.m_tbar_display_item |= TDI_DOWN; } CloseTaskBarWnd(); OpenTaskBarWnd(); } } BOOL CTrafficMonitorDlg::OnQueryEndSession() { if (!CDialog::OnQueryEndSession()) return FALSE; // TODO: 在此添加专用的查询结束会话代码 theApp.SaveConfig(); theApp.SaveGlobalConfig(); SaveHistoryTraffic(); BackupHistoryTrafficFile(); if (theApp.m_debug_log) { CCommon::WriteLog(_T("TrafficMonitor进程已被终止,设置已保存。"), (theApp.m_config_dir + L".\\debug.log").c_str()); } return TRUE; } void CTrafficMonitorDlg::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CDialog::OnPaint() m_skin.DrawInfo(&dc, theApp.m_cfg_data.m_show_more_info, m_font); } afx_msg LRESULT CTrafficMonitorDlg::OnDpichanged(WPARAM wParam, LPARAM lParam) { int dpi = LOWORD(wParam); theApp.SetDPI(dpi); if (IsTaskbarWndValid()) { //根据新的DPI重新设置任务栏窗口字体 m_tBarDlg->SetTextFont(); } LoadSkinLayout(); //根据当前选择的皮肤获取布局数据 SetItemPosition(); //初始化窗口位置 LoadBackGroundImage(); SetTextFont(); //重新加载字体 Invalidate(FALSE); //重绘界面 return 0; } afx_msg LRESULT CTrafficMonitorDlg::OnTaskbarWndClosed(WPARAM wParam, LPARAM lParam) { theApp.m_cfg_data.m_show_task_bar_wnd = false; //关闭任务栏窗口后,如果没有显示通知区图标,且没有显示主窗口或设置了鼠标穿透,则将通知区图标显示出来 if (!theApp.m_general_data.show_notify_icon && theApp.IsForceShowNotifyIcon()) { AddNotifyIcon(); theApp.m_general_data.show_notify_icon = true; } return 0; } afx_msg LRESULT CTrafficMonitorDlg::OnMonitorInfoUpdated(WPARAM wParam, LPARAM lParam) { Invalidate(FALSE); //刷新窗口信息 //更新鼠标提示 if (theApp.m_main_wnd_data.show_tool_tip && m_tool_tips.GetSafeHwnd() != NULL) { CString tip_info; tip_info = GetMouseTipsInfo(); m_tool_tips.UpdateTipText(tip_info, this); } //更新任务栏窗口鼠标提示 if (IsTaskbarWndValid()) m_tBarDlg->UpdateToolTips(); return 0; } LRESULT CTrafficMonitorDlg::OnDisplaychange(WPARAM wParam, LPARAM lParam) { GetScreenSize(); CheckWindowPos(true); return 0; } void CTrafficMonitorDlg::OnExitSizeMove() { // TODO: 在此添加消息处理程序代码和/或调用默认值 CheckWindowPos(); CDialog::OnExitSizeMove(); } void CTrafficMonitorDlg::OnPluginManage() { // TODO: 在此添加命令处理程序代码 CPluginManagerDlg dlg; dlg.DoModal(); } LRESULT CTrafficMonitorDlg::OnReopenTaksbarWnd(WPARAM wParam, LPARAM lParam) { CloseTaskBarWnd(); OpenTaskBarWnd(); return 0; } void CTrafficMonitorDlg::OnOpenTaskManager() { ShellExecuteW(NULL, _T("open"), (theApp.m_system_dir + L"\\Taskmgr.exe").c_str(), NULL, NULL, SW_NORMAL); //打开任务管理器 } afx_msg LRESULT CTrafficMonitorDlg::OnSettingsApplied(WPARAM wParam, LPARAM lParam) { COptionsDlg* pOptionsDlg = (COptionsDlg*)wParam; if (pOptionsDlg != nullptr) { ApplySettings(*pOptionsDlg); } return 0; } void CTrafficMonitorDlg::OnDisplaySettings() { // TODO: 在此添加命令处理程序代码 CSetItemOrderDlg dlg; dlg.SetItemOrder(theApp.m_taskbar_data.item_order.GetItemOrderConst()); dlg.SetDisplayItem(theApp.m_taskbar_data.m_tbar_display_item); dlg.SetPluginDisplayItem(theApp.m_taskbar_data.plugin_display_item); if (dlg.DoModal() == IDOK) { theApp.m_taskbar_data.item_order.SetOrder(dlg.GetItemOrder()); theApp.m_taskbar_data.m_tbar_display_item = dlg.GetDisplayItem(); theApp.m_taskbar_data.plugin_display_item = dlg.GetPluginDisplayItem(); CloseTaskBarWnd(); OpenTaskBarWnd(); } } void CTrafficMonitorDlg::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CheckClickedItem(point); if (m_clicked_item.is_plugin && m_clicked_item.plugin_item != nullptr) { ITMPlugin* plugin = theApp.m_plugins.GetPluginByItem(m_clicked_item.plugin_item); if (plugin != nullptr && plugin->GetAPIVersion() >= 3) { if (m_clicked_item.plugin_item->OnMouseEvent(IPluginItem::MT_LCLICKED, point.x, point.y, (void*)GetSafeHwnd(), 0) != 0) return; } } CDialog::OnLButtonUp(nFlags, point); } void CTrafficMonitorDlg::OnRefreshConnectionList() { IniConnection(); } ================================================ FILE: TrafficMonitor/TrafficMonitorDlg.h ================================================  // TrafficMonitorDlg.h : 头文件 // #pragma once #pragma comment (lib, "iphlpapi.lib") #include "NetworkInfoDlg.h" #include "afxwin.h" #include "StaticEx.h" #include "Common.h" #include "TaskBarDlg.h" #include "SkinDlg.h" #include "HistoryTrafficDlg.h" #include "OptionsDlg.h" #include "PictureStatic.h" #include "IconSelectDlg.h" #include "DrawCommon.h" #include "IniHelper.h" #include "LinkStatic.h" #include "AdapterCommon.h" #include "AboutDlg.h" #include "CPUUsage.h" #include "HistoryTrafficFile.h" #include "HighResolutionTimer.h" // CTrafficMonitorDlg 对话框 class CTrafficMonitorDlg : public CDialog { // 构造 public: CTrafficMonitorDlg(CWnd* pParent = NULL); // 标准构造函数 ~CTrafficMonitorDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_TRAFFICMONITOR_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; NOTIFYICONDATA m_ntIcon; //通知区域图标 CTaskBarDlg* m_tBarDlg{}; //任务栏窗口的指针 vector m_connections; //保存获取到的要显示到“选择网卡”菜单项中的所有网络连接 MIB_IFTABLE* m_pIfTable; DWORD m_dwSize{}; //m_pIfTable的大小 int m_connection_selected{ 0 }; //要显示流量的连接的序号 unsigned __int64 m_in_bytes{}; //当前已接收的字节数 unsigned __int64 m_out_bytes{}; //当前已发送的字节数 unsigned __int64 m_last_in_bytes{}; //上次已接收的字节数 unsigned __int64 m_last_out_bytes{}; //上次已发送的字节数 CCPUUsage m_cpu_usage; bool m_first_start{ true }; //初始时为true,在定时器第一次启动后置为flase // https://www.jianshu.com/p/9d4b68cdbd99 struct Monitors { std::vector monitorinfos; static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData) { MONITORINFO iMonitor; iMonitor.cbSize = sizeof(MONITORINFO); GetMonitorInfo(hMon, &iMonitor); Monitors* pThis = reinterpret_cast(pData); pThis->monitorinfos.push_back(iMonitor); return TRUE; } Monitors() { EnumDisplayMonitors(0, 0, MonitorEnum, (LPARAM)this); } }; //CRect m_screen_rect; //屏幕的范围(不包含任务栏) vector m_screen_rects; //所有屏幕的范围(不包含任务栏) vector m_last_screen_rects; //上一次所有屏幕的范围(不包含任务栏) CSize m_screen_size; //屏幕的大小(包含任务栏) CSkinFile m_skin; CommonDisplayItem m_clicked_item; //鼠标点击的项目 CFont m_font; //字体 int m_restart_cnt{ -1 }; //重新初始化次数 unsigned int m_timer_cnt{}; //定时器触发次数(自程序启动以来的秒数) unsigned int m_monitor_time_cnt{}; int m_zero_speed_cnt{}; //如果检测不到网速,该变量就会自加 int m_insert_to_taskbar_cnt{}; //用来统计尝试嵌入任务栏的次数 int m_cannot_intsert_to_task_bar_warning{ true }; //指示是否会在无法嵌入任务栏时弹出提示框 static unsigned int m_WM_TASKBARCREATED; //任务栏重启消息 vector m_skins; //储存皮肤文件的路径 int m_skin_selected{}; //选择的皮肤序号 SYSTEMTIME m_start_time; //程序启动时的时间 CHistoryTrafficFile m_history_traffic{ theApp.m_history_traffic_path }; //储存历史流量 CToolTipCtrl m_tool_tips; bool m_connection_change_flag{ false }; //如果执行过IniConnection()函数,该flag会置为true bool m_is_foreground_fullscreen{ false }; //指示前台窗口是否正在全局显示 bool m_menu_popuped{ false }; //指示当前是否有菜单处于弹出状态 HDC m_desktop_dc; string m_connection_name_preferd{ theApp.m_cfg_data.m_connection_name }; //保存用户手动选择的网络连接名称 //CHighResolutionTimer m_timer; // 采用多媒体定时器(也防止了界面阻塞出现的卡顿现象) CCriticalSection m_critical; static UINT MonitorThreadCallback(LPVOID dwUser); bool m_is_monitor_thread_runing{ false }; CString GetMouseTipsInfo(); //获取鼠标提示信息 void SetTransparency(); //根据m_transparency的值设置窗口透明度 void SetTransparency(int transparency); void SetAlwaysOnTop(); //根据m_always_on_top的值设置窗口置顶 void SetMousePenetrate(); //根据m_mouse_penetrate的值设置是否鼠标穿透 POINT CalculateWindowMoveOffset(CRect rect, bool screen_changed); //计算当窗口处于屏幕区域外时,移动到屏幕区域需要移动的位置 void CheckWindowPos(bool screen_changed = false); //测试窗口的位置,如窗口的位置在屏幕外,则移动窗口使其全部都在屏幕内,并返回新位置 void GetScreenSize(); //获取屏幕的大小 void AutoSelect(); //void UpdateConnections(); //自动选择连接 void IniConnection(); //初始化连接 MIB_IFROW GetConnectIfTable(int connection_index); //获取当前选择的网络连接的MIB_IFROW对象。connection_index为m_connections中的索引 NetWorkConection GetConnection(int connection_index); //获取当前选择的网络连接的NetWorkConection对象。connection_index为m_connections中的索引 void IniConnectionMenu(CMenu* pMenu); //初始化“选择网络连接”菜单 void IniTaskBarConnectionMenu(); //初始化任务栏窗口的“选择网络连接”菜单 void SetConnectionMenuState(CMenu* pMenu); //设置“选择网络连接”菜单中选中的项目 void CloseTaskBarWnd(); //关闭任务栏窗口 void OpenTaskBarWnd(); //打开任务栏窗口 void AddNotifyIcon(); //添加通知区图标 void DeleteNotifyIcon(); void ShowNotifyTip(const wchar_t* title, const wchar_t* message); //显示通知区提示 void UpdateNotifyIconTip(); //更新通知区图标的鼠标提示 void SaveHistoryTraffic(); void LoadHistoryTraffic(); void BackupHistoryTrafficFile(); void _OnOptions(int tab); //打开“选项”对话框的处理,参数为打开时切换的标签 void ApplySettings(COptionsDlg& optionsDlg); void SetItemPosition(); //设置显示的4个项目的位置 void LoadSkinLayout(); //从当前皮肤获取布局数据 void LoadBackGroundImage(); void SetTextFont(); bool IsTaskbarWndValid() const; void TaskbarShowHideItem(DisplayItem type); //判断一个点在哪个显示项目的区域内,并保存到m_clicked_item void CheckClickedItem(CPoint point); public: //void ApplySettings(); bool IsTemperatureNeeded() const; //判断是否需要显示温度信息 protected: // 生成的消息映射函数 virtual BOOL OnInitDialog(); // afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: // afx_msg LRESULT OnNcHitTest(CPoint point); afx_msg void OnTimer(UINT_PTR nIDEvent); // afx_msg void OnRButtonDown(UINT nFlags, CPoint point); afx_msg void OnRButtonUp(UINT nFlags, CPoint point); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnNetworkInfo(); afx_msg void OnAlwaysOnTop(); afx_msg void OnTransparency100(); afx_msg void OnTransparency80(); afx_msg void OnTransparency60(); afx_msg void OnTransparency40(); afx_msg void OnClose(); virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); afx_msg void OnInitMenu(CMenu* pMenu); virtual BOOL PreTranslateMessage(MSG* pMsg); afx_msg void OnLockWindowPos(); afx_msg void OnMove(int x, int y); protected: afx_msg LRESULT OnNotifyIcon(WPARAM wParam, LPARAM lParam); public: afx_msg void OnShowNotifyIcon(); afx_msg void OnDestroy(); afx_msg void OnShowCpuMemory(); afx_msg void OnMousePenetrate(); //afx_msg void OnTextColor(); afx_msg void OnShowTaskBarWnd(); afx_msg void OnAppAbout(); afx_msg void OnShowCpuMemory2(); afx_msg void OnShowMainWnd(); afx_msg void OnChangeSkin(); afx_msg LRESULT OnTaskBarCreated(WPARAM wParam, LPARAM lParam); //afx_msg void OnSetFont(); afx_msg void OnTrafficHistory(); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); afx_msg void OnOptions(); afx_msg void OnOptions2(); protected: afx_msg LRESULT OnExitmenuloop(WPARAM wParam, LPARAM lParam); public: afx_msg void OnChangeNotifyIcon(); afx_msg void OnAlowOutOfBorder(); afx_msg void OnCheckUpdate(); protected: afx_msg LRESULT OnTaskbarMenuPopedUp(WPARAM wParam, LPARAM lParam); public: afx_msg void OnShowNetSpeed(); afx_msg BOOL OnQueryEndSession(); afx_msg void OnPaint(); protected: afx_msg LRESULT OnDpichanged(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnTaskbarWndClosed(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnMonitorInfoUpdated(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnDisplaychange(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnReopenTaksbarWnd(WPARAM wParam, LPARAM lParam); public: afx_msg void OnExitSizeMove(); afx_msg void OnPluginManage(); afx_msg void OnOpenTaskManager(); protected: afx_msg LRESULT OnSettingsApplied(WPARAM wParam, LPARAM lParam); public: afx_msg void OnDisplaySettings(); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnRefreshConnectionList(); }; ================================================ FILE: TrafficMonitor/UpdateHelper.cpp ================================================ #include "stdafx.h" #include "UpdateHelper.h" #include "SimpleXML.h" #include "Common.h" CUpdateHelper::CUpdateHelper() { } CUpdateHelper::~CUpdateHelper() { } void CUpdateHelper::SetUpdateSource(UpdateSource update_source) { m_update_source = update_source; } bool CUpdateHelper::CheckForUpdate() { wstring version_info; //使用GitHub更新源 if (m_update_source == UpdateSource::GitHubSource) { if (CCommon::GetURL(L"https://raw.githubusercontent.com/zhongyang219/TrafficMonitor/master/version_utf8.info", version_info, true)) //获取版本信息 { m_row_data = true; } else if (CCommon::GetURL(L"https://github.com/zhongyang219/TrafficMonitor/blob/master/version_utf8.info", version_info, true)) //获取版本信息 { m_row_data = false; } else { return false; } if (!m_row_data) { size_t index = version_info.find(L"<version>"); if (index != std::wstring::npos) version_info = version_info.substr(index); CString str_version_info = version_info.c_str(); str_version_info.Replace(L"<", L"<"); str_version_info.Replace(L">", L">"); version_info = str_version_info; } } //使用Gitee更新源 else { if (!CCommon::GetURL(L"https://gitee.com/zhongyang219/TrafficMonitor/raw/master/version_utf8.info", version_info, true)) //获取版本信息 return false; } ParseUpdateInfo(version_info); return true; } void CUpdateHelper::ParseUpdateInfo(wstring version_info) { CSimpleXML version_xml; version_xml.LoadXMLContentDirect(version_info); m_version = version_xml.GetNode(L"version"); wstring str_source_tag = (m_update_source == UpdateSource::GitHubSource ? L"GitHub" : L"Gitee"); wstring str_link_tag, str_link_tag_x64; #ifdef WITHOUT_TEMPERATURE str_link_tag = L"link_without_temperature"; str_link_tag_x64 = L"link_without_temperature_x64"; #else str_link_tag = L"link"; str_link_tag_x64 = L"link_x64"; #endif m_link64 = version_xml.GetNode(str_link_tag_x64.c_str(), str_source_tag.c_str()); m_link = version_xml.GetNode(str_link_tag.c_str(), str_source_tag.c_str()); CString contents_zh_cn = version_xml.GetNode(L"contents_zh_cn", L"update_contents").c_str(); CString contents_en = version_xml.GetNode(L"contents_en", L"update_contents").c_str(); CString contents_zh_tw = version_xml.GetNode(L"contents_zh_tw", L"update_contents").c_str(); contents_zh_cn.Replace(L"\\n", L"\r\n"); contents_en.Replace(L"\\n", L"\r\n"); contents_zh_tw.Replace(L"\\n", L"\r\n"); m_contents_zh_cn = contents_zh_cn; m_contents_en = contents_en; m_contents_zh_tw = contents_zh_tw; } const std::wstring& CUpdateHelper::GetVersion() const { return m_version; } const std::wstring& CUpdateHelper::GetLink() const { return m_link; } const std::wstring& CUpdateHelper::GetLink64() const { return m_link64; } const std::wstring& CUpdateHelper::GetContentsEn() const { return m_contents_en; } const std::wstring& CUpdateHelper::GetContentsZhCn() const { return m_contents_zh_cn; } const std::wstring& CUpdateHelper::GetContentsZhTw() const { return m_contents_zh_tw; } bool CUpdateHelper::IsRowData() { return m_row_data; } ================================================ FILE: TrafficMonitor/UpdateHelper.h ================================================ #pragma once class CUpdateHelper { public: CUpdateHelper(); ~CUpdateHelper(); enum class UpdateSource { GitHubSource, GiteeSource }; void SetUpdateSource(UpdateSource update_source); bool CheckForUpdate(); const std::wstring& GetVersion() const; const std::wstring& GetLink() const; const std::wstring& GetLink64() const; const std::wstring& GetContentsEn() const; const std::wstring& GetContentsZhCn() const; const std::wstring& GetContentsZhTw() const; bool IsRowData(); private: void ParseUpdateInfo(wstring version_info); private: std::wstring m_version; std::wstring m_link; std::wstring m_link64; std::wstring m_contents_en; std::wstring m_contents_zh_cn; std::wstring m_contents_zh_tw; bool m_row_data{ true }; UpdateSource m_update_source{ UpdateSource::GitHubSource }; }; ================================================ FILE: TrafficMonitor/WIC.cpp ================================================ #include "stdafx.h" #include "WIC.h" CWICFactory CWICFactory::m_instance; CWICFactory::CWICFactory() { //ʼm_pWICFactory _hrOleInit = ::OleInitialize(NULL); #ifndef COMPILE_FOR_WINXP CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pWICFactory)); if (m_pWICFactory == nullptr) CoCreateInstance(CLSID_WICImagingFactory1, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pWICFactory)); #endif } CWICFactory::~CWICFactory() { if (m_pWICFactory) { m_pWICFactory->Release(); m_pWICFactory = NULL; } if (SUCCEEDED(_hrOleInit)) { OleUninitialize(); } } ////////////////////////////////////////////////////////// typedef DWORD ARGB; CMenuIcon::CMenuIcon() { } CMenuIcon::~CMenuIcon() { } HRESULT CMenuIcon::AddIconToMenuItem(HMENU hmenu, int iMenuItem, BOOL fByPosition, HICON hicon) { #ifndef COMPILE_FOR_WINXP if (CWICFactory::GetWIC() == nullptr) return 0; HBITMAP hbmp = NULL; IWICBitmap *pBitmap; HRESULT hr = CWICFactory::GetWIC()->CreateBitmapFromHICON(hicon, &pBitmap); if (SUCCEEDED(hr)) { IWICFormatConverter *pConverter; hr = CWICFactory::GetWIC()->CreateFormatConverter(&pConverter); if (SUCCEEDED(hr)) { hr = pConverter->Initialize(pBitmap, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom); if (SUCCEEDED(hr)) { UINT cx, cy; hr = pConverter->GetSize(&cx, &cy); if (SUCCEEDED(hr)) { const SIZE sizIcon = { (int)cx, -(int)cy }; BYTE *pbBuffer; hr = Create32BitHBITMAP(NULL, &sizIcon, reinterpret_cast(&pbBuffer), &hbmp); if (SUCCEEDED(hr)) { const UINT cbStride = cx * sizeof(ARGB); const UINT cbBuffer = cy * cbStride; hr = pConverter->CopyPixels(NULL, cbStride, cbBuffer, pbBuffer); } } } pConverter->Release(); } pBitmap->Release(); } if (SUCCEEDED(hr)) { hr = AddBitmapToMenuItem(hmenu, iMenuItem, fByPosition, hbmp); } if (FAILED(hr)) { DeleteObject(hbmp); hbmp = NULL; } return hr; #else return 0; #endif } HRESULT CMenuIcon::AddBitmapToMenuItem(HMENU hmenu, int iItem, BOOL fByPosition, HBITMAP hbmp) { HRESULT hr = E_FAIL; MENUITEMINFO mii = { sizeof(mii) }; mii.fMask = MIIM_BITMAP; mii.hbmpItem = hbmp; if (SetMenuItemInfo(hmenu, iItem, fByPosition, &mii)) { hr = S_OK; } return hr; } void CMenuIcon::InitBitmapInfo(BITMAPINFO * pbmi, ULONG cbInfo, LONG cx, LONG cy, WORD bpp) { ZeroMemory(pbmi, cbInfo); pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pbmi->bmiHeader.biPlanes = 1; pbmi->bmiHeader.biCompression = BI_RGB; pbmi->bmiHeader.biWidth = cx; pbmi->bmiHeader.biHeight = cy; pbmi->bmiHeader.biBitCount = bpp; } HRESULT CMenuIcon::Create32BitHBITMAP(HDC hdc, const SIZE * psize, void ** ppvBits, HBITMAP * phBmp) { *phBmp = NULL; BITMAPINFO bmi; InitBitmapInfo(&bmi, sizeof(bmi), psize->cx, psize->cy, 32); HDC hdcUsed = hdc ? hdc : GetDC(NULL); if (hdcUsed) { *phBmp = CreateDIBSection(hdcUsed, &bmi, DIB_RGB_COLORS, ppvBits, NULL, 0); if (hdc != hdcUsed) { ReleaseDC(NULL, hdcUsed); } } return (NULL == *phBmp) ? E_OUTOFMEMORY : S_OK; } ================================================ FILE: TrafficMonitor/WIC.h ================================================ //ʹ Windows ӳWICͼ꣨HICONתΪ͸ȵPARGB32λͼӵ˵ //https://docs.microsoft.com/en-us/previous-versions/bb757020(v=msdn.10) #pragma once class CWICFactory { public: ~CWICFactory(); static IWICImagingFactory* GetWIC() { return m_instance.m_pWICFactory; } private: HRESULT _hrOleInit{}; IWICImagingFactory *m_pWICFactory{}; static CWICFactory m_instance; //CWICFactoryΨһĶ private: CWICFactory(); }; class CMenuIcon { public: CMenuIcon(); ~CMenuIcon(); //һ˵ͼ static HRESULT AddIconToMenuItem(HMENU hmenu, int iMenuItem, BOOL fByPosition, HICON hicon); private: static HRESULT AddBitmapToMenuItem(HMENU hmenu, int iItem, BOOL fByPosition, HBITMAP hbmp); static void InitBitmapInfo(__out_bcount(cbInfo) BITMAPINFO *pbmi, ULONG cbInfo, LONG cx, LONG cy, WORD bpp); static HRESULT Create32BitHBITMAP(HDC hdc, const SIZE *psize, __deref_opt_out void **ppvBits, __out HBITMAP* phBmp); }; ================================================ FILE: TrafficMonitor/WinVersionHelper.cpp ================================================ #include "stdafx.h" #include "WinVersionHelper.h" #include "WindowsSettingHelper.h" CWinVersionHelper::CWinVersionHelper() { DWORD dwMajorVer{}, dwMinorVer{}, dwBuildNumber{}; HMODULE hModNtdll{}; if (hModNtdll = ::LoadLibraryW(L"ntdll.dll")) { typedef void (WINAPI *pfRTLGETNTVERSIONNUMBERS)(DWORD*, DWORD*, DWORD*); pfRTLGETNTVERSIONNUMBERS pfRtlGetNtVersionNumbers; pfRtlGetNtVersionNumbers = (pfRTLGETNTVERSIONNUMBERS)::GetProcAddress(hModNtdll, "RtlGetNtVersionNumbers"); if (pfRtlGetNtVersionNumbers) { pfRtlGetNtVersionNumbers(&dwMajorVer, &dwMinorVer, &dwBuildNumber); dwBuildNumber &= 0x0ffff; } ::FreeLibrary(hModNtdll); hModNtdll = NULL; } m_major_version = dwMajorVer; m_minor_version = dwMinorVer; m_build_number = dwBuildNumber; CWindowsSettingHelper::CheckWindows10LightTheme(); } CWinVersionHelper::~CWinVersionHelper() { } bool CWinVersionHelper::IsWindows11OrLater() const { if (m_major_version > 10) return true; else if (m_major_version == 10 && m_minor_version > 0) return true; else if (m_major_version == 10 && m_minor_version == 0 && m_build_number >= 21996) return true; else return false; } bool CWinVersionHelper::IsWindows10FallCreatorOrLater() const { if (m_major_version > 10) return true; else if (m_major_version == 10 && m_minor_version > 0) return true; else if (m_major_version == 10 && m_minor_version == 0 && m_build_number >= 16299) return true; else return false; } bool CWinVersionHelper::IsWindows7() const { return (m_major_version == 6 && m_minor_version == 1); } bool CWinVersionHelper::IsWindows8Or8point1() const { return (m_major_version == 6 && m_minor_version > 1); } bool CWinVersionHelper::IsWindows8OrLater() const { if (m_major_version > 6) return true; else if (m_major_version == 6 && m_minor_version >= 2) return true; else return false; } bool CWinVersionHelper::IsWindows10OrLater() const { return m_major_version >= 10; } ================================================ FILE: TrafficMonitor/WinVersionHelper.h ================================================ #pragma once class CWinVersionHelper { public: CWinVersionHelper(); ~CWinVersionHelper(); bool IsWindows11OrLater() const; //判断当前Windows版本是否为Win11或更新的版本 bool IsWindows10FallCreatorOrLater() const; //判断当前Windows版本是否为Win10秋季创意者更新或更新的版本 bool IsWindows7() const; //判断Windows版本是否为Windows7 bool IsWindows8Or8point1() const; //判断Windows版本是否为Windows8或Windows8.1 bool IsWindows8OrLater() const; bool IsWindows10OrLater() const; int GetMajorVersion() const { return m_major_version; } int GetMinorVersion() const { return m_minor_version; } int GetBuildNumber() const { return m_build_number; } protected: int m_major_version{}; int m_minor_version{}; int m_build_number{}; }; ================================================ FILE: TrafficMonitor/WindowsSettingHelper.cpp ================================================ #include "stdafx.h" #include "WindowsSettingHelper.h" #include "TrafficMonitor.h" bool CWindowsSettingHelper::m_light_theme{}; bool CWindowsSettingHelper::IsWindows10LightTheme() { return m_light_theme; } void CWindowsSettingHelper::CheckWindows10LightTheme() { if (theApp.m_win_version.IsWindows10OrLater()) { HKEY hKey; DWORD dwThemeData(0); LONG lRes = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey); if (lRes == ERROR_SUCCESS) { GetDWORDRegKeyData(hKey, L"SystemUsesLightTheme", dwThemeData); m_light_theme = (dwThemeData != 0); } else { m_light_theme = false; } RegCloseKey(hKey); } else { m_light_theme = false; } } bool CWindowsSettingHelper::IsDotNetFramework4Point5Installed() { DWORD netFramewordRelease{}; if (!GetDWORDRegKeyData(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full", L"Release", netFramewordRelease)) return false; return netFramewordRelease >= 379893; } bool CWindowsSettingHelper::IsTaskbarSearchBtnShown() { DWORD data{}; if (!GetDWORDRegKeyData(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Search", L"SearchboxTaskbarMode", data)) return false; return data != 0; } bool CWindowsSettingHelper::IsTaskbarTaskViewBtnShown() { DWORD data{}; if (!GetDWORDRegKeyData(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"ShowTaskViewButton", data)) return false; return data != 0; } bool CWindowsSettingHelper::IsTaskbarWidgetsBtnShown() { DWORD data{}; if (!GetDWORDRegKeyData(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"TaskbarDa", data)) return false; return data != 0; } bool CWindowsSettingHelper::IsTaskbarChartBtnShown() { DWORD data{}; if (!GetDWORDRegKeyData(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"TaskbarMn", data)) return false; return data != 0; } bool CWindowsSettingHelper::IsTaskbarCenterAlign() { DWORD data{}; if (!GetDWORDRegKeyData(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"TaskbarAl", data)) return false; return data != 0; } LONG CWindowsSettingHelper::GetDWORDRegKeyData(HKEY hKey, const wstring& strValueName, DWORD& dwValueData) { DWORD dwBufferSize(sizeof(DWORD)); DWORD dwResult(0); LONG lError = ::RegQueryValueExW(hKey, strValueName.c_str(), NULL, NULL, reinterpret_cast(&dwResult), &dwBufferSize); if (lError == ERROR_SUCCESS) dwValueData = dwResult; return lError; } bool CWindowsSettingHelper::GetDWORDRegKeyData(HKEY keyParent, const wstring& strKeyName, const wstring& strValueName, DWORD& dwValueData) { CRegKey key; if (key.Open(keyParent, strKeyName.c_str(), KEY_READ) != ERROR_SUCCESS) return false; return (key.QueryDWORDValue(strValueName.c_str(), dwValueData) == ERROR_SUCCESS); } ================================================ FILE: TrafficMonitor/WindowsSettingHelper.h ================================================ #pragma once class CWindowsSettingHelper { public: static bool IsWindows10LightTheme(); //жWindowsǷΪdzɫ static void CheckWindows10LightTheme(); static bool IsDotNetFramework4Point5Installed(); //жǷװ.Net Framework 4.5 (https://docs.microsoft.com/zh-cn/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed) //Windows11 static bool IsTaskbarSearchBtnShown(); //Ƿʾˡť static bool IsTaskbarTaskViewBtnShown(); //Ƿʾˡͼť static bool IsTaskbarWidgetsBtnShown(); //ǷʾˡСť static bool IsTaskbarChartBtnShown(); //Ƿʾˡ족ť static bool IsTaskbarCenterAlign(); //Ƿ private: static LONG GetDWORDRegKeyData(HKEY hKey, const wstring& strValueName, DWORD& dwValueData); static bool GetDWORDRegKeyData(HKEY keyParent, const wstring& strKeyName, const wstring& strValueName, DWORD& dwValueData); private: static bool m_light_theme; }; ================================================ FILE: TrafficMonitor/auto_start_helper.cpp ================================================ #include "stdafx.h" #include "auto_start_helper.h" #include #include #include #include "SimpleXML.h" # pragma comment(lib, "taskschd.lib") // Helper macros from wix. // TODO: use "s" and "..." parameters to report errors from these functions. #define ExitOnFailure(x, s, ...) \ if (FAILED(x)) \ { \ goto LExit; \ } #define ExitWithLastError(x, s, ...) \ { \ DWORD Dutil_er = ::GetLastError(); \ x = HRESULT_FROM_WIN32(Dutil_er); \ if (!FAILED(x)) \ { \ x = E_FAIL; \ } \ goto LExit; \ } #define ExitFunction() \ { \ goto LExit; \ } const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0' const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0' bool create_auto_start_task_for_this_user(bool runElevated) { HRESULT hr = S_OK; WCHAR username_domain[USERNAME_DOMAIN_LEN]; WCHAR username[USERNAME_LEN]; std::wstring wstrTaskName; ITaskService* pService = NULL; ITaskFolder* pTaskFolder = NULL; ITaskDefinition* pTask = NULL; IRegistrationInfo* pRegInfo = NULL; ITaskSettings* pSettings = NULL; ITriggerCollection* pTriggerCollection = NULL; IRegisteredTask* pRegisteredTask = NULL; // ------------------------------------------------------ // Get the Domain/Username for the trigger. if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) { ExitWithLastError(hr, "Getting username failed: %x", hr); } if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN)) { ExitWithLastError(hr, "Getting the user's domain failed: %x", hr); } wcscat_s(username_domain, L"\\"); wcscat_s(username_domain, username); // Task Name. wstrTaskName = L"Autorun for "; wstrTaskName += username; // Get the executable path passed to the custom action. WCHAR wszExecutablePath[MAX_PATH]; GetModuleFileName(NULL, wszExecutablePath, MAX_PATH); // ------------------------------------------------------ // Create an instance of the Task Service. hr = CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (void**)&pService); ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr); // Connect to the task service. hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr); // ------------------------------------------------------ // Get the TrafficMonitor task folder. Creates it if it doesn't exist. hr = pService->GetFolder(_bstr_t(L"\\TrafficMonitor"), &pTaskFolder); if (FAILED(hr)) { // Folder doesn't exist. Get the Root folder and create the TrafficMonitor subfolder. ITaskFolder* pRootFolder = NULL; hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder); ExitOnFailure(hr, "Cannot get Root Folder pointer: %x", hr); hr = pRootFolder->CreateFolder(_bstr_t(L"\\TrafficMonitor"), _variant_t(L""), &pTaskFolder); if (FAILED(hr)) { pRootFolder->Release(); ExitOnFailure(hr, "Cannot create TrafficMonitor task folder: %x", hr); } } // If the task exists, just enable it. { IRegisteredTask* pExistingRegisteredTask = NULL; hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask); if (SUCCEEDED(hr)) { // Task exists, try enabling it. hr = pExistingRegisteredTask->put_Enabled(VARIANT_TRUE); pExistingRegisteredTask->Release(); if (SUCCEEDED(hr)) { // Function enable. Sounds like a success. ExitFunction(); } } } // Create the task builder object to create the task. hr = pService->NewTask(0, &pTask); ExitOnFailure(hr, "Failed to create a task definition: %x", hr); // ------------------------------------------------------ // Get the registration info for setting the identification. hr = pTask->get_RegistrationInfo(&pRegInfo); ExitOnFailure(hr, "Cannot get identification pointer: %x", hr); hr = pRegInfo->put_Author(_bstr_t(username_domain)); ExitOnFailure(hr, "Cannot put identification info: %x", hr); // ------------------------------------------------------ // Create the settings for the task hr = pTask->get_Settings(&pSettings); ExitOnFailure(hr, "Cannot get settings pointer: %x", hr); hr = pSettings->put_StartWhenAvailable(VARIANT_FALSE); ExitOnFailure(hr, "Cannot put_StartWhenAvailable setting info: %x", hr); hr = pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE); ExitOnFailure(hr, "Cannot put_StopIfGoingOnBatteries setting info: %x", hr); hr = pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S")); //Unlimited ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: %x", hr); hr = pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE); ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: %x", hr); // ------------------------------------------------------ // Get the trigger collection to insert the logon trigger. hr = pTask->get_Triggers(&pTriggerCollection); ExitOnFailure(hr, "Cannot get trigger collection: %x", hr); // Add the logon trigger to the task. { ITrigger* pTrigger = NULL; ILogonTrigger* pLogonTrigger = NULL; hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger); ExitOnFailure(hr, "Cannot create the trigger: %x", hr); hr = pTrigger->QueryInterface( IID_ILogonTrigger, (void**)&pLogonTrigger); pTrigger->Release(); ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: %x", hr); hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1")); // Timing issues may make explorer not be started when the task runs. // Add a little delay to mitigate this. hr = pLogonTrigger->put_Delay(_bstr_t(L"PT03S")); // Define the user. The task will execute when the user logs on. // The specified user must be a user on this computer. hr = pLogonTrigger->put_UserId(_bstr_t(username_domain)); pLogonTrigger->Release(); ExitOnFailure(hr, "Cannot add user ID to logon trigger: %x", hr); } // ------------------------------------------------------ // Add an Action to the task. This task will execute the path passed to this custom action. { IActionCollection* pActionCollection = NULL; IAction* pAction = NULL; IExecAction* pExecAction = NULL; // Get the task action collection pointer. hr = pTask->get_Actions(&pActionCollection); ExitOnFailure(hr, "Cannot get Task collection pointer: %x", hr); // Create the action, specifying that it is an executable action. hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction); pActionCollection->Release(); ExitOnFailure(hr, "Cannot create the action: %x", hr); // QI for the executable task pointer. hr = pAction->QueryInterface( IID_IExecAction, (void**)&pExecAction); pAction->Release(); ExitOnFailure(hr, "QueryInterface call failed for IExecAction: %x", hr); // Set the path of the executable to TrafficMonitor (passed as CustomActionData). hr = pExecAction->put_Path(_bstr_t(wszExecutablePath)); pExecAction->Release(); ExitOnFailure(hr, "Cannot set path of executable: %x", hr); } // ------------------------------------------------------ // Create the principal for the task { IPrincipal* pPrincipal = NULL; hr = pTask->get_Principal(&pPrincipal); ExitOnFailure(hr, "Cannot get principal pointer: %x", hr); // Set up principal information: hr = pPrincipal->put_Id(_bstr_t(L"Principal1")); hr = pPrincipal->put_UserId(_bstr_t(username_domain)); hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN); if (runElevated) { hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_HIGHEST); } else { hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_LUA); } pPrincipal->Release(); ExitOnFailure(hr, "Cannot put principal run level: %x", hr); } // ------------------------------------------------------ // Save the task in the TrafficMonitor folder. { _variant_t SDDL_FULL_ACCESS_FOR_EVERYONE = L"D:(A;;FA;;;WD)"; hr = pTaskFolder->RegisterTaskDefinition( _bstr_t(wstrTaskName.c_str()), pTask, TASK_CREATE_OR_UPDATE, _variant_t(username_domain), _variant_t(), TASK_LOGON_INTERACTIVE_TOKEN, SDDL_FULL_ACCESS_FOR_EVERYONE, &pRegisteredTask); ExitOnFailure(hr, "Error saving the Task : %x", hr); } LExit: if (pService) pService->Release(); if (pTaskFolder) pTaskFolder->Release(); if (pTask) pTask->Release(); if (pRegInfo) pRegInfo->Release(); if (pSettings) pSettings->Release(); if (pTriggerCollection) pTriggerCollection->Release(); if (pRegisteredTask) pRegisteredTask->Release(); return (SUCCEEDED(hr)); } bool delete_auto_start_task_for_this_user() { HRESULT hr = S_OK; WCHAR username[USERNAME_LEN]; std::wstring wstrTaskName; ITaskService* pService = NULL; ITaskFolder* pTaskFolder = NULL; // ------------------------------------------------------ // Get the Username for the task. if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) { ExitWithLastError(hr, "Getting username failed: %x", hr); } // Task Name. wstrTaskName = L"Autorun for "; wstrTaskName += username; // ------------------------------------------------------ // Create an instance of the Task Service. hr = CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (void**)&pService); ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr); // Connect to the task service. hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr); // ------------------------------------------------------ // Get the TrafficMonitor task folder. hr = pService->GetFolder(_bstr_t(L"\\TrafficMonitor"), &pTaskFolder); if (FAILED(hr)) { // Folder doesn't exist. No need to disable a non-existing task. hr = S_OK; ExitFunction(); } // ------------------------------------------------------ // If the task exists, disable. { IRegisteredTask* pExistingRegisteredTask = NULL; hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask); if (SUCCEEDED(hr)) { // Task exists, try disabling it. hr = pTaskFolder->DeleteTask(_bstr_t(wstrTaskName.c_str()), 0); } } LExit: if (pService) pService->Release(); if (pTaskFolder) pTaskFolder->Release(); return (SUCCEEDED(hr)); } bool is_auto_start_task_active_for_this_user(std::wstring* path) { HRESULT hr = S_OK; WCHAR username[USERNAME_LEN]; std::wstring wstrTaskName; ITaskService* pService = NULL; ITaskFolder* pTaskFolder = NULL; // ------------------------------------------------------ // Get the Username for the task. if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) { ExitWithLastError(hr, "Getting username failed: %x", hr); } // Task Name. wstrTaskName = L"Autorun for "; wstrTaskName += username; // ------------------------------------------------------ // Create an instance of the Task Service. hr = CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (void**)&pService); ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr); // Connect to the task service. hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr); // ------------------------------------------------------ // Get the TrafficMonitor task folder. hr = pService->GetFolder(_bstr_t(L"\\TrafficMonitor"), &pTaskFolder); ExitOnFailure(hr, "ITaskFolder doesn't exist: %x", hr); bool command_path_match{}; // ------------------------------------------------------ // If the task exists, disable. { IRegisteredTask* pExistingRegisteredTask = NULL; hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask); if (SUCCEEDED(hr)) { // Task exists, get its value. VARIANT_BOOL is_enabled; hr = pExistingRegisteredTask->get_Enabled(&is_enabled); //判断已存在的任务计划命令的exe文件路径是否为当前exe的路径 BSTR xml_buff{}; pExistingRegisteredTask->get_Xml(&xml_buff); CSimpleXML xml; xml.LoadXMLContentDirect(xml_buff); std::wstring command_path = xml.GetNode(L"Command", L"Exec"); if (path != nullptr) *path = command_path; WCHAR wszExecutablePath[MAX_PATH]; GetModuleFileName(NULL, wszExecutablePath, MAX_PATH); command_path_match = (command_path == wszExecutablePath); pExistingRegisteredTask->Release(); if (SUCCEEDED(hr)) { // Got the value. Return it. hr = (is_enabled == VARIANT_TRUE) ? S_OK : E_FAIL; // Fake success or fail to return the value. ExitFunction(); } } } LExit: if (pService) pService->Release(); if (pTaskFolder) pTaskFolder->Release(); //delete[] buff; return (SUCCEEDED(hr) && command_path_match); } ================================================ FILE: TrafficMonitor/auto_start_helper.h ================================================ #pragma once bool is_auto_start_task_active_for_this_user(std::wstring* path); bool create_auto_start_task_for_this_user(bool runElevated); bool delete_auto_start_task_for_this_user(); ================================================ FILE: TrafficMonitor/crashtool.cpp ================================================ #include "StdAfx.h" #include "crashtool.h" #include #include #include #include "MessageDlg.h" #include "Common.h" #include "TrafficMonitor.h" #pragma comment(lib, "Dbghelp.lib") class CCrashReport { public: CCrashReport() { GetAppPath(); } ~CCrashReport() {} public: // 生成MiniDump文件 void CreateMiniDump(EXCEPTION_POINTERS* pEP) { SYSTEMTIME stLocalTime; ::GetLocalTime(&stLocalTime); TCHAR szDumpFile[MAX_PATH] = {0}; ::StringCchPrintf(szDumpFile, _countof(szDumpFile), TEXT("%s%04d%02d%02d%02d%02d%02d_%s.dmp"), m_szDumpFilePath, stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, m_szModuleFileName); HANDLE hDumpFile; hDumpFile = ::CreateFile(szDumpFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); if (INVALID_HANDLE_VALUE == hDumpFile) { return; } m_dumpFile = szDumpFile; MINIDUMP_EXCEPTION_INFORMATION ExpParam; ExpParam.ThreadId = ::GetCurrentThreadId(); ExpParam.ExceptionPointers = pEP; ExpParam.ClientPointers = TRUE; // 生成minidump文件 BOOL bResult = ::MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &ExpParam, NULL, NULL); ::CloseHandle(hDumpFile); } void ShowCrashInfo() { CMessageDlg dlg; dlg.SetWindowTitle(APP_NAME); dlg.SetInfoText(CCommon::LoadText(IDS_ERROR_MESSAGE)); CString info = CCommon::LoadTextFormat(IDS_CRASH_INFO, { m_dumpFile }); info += _T("\r\n"); info += theApp.GetSystemInfoString(); dlg.SetMessageText(info); //设置图标 HICON hIcon; HRESULT hr = LoadIconWithScaleDown(NULL, IDI_ERROR, theApp.DPI(32), theApp.DPI(32), &hIcon); if (SUCCEEDED(hr)) dlg.SetMessageIcon(hIcon); dlg.DoModal(); } private: void GetAppPath() { ZeroMemory(m_szModuleFileName, MAX_PATH); ::GetModuleFileName(NULL, m_szDumpFilePath, _countof(m_szDumpFilePath)); for (int nIndex = (int)_tcslen(m_szDumpFilePath); nIndex >= 0; --nIndex) { if (m_szDumpFilePath[nIndex] == TEXT('\\')) { ::memmove(m_szModuleFileName, m_szDumpFilePath + nIndex + 1, (int)_tcslen(m_szDumpFilePath)); m_szDumpFilePath[nIndex + 1] = 0; break; } } ZeroMemory(m_szDumpFilePath, MAX_PATH); if (!::GetTempPath(MAX_PATH, m_szDumpFilePath)) { m_szDumpFilePath[0] = _T('C'); m_szDumpFilePath[1] = _T(':'); m_szDumpFilePath[2] = _T('\\'); m_szDumpFilePath[3] = _T('\0'); } } private: wchar_t m_szDumpFilePath[MAX_PATH]; wchar_t m_szModuleFileName[MAX_PATH]; CString m_dumpFile; }; namespace CRASHREPORT { static LONG WINAPI __UnhandledExceptionFilter(PEXCEPTION_POINTERS pEP) { ::SetErrorMode(0); //使用默认的 CCrashReport cr; cr.CreateMiniDump(pEP); cr.ShowCrashInfo(); return EXCEPTION_CONTINUE_SEARCH; } void StartCrashReport() { ::SetUnhandledExceptionFilter(__UnhandledExceptionFilter); } } ================================================ FILE: TrafficMonitor/crashtool.h ================================================ #pragma once namespace CRASHREPORT { /**@brief dmupģʽ 󣬵ʱһdumpļļC:\Users\<û>\AppData\Local\TempĿ¼ ļʽʱ_.exe.dmp 20150116174802_CrashShare.exe.dmp */ void StartCrashReport(); } ================================================ FILE: TrafficMonitor/print_compile_time.bat ================================================ REM ǰںʱ䣬浽compile_time.txtļ del /F /Q compile_time.txt echo %date:~0,10% >> compile_time.txt echo %time:~0,8% >> compile_time.txt ================================================ FILE: TrafficMonitor/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ ɵİļ // TrafficMonitor.rc ʹ // #define IDD_TRAFFICMONITOR_DIALOG 102 #define IDR_MAINFRAME 128 #define IDR_MENU1 130 #define IDD_NETWORK_INFO_DIALOG 131 #define IDD_ABOUTBOX 133 #define IDD_TASK_BAR_DIALOG 135 #define IDR_TASK_BAR_MENU 137 #define IDD_SKIN_DIALOG 138 #define IDB_BITMAP1 140 #define IDD_HISTORY_TRAFFIC_DIALOG 141 #define IDD_DONATE_DIALOG 143 #define IDB_BITMAP2 145 #define IDB_DONATE_BITMAP 145 #define IDI_NOFITY_ICON 146 #define IDD_OPTIONS_DIALOG 147 #define IDD_MAIN_WND_SETTINGS_DIALOG 149 #define IDD_TASKBAR_SETTINGS_DIALOG 150 #define IDR_INFO_MENU 153 #define IDR_MENU2 154 #define IDR_HISTORY_TRAFFIC_MENU 154 #define IDD_GENERAL_SETTINGS_DIALOG 155 #define IDB_ABOUT_BACKGROUND_HD 157 #define IDI_NOFITY_ICON2 158 #define IDI_NOFITY_ICON3 159 #define IDD_ICON_SELECT_DIALOG 160 #define IDB_NOTIFY_ICON_PREVIEW 162 #define IDD_MAIN_COLOR_DIALOG 163 #define IDD_TASKBAR_COLOR_DIALOG 165 #define IDS_CHECK_UPDATE_FAILD 167 #define IDS_CHECK_UPDATE_ERROR 168 #define IDD_HISTORY_TRAFFIC_LIST_DIALOG 168 #define IDS_UPDATE_AVLIABLE 169 #define IDS_UPDATE_AVLIABLE2 170 #define IDD_HISTORY_TRAFFIC_CALENDAR_DIALOG 170 #define IDS_ALREADY_UPDATED 171 #define IDS_AUTORUN_FAILED_NO_KEY 172 #define IDS_AUTORUN_FAILED_NO_ACCESS 173 #define IDS_AUTORUN_DELETE_FAILED 174 #define IDS_AN_INSTANCE_RUNNING 175 #define IDS_TRAFFIC_USED_TODAY 176 #define IDS_MEMORY_USAGE 177 #define IDS_CPU_USAGE 178 #define IDS_SEND_EMAIL_TO_ATHOUR 179 #define IDS_GOTO_GITHUB 180 #define IDS_DONATE_ATHOUR 181 #define IDS_UPLOAD 182 #define IDS_DOWNLOAD 183 #define IDS_MEMORY 184 #define IDS_UPLOAD_DISP 185 #define IDS_DOWNLOAD_DISP 186 #define IDS_MEMORY_DISP 187 #define IDS_CONNOT_SAVE_CONFIG_WARNING 188 #define IDS_TRAFFICMONITOR 189 #define IDS_INSUFFICIENT_BUFFER 190 #define IDS_CONNECTION_NUM_CHANGED 191 #define IDS_CONNECTION_NOT_MATCH 192 #define IDS_CONNOT_INSERT_TO_TASKBAR 193 #define IDS_MEMORY_UDAGE_EXCEED 194 #define IDS_NOTIFY 195 #define IDS_TODAY_TRAFFIC_EXCEED 196 #define IDS_TITLE_ABOUT 197 #define IDS_TITLE_DONATE 198 #define IDS_TITLE_HISTORY_TRAFFIC 199 #define IDS_TITLE_CONNECTION_DETIAL 200 #define IDS_TITLE_CHANGE_SKIN 201 #define IDS_TITLE_OPTION 202 #define IDS_TITLE_CHANGE_ICON 203 #define IDS_DATE 204 #define IDS_TRAFFIC_USED 205 #define IDS_FIGURE 206 #define IDS_DEFAULT_ICON 207 #define IDS_ICON 208 #define IDS_INTERFACE_NAME 209 #define IDS_INTERFACE_DESCRIPTION 210 #define IDS_CONNECTION_TYPE 211 #define IDS_IF_TYPE_OTHER 212 #define IDS_IF_TYPE_ETHERNET_CSMACD 213 #define IDS_IF_TYPE_ISO88025_TOKENRING 214 #define IDS_IF_TYPE_FDDI 215 #define IDS_IF_TYPE_PPP 216 #define IDS_IF_TYPE_SOFTWARE_LOOPBACK 217 #define IDS_IF_TYPE_ATM 218 #define IDS_IF_TYPE_IEEE80211 219 #define IDS_IF_TYPE_TUNNEL 220 #define IDS_IF_TYPE_IEEE1394 221 #define IDS_IF_TYPE_IEEE80216_WMAN 222 #define IDS_IF_TYPE_WWANPP 223 #define IDS_IF_TYPE_WWANPP2 224 #define IDS_UNKNOW_CONNECTION 225 #define IDS_SPEED 226 #define IDS_ADAPTER_PHYSICAL_ADDRESS 227 #define IDS_IP_ADDRESS 228 #define IDS_SUBNET_MASK 229 #define IDS_DEFAULT_GATEWAY 230 #define IDS_OPERATIONAL_STATUS 231 #define IDS_IF_OPER_STATUS_NON_OPERATIONAL 232 #define IDS_IF_OPER_STATUS_UNREACHABLE 233 #define IDS_IF_OPER_STATUS_DISCONNECTED 234 #define IDS_IF_OPER_STATUS_CONNECTING 235 #define IDS_IF_OPER_STATUS_CONNECTED 236 #define IDS_IF_OPER_STATUS_OPERATIONAL 237 #define IDS_UNKNOW_STATUS 238 #define IDS_BYTES_RECEIVED 239 #define IDS_BYTES_SENT 240 #define IDS_BYTES_RECEIVED_SINCE_START 241 #define IDS_BYTES_SENT_SINCE_START 242 #define IDS_PROGRAM_ELAPSED_TIME 243 #define IDS_HOUR_MINUTE_SECOND 244 #define IDS_INTERNET_IP_ADDRESS 245 #define IDS_GET_FAILED 246 #define IDS_ITEM 247 #define IDS_VALUE 248 #define IDS_COPY_TO_CLIPBOARD_FAILED 249 #define IDS_SKIN_AUTHOUR 250 #define IDS_OVERWRITE_FONT_TEXT_WARNING 251 #define IDS_OVERWRITE_FONT_WARNING 252 #define IDS_OVERWRITE_TEXT_WARNING 253 #define IDS_SPEED_SHORT_MODE_TIP 254 #define IDS_AUTO 255 #define IDS_FIXED_AS 256 #define IDS_OPEN_CONNECTION_DETIAL 257 #define IDS_OPEN_HISTORICAL_TRAFFIC 258 #define IDS_SHOW_HIDE_MORE_INFO 259 #define IDS_SHOW_HIDE_CPU_MEMORY 260 #define IDS_OPEN_OPTION_SETTINGS 261 #define IDS_OPEN_TASK_MANAGER 262 #define IDS_CHANGE_SKIN 263 #define IDS_NONE 264 #define IDS_FONT_SIZE_WARNING 265 #define IDS_SAME_TEXT_BACK_COLOR_WARNING 266 #define IDS_SAME_BACK_TEXT_COLOR_WARNING 267 #define IDS_FOLLOWING_SYSTEM 268 #define IDS_LANGUAGE_CHANGE_INFO 269 #define IDS_MAIN_WINDOW_SETTINGS 270 #define IDS_TASKBAR_WINDOW_SETTINGS 271 #define IDS_GENERAL_SETTINGS 272 #define IDS_MICROSOFT_YAHEI 273 #define IDS_ACQUIRING 274 #define IDS_DEFAULT_FONT 275 #define IDS_LIST_VIEW 276 #define IDS_CALENDAR_VIEW 277 #define IDS_MONDAY 278 #define IDS_TUESDAY 279 #define IDS_WEDNESDAY 280 #define IDS_THURSDAY 281 #define IDS_FRIDAY 282 #define IDS_SATURDAY 283 #define IDS_SUNDAY 284 #define IDS_CURRENT_MONTH_TOTAL_TRAFFIC 285 #define IDS_TRAFFIC_USED1 286 #define IDS_LANGUAGE_CODE 287 #define IDS_CONNOT_INSERT_TO_TASKBAR_ERROR_LOG 288 #define IDS_NO_CONNECTION 289 #define IDS_SEND_EMAIL_TO_TRANSLATOR 290 #define IDS_CONTACT_TRANSLATOR 290 #define IDR_TEXT2 290 #define IDR_TEXT 290 #define IDS_THANKS_DONORS 291 #define IDS_GET_URL_ERROR_LOG_INFO 292 #define IDS_SHOW_ALL_INFO_TIP 293 #define IDD_DIALOG1 293 #define IDD_MESSAGE_DIALOG 293 #define IDR_ACKNOWLEDGEMENT_TEXT 294 #define IDS_CFG_DIR_CHANGED_INFO 294 #define IDS_DOUBLE_CLICK_TO_ACQUIRE 295 #define IDS_ERROR1 296 #define IDS_ERROR_MESSAGE 297 #define IDS_CRASH_INFO 298 #define IDS_TITLE_ACKNOWLEDGEMENT 299 #define IDI_NOFITY_ICON4 299 #define IDS_SAVE_DEFAULT_STYLE_INQUIRY 300 #define IDS_SPECIFIC_APP 301 #define IDB_NOTIFY_ICON_PREVIEW_LIGHT 302 #define IDS_EXE_FILTER 302 #define IDS_PRESET 303 #define IDS_LIGHT_MODE 304 #define IDB_BITMAP3 305 #define IDB_DONATE_WECHAT 305 #define IDS_AUTO_ADAPT_TIP_INFO 305 #define IDD_ATUO_ADAPT_SETTING_DIALOG 306 #define IDS_WITHOUT_TEMPERATURE 306 #define IDS_MOUSE_PENETRATE_TIP_INFO 307 #define IDS_HISTORY_TRAFFIC_LOST_ERROR_LOG 308 #define IDS_LEGEND 309 #define IDR_LICENSE 310 #define IDS_LICENSE_EXPLAIN 310 #define IDS_LICENSE 311 #define IDI_EXIT 311 #define IDI_HELP 312 #define IDS_DAY_VIEW 312 #define IDI_INFO 313 #define IDS_MONTH_VIEW 313 #define IDI_LOCK 314 #define IDS_QUARTER_VIEW 314 #define IDI_SETTINGS 315 #define IDS_YEAR_VIEW 315 #define IDI_STATISTICS 316 #define IDS_LINEAR_SCALE 316 #define IDI_CLOSE 317 #define IDS_LOG_SCALE 317 #define IDI_PIN 318 #define IDS_CPU_TEMPERATURE 318 #define IDI_SKIN 319 #define IDS_GPU_TEMPERATURE 319 #define IDI_CONNECTION 320 #define IDS_HDD_TEMPERATURE 320 #define IDI_MOUSE 321 #define IDS_MAINBOARD_TEMPERATURE 321 #define IDI_MAIN_WINDOW 322 #define IDS_GPU_DISP 322 #define IDI_TASKBAR_WINDOW 323 #define IDS_HDD_DISP 323 #define IDI_NOTIFY 324 #define IDS_MAINBOARD_DISP 324 #define IDI_MORE 325 #define IDS_CPU_TEMPERATURE_EXCEED 325 #define IDI_ITEM 326 #define IDS_GPU_TEMPERATURE_EXCEED 326 #define IDI_FUNCTION 327 #define IDS_HDD_TEMPERATURE_EXCEED 327 #define IDI_NOTIFY_ICON5 328 #define IDS_MBD_TEMPERATURE_EXCEED 328 #define IDD_DISPLAY_TEXT_SETTINGS_DIALOG 329 #define IDS_MUSICPLAYER2_DESCRIPTION 329 #define IDR_COMPILE_TIME 329 #define IDS_SIMPLENOTEPAD_DESCRIPTION 330 #define IDD_SELECT_ORDER_DIALOG 330 #define IDS_COLOR 331 #define IDS_COLOR_LABEL 332 #define IDD_PLUGIN_MANAGER_DIALOG 332 #define IDS_COLOR_VALUE 333 #define IDS_GPU_USAGE 334 #define IDI_PLUGINS 334 #define IDS_IF_OPER_STATUS_UP 335 #define IDR_MENU3 335 #define IDR_PLUGIN_MANAGER_MENU 335 #define IDS_IF_OPER_STATUS_DOWN 336 #define IDI_TASK_MANAGER 336 #define IDS_IF_OPER_STATUS_DORMANT 337 #define IDD_APP_ALREAD_RUNING_DIALOG 337 #define IDS_GOTO_GITEE 338 #define IDS_USAGE_PERCENTAGE 339 #define IDD_SELECT_CONNECTIONS_DIALOG 339 #define IDS_MEMORY_USED 340 #define IDS_MEMORY_AVAILABLE 341 #define IDS_DOTNET_NOT_INSTALLED_TIP 342 #define IDS_VERSION_UPDATE 343 #define IDS_AVREAGE_TEMPERATURE 344 #define IDS_HARDWARE_MONITOR_WARNING 345 #define IDS_HARDWARE_MONITOR_WARNING2 346 #define IDS_HDD_USAGE 347 #define IDS_FILE_NAME 348 #define IDS_STATUS 349 #define IDS_PLUGIN_LOAD_SUCCEED 350 #define IDS_PLUGIN_MODULE_LOAD_FAILED 351 #define IDS_PLUGIN_FUNCTION_GET_FAILED 352 #define IDS_PLUGIN_INFO 353 #define IDS_NAME 354 #define IDS_DESCRIPTION 355 #define IDS_FILE_PATH 356 #define IDS_ITEM_NUM 357 #define IDS_ITEM_NAMES 358 #define IDS_AUTHOR 359 #define IDS_COPYRIGHT 360 #define IDS_PLUGIN_NO_OPTIONS_INFO 361 #define IDS_PLUGIN_NAME 362 #define IDS_DISABLED 363 #define IDS_RESTART_TO_APPLY_CHANGE_INFO 364 #define IDS_VERSION 365 #define IDS_DISP_ITEM_ID 366 #define IDS_PLUGIN_API_VERSION 367 #define IDS_WEEK_VIEW 368 #define IDS_WEEK_NUM 369 #define IDS_URL 370 #define IDS_PLUGIN_VERSION_NOT_SUPPORT 371 #define IDS_MODIFY_PRESET 372 #define IDS_SELECT_AT_LEASE_ONE_WARNING 373 #define IDS_AUTO_SAVE_TO_PRESET_TIP 374 #define IDS_TOTAL_NET_SPEED 375 #define IDS_SHOW_RESOURCE_USAGE_GRAPH_TIP 376 #define IDS_SHOW_NET_SPEED_GRAPH_TIP 377 #define IDS_REFRESH_CONNECTION_LIST 378 #define IDS_HARDWARE_MONITOR_INIT_FAILED 379 #define IDS_HARDWARE_INFO_ACQUIRE_FAILED_ERROR 380 #define IDS_AUTO_RUN_METHOD_REGESTRY 381 #define IDS_AUTO_RUN_METHOD_TASK_SCHEDULE 382 #define IDS_PATH 383 #define IDS_SET_AUTO_RUN_FAILED_WARNING 384 #define IDC_STATIC_INFO 1001 #define IDC_STATIC1 1002 #define IDC_STATIC_DOWN 1002 #define IDC_STATIC_UP 1003 #define IDC_STATIC2 1003 #define IDC_STATIC_DOWN1 1003 #define IDC_STATIC_MEMORY 1004 #define IDC_STATIC3 1004 #define IDC_STATIC_CPU 1005 #define IDC_STATIC4 1005 #define IDC_STATIC_UP1 1006 #define IDC_STATIC_VERSION 1007 #define IDC_COMBO1 1008 #define IDC_STATIC_SKIN_S 1009 #define IDC_STATIC_SKIN_L 1010 #define IDC_STATIC_TEXT2 1012 #define IDC_SKIN_INFO 1013 #define IDC_STATIC_ABOUT 1015 #define IDC_STATIC_MAIL 1016 #define IDC_LIST1 1017 #define IDC_INFO_LIST 1017 #define IDC_INFO_LIST1 1017 #define IDC_HISTORY_INFO_LIST 1017 #define IDC_STATIC_LICENSE 1017 #define IDC_DONATE_PIC 1018 #define IDC_FONT_NAME_EDIT 1019 #define IDC_FONT_SIZE_EDIT 1020 #define IDC_STATIC_CHECK_UPDATE 1021 #define IDC_SET_FONT_BUTTON 1021 #define IDC_STATIC_DONATE 1022 #define IDC_TEXT_COLOR_STATIC 1022 #define IDC_UPLOAD_EDIT 1023 #define IDC_DOWNLOAD_EDIT 1024 #define IDC_CPU_EDIT 1025 #define IDC_MEMORY_EDIT 1026 #define IDC_FONT_NAME_EDIT1 1027 #define IDC_FONT_SIZE_EDIT1 1028 #define IDC_SET_FONT_BUTTON1 1029 #define IDC_TEXT_COLOR_STATIC1 1030 #define IDC_UPLOAD_EDIT1 1031 #define IDC_DOWNLOAD_EDIT1 1032 #define IDC_CPU_EDIT1 1033 #define IDC_MEMORY_EDIT1 1034 #define IDC_TEXT_COLOR_STATIC2 1035 #define IDC_TAB1 1035 #define IDC_SET_DEFAULT_BUTTON 1036 #define IDC_TEXT_COLOR_STATIC3 1036 #define IDC_SET_COLOR_BUTTON2 1037 #define IDC_TRANSPARENT_COLOR_STATIC 1037 #define IDC_SET_COLOR_BUTTON1 1038 #define IDC_SET_COLOR_BUTTON3 1038 #define IDC_SWITCH_UP_DOWN_CHECK 1039 #define IDC_SWITCH_UP_DOWN_CHECK1 1040 #define IDC_SET_DEFAULT_BUTTON1 1041 #define IDC_FULLSCREEN_HIDE_CHECK 1042 #define IDC_SWITCH_UP_DOWN_CHECK2 1042 #define IDC_SPEED_SHORT_MODE_CHECK 1042 #define IDC_STATIC_GITHUB 1043 #define IDC_SPEED_SHORT_MODE_CHECK2 1043 #define IDC_SET_LIGHT_MODE_BUTTON 1043 #define IDC_CHECK_UPDATE_CHECK 1044 #define IDC_STATIC_GITEE 1044 #define IDC_CHECK_NOW_BUTTON 1045 #define IDC_AUTO_RUN_CHECK 1046 #define IDC_TASKBAR_WND_ON_LEFT_CHECK 1047 #define IDC_HIDE_UNIT_CHECK 1049 #define IDC_UNIT_COMBO 1050 #define IDC_ICON_PREVIEW 1051 #define IDC_HIDE_PERCENTAGE_CHECK 1051 #define IDC_SKIN_COURSE_STATIC 1052 #define IDC_SKIN_COURSE_STATIC2 1053 #define IDC_SKIN_DOWNLOAD_STATIC 1053 #define IDC_PREVIEW_GROUP_STATIC 1054 #define IDC_NOTIFY_STATIC 1056 #define IDC_ALLOW_SKIN_FONT_CHECK 1057 #define IDC_CHECK2 1058 #define IDC_ALLOW_SKIN_DISP_STR_CHECK 1058 #define IDC_VALUE_RIGHT_ALIGN_CHECK 1058 #define IDC_ALWAYS_ON_TOP_CHECK 1058 #define IDC_UP_STATIC 1059 #define IDC_DOWN_STATIC 1060 #define IDC_UP_VALUE_STATIC 1060 #define IDC_CPU_STATIC 1061 #define IDC_DWON_LABLE_STATIC 1061 #define IDC_MEMORY_STATIC 1062 #define IDC_DWON_VALUE_STATIC 1062 #define IDC_SPECIFY_EACH_ITEM_COLOR_CHECK 1063 #define IDC_CPU_LABLE_STATIC 1063 #define IDC_CPU_TEMP_STATIC 1063 #define IDC_CPU_VALUE_STATIC 1064 #define IDC_GPU_TEMP_STATIC 1064 #define IDC_MEMORY_LABLE_STATIC 1065 #define IDC_HDD_TEMP_STATIC 1065 #define IDC_UP_STATIC8 1066 #define IDC_MEMORY_VALUE_STATIC 1066 #define IDC_MEMORY_STATIC2 1066 #define IDC_MBD_TEMP_STATIC 1066 #define IDC_UP_LABLE_STATIC 1067 #define IDC_DOUBLE_CLICK_COMBO 1068 #define IDC_TODAY_TRAFFIC_TIP_CHECK 1069 #define IDC_TODAY_TRAFFIC_TIP_EDIT 1070 #define IDC_MEMORY_USAGE_TIP_CHECK 1071 #define IDC_MEMORY_USAGE_TIP_EDIT 1072 #define IDC_TODAY_TRAFFIC_TIP_COMBO 1073 #define IDC_STATIC_COPYRIGHT 1074 #define IDC_LANGUAGE_COMBO 1075 #define IDC_CPU_TEMP_LABLE_STATIC 1076 #define IDC_CPU_TEMP_TIP_EDIT 1076 #define IDC_YEAR_COMBO 1077 #define IDC_CPU_TEMP_VALUE_STATIC 1077 #define IDC_GPU_TEMP_TIP_CHECK 1077 #define IDC_MONTH_COMBO 1078 #define IDC_GPU_TEMP_LABLE_STATIC 1078 #define IDC_GPU_TEMP_TIP_EDIT 1078 #define IDC_PREVIOUS_BUTTON 1079 #define IDC_GPU_TEMP_VALUE_STATIC 1079 #define IDC_NEXT_BUTTON 1080 #define IDC_OPEN_CONFIG_PATH_BUTTON 1080 #define IDC_HDD_TEMP_LABLE_STATIC 1080 #define IDC_DIGIT_NUMBER_COMBO 1081 #define IDC_HDD_TEMP_VALUE_STATIC 1081 #define IDC_HDD_TIP_EDIT 1081 #define IDC_HORIZONTAL_ARRANGE_CHECK 1082 #define IDC_MAIN_BOARD_TEMP_LABLE_STATIC 1082 #define IDC_MBD_TEMP_TIP_CHECK 1082 #define IDC_PREVIEW_BUTTON 1083 #define IDC_MAIN_BOARD_TEMP_VALUE_STATIC 1083 #define IDC_MBD_TEMP_TIP_EDIT 1083 #define IDC_INDEX_STATIC 1084 #define IDC_STATIC_ACKNOWLEDGEMENT 1085 #define IDC_TRADITIONAL_CHINESE_TRANSLATOR_STATIC 1086 #define IDC_TRANSLATOR_STATIC 1087 #define IDC_SEPARATE_VALUE_UNIT_CHECK 1089 #define IDC_SHOW_STATUS_BAR_CHECK 1090 #define IDC_UNIT_BYTE_RADIO 1091 #define IDC_UNIT_BIT_RADIO 1092 #define IDC_SHOW_ALL_CONNECTION_CHECK 1092 #define IDC_SAVE_TO_APPDATA_RADIO 1093 #define IDC_SAVE_TO_PROGRAM_DIR_RADIO 1094 #define IDC_HELP_EDIT 1095 #define IDC_INFO_STATIC 1096 #define IDC_SHOW_TOOL_TIP_CHK 1097 #define IDC_DEFAULT_STYLE_BUTTON 1098 #define IDC_BROWSE_BUTTON 1100 #define IDC_EXE_PATH_EDIT 1101 #define IDC_EXE_PATH_STATIC 1102 #define IDC_TEXT_STATIC 1103 #define IDC_CM_GRAPH_BAR_RADIO 1104 #define IDC_CM_GRAPH_PLOT_RADIO 1105 #define IDC_USE_CPU_TIME_RADIO 1106 #define IDC_USE_PDH_RADIO 1107 #define IDC_BACKGROUND_TRANSPARENT_CHECK 1108 #define IDC_AUTO_ADAPT_LIGHT_THEME_CHECK 1109 #define IDC_AUTO_ADAPT_SETTINGS_BUTTON 1110 #define IDC_DARK_MODE_DEFAULT_STYLE_COMBO 1111 #define IDC_LIGHT_MODE_DEFAULT_STYLE_COMBO 1112 #define IDC_MENU_BUTTON 1112 #define IDC_AUTO_ADAPT_CHECK 1113 #define IDC_MONITOR_SPAN_EDIT 1114 #define IDC_VIEW_TYPE_COMBO 1115 #define IDC_VIEW_SCALE_COMBO 1116 #define IDC_HDD_TEMP_TIP_CHECK 1117 #define IDC_AUTO_SET_BACK_COLOR_CHECK 1117 #define IDC_RESTORE_DEFAULT_BUTTON 1118 #define IDC_DISPLAY_TEXT_SETTING_BUTTON 1119 #define IDC_CPU_TEMP_TIP_CHECK 1120 #define IDC_OPENHARDWAREMONITOR_LINK 1122 #define IDC_TINYXML2_LINK 1123 #define IDC_MUSICPLAYER2_LINK 1124 #define IDC_SIMPLENOTEPAD_LINK 1125 #define IDC_GITHUB_RADIO 1126 #define IDC_GITEE_RADIO 1127 #define IDC_MEMORY_DISPLAY_COMBO 1127 #define IDC_RESTORE_DEFAULT_TIME_SPAN_BUTTON 1128 #define IDC_SELECT_HARD_DISK_COMBO 1129 #define IDC_CPU_CHECK 1130 #define IDC_GPU_CHECK 1131 #define IDC_SHOW_DASHED_BOX 1131 #define IDC_HDD_CHECK 1132 #define IDC_MBD_CHECK 1133 #define IDC_MOUSE_PENETRATE_CHECK 1133 #define IDC_SELECT_CPU_COMBO 1134 #define IDC_LOCK_WINDOW_POS_CHECK 1134 #define IDC_ALOW_OUT_OF_BORDER_CHECK 1135 #define IDC_MOVE_UP_BUTTON 1136 #define IDC_MOVE_DOWN_BUTTON 1137 #define IDC_SET_ORDER_BUTTON 1137 #define IDC_OPTINS_BUTTON 1139 #define IDC_PLUGIN_MANAGE_BUTTON 1140 #define IDC_PLUGIN_INFO_BUTTON 1141 #define IDC_SHOW_NOTIFY_ICON_CHECK 1142 #define IDC_HDD_STATIC 1143 #define IDC_HARDWARE_MONITOR_STATIC 1144 #define IDC_SELECT_HDD_STATIC 1145 #define IDC_SELECT_CPU_STATIC 1146 #define IDC_APPLY_BUTTON 1147 #define IDC_TASKBAR_WND_SNAP_CHECK 1148 #define IDC_ITEM_SPACE_EDIT 1149 #define IDC_EXIT_INST_BUTTON 1150 #define IDC_OPEN_SETTINGS_BUTTON 1151 #define IDC_SHOW_HIDE_MAIN_WINDOW_BUTTON 1152 #define IDC_SHOW_HIDE_TASKBAR_WINDOW_BUTTON 1153 #define IDC_PLUGIN_DEV_GUID_STATIC 1153 #define IDC_PLUGIN_DOWNLOAD_STATIC 1154 #define IDC_SELECT_CONNECTIONS_BUTTON 1155 #define IDC_AUTO_SAVE_TO_PRESET_CHECK 1156 #define IDC_SHOW_NET_SPEED_FIGURE_CHECK 1157 #define IDC_NET_SPEED_FIGURE_MAX_VALUE_EDIT 1158 #define IDC_NET_SPEED_FIGURE_MAX_VALUE_UNIT_COMBO 1159 #define IDC_OPEN_PLUGIN_DIR_STATIC 1160 #define IDC_OPEN_SKIN_DIR_STATIC 1161 #define IDC_RESET_AUTO_RUN_BUTTON 1162 #define IDS_CPU_FREQ 1163 #define ID_32771 32771 #define ID_NETWORK_INFO 32772 #define ID_32773 32773 #define ID_ALWAYS_ON_TOP 32774 #define ID_32775 32775 #define ID_32776 32776 #define ID_32777 32777 #define ID_32778 32778 #define ID_32779 32779 #define ID_TRANS_100 32780 #define ID_TRANSPARENCY_100 32781 #define ID_TRANSPARENCY_80 32782 #define ID_TRANSPARENCY_60 32783 #define ID_TRANSPARENCY_40 32784 #define ID_32785 32785 #define ID_32786 32786 #define ID_32789 32789 #define ID_LOCK_WINDOW_POS 32790 #define ID_32791 32791 #define ID_SHOW_NOTIFY_ICON 32792 #define ID_32793 32793 #define ID_SHOW_CPU_MEMORY 32794 #define ID_32795 32795 #define ID_MOUSE_PENETRATE 32796 #define ID_32797 32797 #define ID_32798 32798 #define ID_TEXT_COLOR 32799 #define ID_32800 32800 #define ID_SHOW_TASK_BAR_WND 32801 #define ID_32802 32802 #define ID_32803 32803 #define ID_32804 32804 #define ID_32805 32805 #define ID_32806 32806 #define ID_SET_BACK_COLOR 32807 #define ID_32808 32808 #define ID_SET_TEXT_COLOR 32809 #define ID_32810 32810 #define ID_SHOW_CPU_MEMORY2 32811 #define ID_32812 32812 #define ID_MINMIZE 32813 #define ID_32814 32814 #define ID_AUTO_RUN_WHEN_START 32815 #define ID_HIDE_MAIN_WND 32816 #define ID_32817 32817 #define ID_32818 32818 #define ID_CHANGE_SKIN 32819 #define ID_32820 32820 #define ID_SET_FONT 32821 #define ID_32822 32822 #define ID_SET_ 32823 #define ID_SET_FONT2 32824 #define ID_32825 32825 #define ID_TRAFFIC_HISTORY 32826 #define ID_32827 32827 #define ID_32828 32828 #define ID_OPTIONS 32829 #define ID_32830 32830 #define ID_OPTIONS2 32831 #define ID_32832 32832 #define ID_COPY_TEXT 32833 #define ID_32834 32834 #define ID_32835 32835 #define ID_USE_LINEAR_SCALE 32836 #define ID_USE_LOG_SCALE 32837 #define ID_32838 32838 #define ID_CHANGE_NOTIFY_ICON 32839 #define ID_32840 32840 #define ID_ALOW_OUT_OF_BORDER 32841 #define ID_32842 32842 #define ID_32843 32843 #define ID_32844 32844 #define ID_32845 32845 #define ID_CHECK_UPDATE 32846 #define ID_SHOW_MAIN_WND 32847 #define ID_DEFAULT_STYLE1 32848 #define ID_DEFAULT_STYLE_MAX 32857 #define ID_MODIFY_DEFAULT_STYLE1 32858 #define ID_MODIFY_DEFAULT_STYLE_MAX 32867 #define ID_LIGHT_MODE_STYLE 32868 #define ID_SHOW_NET_SPEED 32869 #define ID_FIRST_DAY_OF_WEEK_SUNDAY 32870 #define ID_FIRST_DAY_OF_WEEK_MONDAY 32871 #define ID_CALENDAR_JUMP_TO_TODAY 32872 #define ID_FREQUENTY_ASKED_QUESTIONS 32873 #define ID_CMD_TEST 32874 #define ID_SHOW_UP_SPEED 32875 #define ID_SHOW_DOWN_SPEED 32876 #define ID_SHOW_CPU_USAGE 32877 #define ID_SHOW_MEMORY_USAGE 32878 #define ID_SHOW_CPU_TEMPERATURE 32879 #define ID_SHOW_GPU_TEMPERATURE 32880 #define ID_SHOW_HDD_TEMPERATURE 32881 #define ID_SHOW_MAIN_BOARD_TEMPERATURE 32882 #define ID_SHOW_GPU 32883 #define ID_SHOW_HDD 32884 #define ID_UPDATE_LOG 32885 #define ID_PLUGIN_MANAGE 32886 #define ID_SHOW_PLUGIN_ITEM_START 32887 #define ID_SHOW_PLUGIN_ITEM_MAX 33140 #define ID_SELETE_CONNECTION 33141 #define ID_SELECT_ALL_CONNECTION 33142 #define ID_SELETE_CONNECTION_MAX 33398 #define ID_PLUGIN_DETAIL 33399 #define ID_PLUGIN_OPTIONS 33400 #define ID_PLUGIN_DISABLE 33401 #define ID_SHOW_TOTAL_SPEED 33402 #define ID_OPEN_TASK_MANAGER 33403 #define ID_REFRESH_CONNECTION_LIST 33404 #define ID_DISPLAY_SETTINGS 33405 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 341 #define _APS_NEXT_COMMAND_VALUE 33406 #define _APS_NEXT_CONTROL_VALUE 1166 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: TrafficMonitor/skins/0默认皮肤/skin.ini ================================================ [skin] text_color=16384 skin_author=zy ================================================ FILE: TrafficMonitor/skins/xml_test/skin.xml ================================================  16768959,10022341,16777215,16777215,16777215,16770992,16770992,16770992,16770992 1 zy 上传: 下载: CPU: 内存: 显卡: CPU温度: 显卡温度: ↑↓: b4zc373y b5R30ITQ ================================================ FILE: TrafficMonitor/skins/皮肤01/skin.ini ================================================ [skin] text_color=3803808 skin_author=zy ================================================ FILE: TrafficMonitor/skins/皮肤02/skin.ini ================================================ [skin] text_color=9844741 skin_author=zy ================================================ FILE: TrafficMonitor/skins/皮肤03/skin.ini ================================================ [skin] text_color=16777215 skin_author=zy ================================================ FILE: TrafficMonitor/skins/皮肤04/skin.ini ================================================ [skin] text_color=16777215 skin_author=zy ================================================ FILE: TrafficMonitor/skins/皮肤05/skin.ini ================================================ [skin] text_color=335674 skin_author=zy ================================================ FILE: TrafficMonitor/skins/皮肤06/skin.ini ================================================ [skin] text_color=16773870 skin_author=zy ================================================ FILE: TrafficMonitor/skins/皮肤07/skin.ini ================================================ [skin] text_color=14547455 skin_author=zy ================================================ FILE: TrafficMonitor/skins/皮肤08/skin.ini ================================================ [skin] text_color=16763528 skin_author=zy ================================================ FILE: TrafficMonitor/skins/皮肤09/skin.ini ================================================ [skin] text_color=16384 skin_author=zy ================================================ FILE: TrafficMonitor/skins/皮肤10/skin.ini ================================================ [skin] text_color=9586944 skin_author="zy" [layout] text_height=20 no_text=1 preview_width=238 preview_height=110 width_l=189 height_l=43 up_x_l=24 up_y_l=2 up_width_l=73 up_align_l=0 down_x_l=116 down_y_l=2 down_width_l=73 down_align_l=0 cpu_x_l=24 cpu_y_l=21 cpu_width_l=73 cpu_align_l=0 memory_x_l=116 memory_y_l=21 memory_width_l=73 memory_align_l=0 show_up_l=1 show_down_l=1 show_cpu_l=1 show_memory_l=1 preview_x_l=0 preview_y_l=47 width_s=189 height_s=28 up_x_s=24 up_y_s=4 up_width_s=73 up_align_s=0 down_x_s=116 down_y_s=4 down_width_s=73 down_align_s=0 cpu_x_s=0 cpu_y_s=0 cpu_width_s=0 cpu_align_s=0 memory_x_s=0 memory_y_s=0 memory_width_s=0 memory_align_s=0 show_up_s=1 show_down_s=1 show_cpu_s=0 show_memory_s=0 preview_x_s=0 preview_y_s=0 ================================================ FILE: TrafficMonitor/skins/皮肤10(竖排)/skin.ini ================================================ [skin] text_color=9586944 skin_author="zy" [layout] text_height=20 no_text=1 preview_width=238 preview_height=79 width_l=110 height_l=63 up_x_l=24 up_y_l=2 up_width_l=85 down_x_l=24 down_y_l=21 down_width_l=85 cpu_x_l=24 cpu_y_l=40 cpu_width_l=34 memory_x_l=76 memory_y_l=40 memory_width_l=33 show_up_l=1 show_down_l=1 show_cpu_l=1 show_memory_l=1 preview_x_l=115 preview_y_l=0 width_s=100 height_s=43 up_x_s=24 up_y_s=2 up_width_s=76 down_x_s=24 down_y_s=20 down_width_s=76 cpu_x_s=0 cpu_y_s=0 cpu_width_s=0 memory_x_s=0 memory_y_s=0 memory_width_s=0 show_up_s=1 show_down_s=1 show_cpu_s=0 show_memory_s=0 preview_x_s=0 preview_y_s=0 ================================================ FILE: TrafficMonitor/skins/皮肤11/skin.ini ================================================ [skin] text_color=16777215,0,0,0, specify_each_item_color=0 skin_author="zy" font_name="Segoe UI Semibold" font_size=10 font_style=0 [layout] text_height=20 no_text=1 preview_width=171 preview_height=108 width_l=174 height_l=41 up_x_l=16 up_y_l=1 up_width_l=69 up_align_l=1 down_x_l=16 down_y_l=20 down_width_l=69 down_align_l=1 cpu_x_l=90 cpu_y_l=20 cpu_width_l=42 cpu_align_l=2 memory_x_l=132 memory_y_l=20 memory_width_l=42 memory_align_l=2 show_up_l=1 show_down_l=1 show_cpu_l=1 show_memory_l=1 preview_x_l=0 preview_y_l=55 width_s=90 height_s=41 up_x_s=16 up_y_s=1 up_width_s=69 up_align_s=1 down_x_s=16 down_y_s=20 down_width_s=69 down_align_s=1 cpu_x_s=0 cpu_y_s=0 cpu_width_s=0 cpu_align_s=0 memory_x_s=0 memory_y_s=0 memory_width_s=0 memory_align_s=0 show_up_s=1 show_down_s=1 show_cpu_s=0 show_memory_s=0 preview_x_s=0 preview_y_s=0 ================================================ FILE: TrafficMonitor/skins/默认皮肤2/skin.ini ================================================ [skin] text_color=16384 skin_author=zy [layout] text_height=20 width_l=220 height_l=43 up_x_l=6 up_y_l=2 up_width_l=108 down_x_l=114 down_y_l=2 down_width_l=110 cpu_x_l=6 cpu_y_l=21 cpu_width_l=108 memory_x_l=114 memory_y_l=21 memory_width_l=110 show_up_l = 1 show_down_l = 1 show_cpu_l = 1 show_memory_l = 1 width_s=153 height_s=28 cpu_x_s=6 cpu_y_s=4 cpu_width_s=70 memory_x_s=77 memory_y_s=4 memory_width_s=77 show_item_s = 12 show_up_s = 0 show_down_s = 0 show_cpu_s = 1 show_memory_s = 1 ================================================ FILE: TrafficMonitor/stdafx.cpp ================================================ // stdafx.cpp : ֻ׼ļԴļ // TrafficMonitor.pch ΪԤͷ // stdafx.obj ԤϢ #include "stdafx.h" ================================================ FILE: TrafficMonitor/stdafx.h ================================================  // stdafx.h : 标准系统包含文件的包含文件, // 或是经常使用但不常更改的 // 特定于项目的包含文件 #pragma once #ifndef VC_EXTRALEAN #define VC_EXTRALEAN // 从 Windows 头中排除极少使用的资料 #endif #include "targetver.h" #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 // 关闭 MFC 对某些常见但经常可放心忽略的警告消息的隐藏 #define _AFX_ALL_WARNINGS #include // MFC 核心组件和标准组件 #include // MFC 扩展 #include // MFC 自动化类 #ifndef _AFX_NO_OLE_SUPPORT #include // MFC 对 Internet Explorer 4 公共控件的支持 #endif #ifndef _AFX_NO_AFXCMN_SUPPORT #include // MFC 对 Windows 公共控件的支持 #endif // _AFX_NO_AFXCMN_SUPPORT #include // 功能区和控件条的 MFC 支持 #include "resource.h" #include using std::string; using std::wstring; #include using std::vector; #include using std::deque; #include #include using std::ifstream; using std::ofstream; #include #include #include #include #include #include //用于支持使用网络相关的类 #include #ifdef _UNICODE #if defined _M_IX86 #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") #elif defined _M_X64 #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") #else #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #endif #endif #define MY_WM_NOTIFYICON (WM_USER+1005) #define WM_TASKBAR_WND_CLOSED (WM_USER+1006) //任务栏窗口关闭时发送此消息 #define WM_MONITOR_INFO_UPDATED (WM_USER+1007) //监控信息已更新 #define WM_REOPEN_TASKBAR_WND (WM_USER+1008) //重新打开任务栏窗口 #define WM_SETTINGS_APPLIED (WM_USER+1009) //在选项设置中点击了“应用”按钮 #define WM_NEXT_USER_MSG (WM_USER+1010) //#define CONFIG_PATH _T(".\\config.ini") //#define CONFIG_PATHA ".\\config.ini" //#define LOG_PATH _T(".\\error.log") //#define HISTORY_TRAFFIC_PATH _T(".\\history_traffic.dat") #define MAX_RESTART_CNT 10 //最大重新初始化次数 #define MAIN_TIMER 1234 //主定时器的ID #define DELAY_TIMER 1235 //延时定时器ID #define TASKBAR_TIMER 1236 #define CONNECTION_DETAIL_TIMER 1237 #define MONITOR_TIMER 1238 #define MAX_INSERT_TO_TASKBAR_CNT 5 //尝试嵌入任务栏的最大次数 #define APP_NAME _T("TrafficMonitor") #define APP_CLASS_NAME _T("TrafficMonitor_r7XZaS4p") //程序主窗口的类名 #define VERSION L"1.83" #define MAX_NOTIFY_ICON 6 //可选的通知区图标数量 //背景图片的文件名 #define BACKGROUND_IMAGE_S L"\\background.bmp" #define BACKGROUND_IMAGE_L L"\\background_l.bmp" #define BACKGROUND_MASK_S L"\\background_mask.bmp" #define BACKGROUND_MASK_L L"\\background_mask_l.bmp" #define MIN_FONT_SIZE 5 #define MAX_FONT_SIZE 72 #define SAFE_DELETE(p) do \ {\ if(p != nullptr) \ { \ delete p; \ p = nullptr; \ } \ } while (false) //定义两个用于作为任务栏透明色的颜色(当需要设置任务栏窗口不透明时使用) #define TASKBAR_TRANSPARENT_COLOR1 RGB(52, 28, 41) #define TASKBAR_TRANSPARENT_COLOR2 RGB(38, 67, 55) //如果需要为Windows XP系统编译,请去掉下面一行代码的注释 //#define COMPILE_FOR_WINXP ================================================ FILE: TrafficMonitor/targetver.h ================================================ #pragma once // SDKDDKVer.h õ߰汾 Windows ƽ̨ // ҪΪǰ Windows ƽ̨Ӧó WinSDKVer.h // _WIN32_WINNT ΪҪֵ֧ƽ̨Ȼٰ SDKDDKVer.h #include ================================================ FILE: TrafficMonitor/tinyxml2/tinyxml2.cpp ================================================ /* Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "tinyxml2.h" #include // yes, this one new style header, is in the Android SDK. #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) # include # include #else # include # include #endif #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) // Microsoft Visual Studio, version 2005 and higher. Not WinCE. /*int _snprintf_s( char *buffer, size_t sizeOfBuffer, size_t count, const char *format [, argument] ... );*/ static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) { va_list va; va_start( va, format ); const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); va_end( va ); return result; } static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) { const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); return result; } #define TIXML_VSCPRINTF _vscprintf #define TIXML_SSCANF sscanf_s #elif defined _MSC_VER // Microsoft Visual Studio 2003 and earlier or WinCE #define TIXML_SNPRINTF _snprintf #define TIXML_VSNPRINTF _vsnprintf #define TIXML_SSCANF sscanf #if (_MSC_VER < 1400 ) && (!defined WINCE) // Microsoft Visual Studio 2003 and not WinCE. #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. #else // Microsoft Visual Studio 2003 and earlier or WinCE. static inline int TIXML_VSCPRINTF( const char* format, va_list va ) { int len = 512; for (;;) { len = len*2; char* str = new char[len](); const int required = _vsnprintf(str, len, format, va); delete[] str; if ( required != -1 ) { TIXMLASSERT( required >= 0 ); len = required; break; } } TIXMLASSERT( len >= 0 ); return len; } #endif #else // GCC version 3 and higher //#warning( "Using sn* functions." ) #define TIXML_SNPRINTF snprintf #define TIXML_VSNPRINTF vsnprintf static inline int TIXML_VSCPRINTF( const char* format, va_list va ) { int len = vsnprintf( 0, 0, format, va ); TIXMLASSERT( len >= 0 ); return len; } #define TIXML_SSCANF sscanf #endif #if defined(_WIN64) #define TIXML_FSEEK _fseeki64 #define TIXML_FTELL _ftelli64 #elif defined(__APPLE__) || (__FreeBSD__) #define TIXML_FSEEK fseeko #define TIXML_FTELL ftello #elif defined(__unix__) && defined(__x86_64__) #define TIXML_FSEEK fseeko64 #define TIXML_FTELL ftello64 #else #define TIXML_FSEEK fseek #define TIXML_FTELL ftell #endif static const char LINE_FEED = static_cast(0x0a); // all line endings are normalized to LF static const char LF = LINE_FEED; static const char CARRIAGE_RETURN = static_cast(0x0d); // CR gets filtered out static const char CR = CARRIAGE_RETURN; static const char SINGLE_QUOTE = '\''; static const char DOUBLE_QUOTE = '\"'; // Bunch of unicode info at: // http://www.unicode.org/faq/utf_bom.html // ef bb bf (Microsoft "lead bytes") - designates UTF-8 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; namespace tinyxml2 { struct Entity { const char* pattern; int length; char value; }; static const int NUM_ENTITIES = 5; static const Entity entities[NUM_ENTITIES] = { { "quot", 4, DOUBLE_QUOTE }, { "amp", 3, '&' }, { "apos", 4, SINGLE_QUOTE }, { "lt", 2, '<' }, { "gt", 2, '>' } }; StrPair::~StrPair() { Reset(); } void StrPair::TransferTo( StrPair* other ) { if ( this == other ) { return; } // This in effect implements the assignment operator by "moving" // ownership (as in auto_ptr). TIXMLASSERT( other != 0 ); TIXMLASSERT( other->_flags == 0 ); TIXMLASSERT( other->_start == 0 ); TIXMLASSERT( other->_end == 0 ); other->Reset(); other->_flags = _flags; other->_start = _start; other->_end = _end; _flags = 0; _start = 0; _end = 0; } void StrPair::Reset() { if ( _flags & NEEDS_DELETE ) { delete [] _start; } _flags = 0; _start = 0; _end = 0; } void StrPair::SetStr( const char* str, int flags ) { TIXMLASSERT( str ); Reset(); size_t len = strlen( str ); TIXMLASSERT( _start == 0 ); _start = new char[ len+1 ]; memcpy( _start, str, len+1 ); _end = _start + len; _flags = flags | NEEDS_DELETE; } char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr ) { TIXMLASSERT( p ); TIXMLASSERT( endTag && *endTag ); TIXMLASSERT(curLineNumPtr); char* start = p; const char endChar = *endTag; size_t length = strlen( endTag ); // Inner loop of text parsing. while ( *p ) { if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { Set( start, p, strFlags ); return p + length; } else if (*p == '\n') { ++(*curLineNumPtr); } ++p; TIXMLASSERT( p ); } return 0; } char* StrPair::ParseName( char* p ) { if ( !p || !(*p) ) { return 0; } if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) { return 0; } char* const start = p; ++p; while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) { ++p; } Set( start, p, 0 ); return p; } void StrPair::CollapseWhitespace() { // Adjusting _start would cause undefined behavior on delete[] TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); // Trim leading space. _start = XMLUtil::SkipWhiteSpace( _start, 0 ); if ( *_start ) { const char* p = _start; // the read pointer char* q = _start; // the write pointer while( *p ) { if ( XMLUtil::IsWhiteSpace( *p )) { p = XMLUtil::SkipWhiteSpace( p, 0 ); if ( *p == 0 ) { break; // don't write to q; this trims the trailing space. } *q = ' '; ++q; } *q = *p; ++q; ++p; } *q = 0; } } const char* StrPair::GetStr() { TIXMLASSERT( _start ); TIXMLASSERT( _end ); if ( _flags & NEEDS_FLUSH ) { *_end = 0; _flags ^= NEEDS_FLUSH; if ( _flags ) { const char* p = _start; // the read pointer char* q = _start; // the write pointer while( p < _end ) { if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { // CR-LF pair becomes LF // CR alone becomes LF // LF-CR becomes LF if ( *(p+1) == LF ) { p += 2; } else { ++p; } *q = LF; ++q; } else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { if ( *(p+1) == CR ) { p += 2; } else { ++p; } *q = LF; ++q; } else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { // Entities handled by tinyXML2: // - special entities in the entity table [in/out] // - numeric character reference [in] // 中 or 中 if ( *(p+1) == '#' ) { const int buflen = 10; char buf[buflen] = { 0 }; int len = 0; const char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); if ( adjusted == 0 ) { *q = *p; ++p; ++q; } else { TIXMLASSERT( 0 <= len && len <= buflen ); TIXMLASSERT( q + len <= adjusted ); p = adjusted; memcpy( q, buf, len ); q += len; } } else { bool entityFound = false; for( int i = 0; i < NUM_ENTITIES; ++i ) { const Entity& entity = entities[i]; if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 && *( p + entity.length + 1 ) == ';' ) { // Found an entity - convert. *q = entity.value; ++q; p += entity.length + 2; entityFound = true; break; } } if ( !entityFound ) { // fixme: treat as error? ++p; ++q; } } } else { *q = *p; ++p; ++q; } } *q = 0; } // The loop below has plenty going on, and this // is a less useful mode. Break it out. if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) { CollapseWhitespace(); } _flags = (_flags & NEEDS_DELETE); } TIXMLASSERT( _start ); return _start; } // --------- XMLUtil ----------- // const char* XMLUtil::writeBoolTrue = "true"; const char* XMLUtil::writeBoolFalse = "false"; void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse) { static const char* defTrue = "true"; static const char* defFalse = "false"; writeBoolTrue = (writeTrue) ? writeTrue : defTrue; writeBoolFalse = (writeFalse) ? writeFalse : defFalse; } const char* XMLUtil::ReadBOM( const char* p, bool* bom ) { TIXMLASSERT( p ); TIXMLASSERT( bom ); *bom = false; const unsigned char* pu = reinterpret_cast(p); // Check for BOM: if ( *(pu+0) == TIXML_UTF_LEAD_0 && *(pu+1) == TIXML_UTF_LEAD_1 && *(pu+2) == TIXML_UTF_LEAD_2 ) { *bom = true; p += 3; } TIXMLASSERT( p ); return p; } void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) { const unsigned long BYTE_MASK = 0xBF; const unsigned long BYTE_MARK = 0x80; const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; if (input < 0x80) { *length = 1; } else if ( input < 0x800 ) { *length = 2; } else if ( input < 0x10000 ) { *length = 3; } else if ( input < 0x200000 ) { *length = 4; } else { *length = 0; // This code won't convert this correctly anyway. return; } output += *length; // Scary scary fall throughs are annotated with carefully designed comments // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc switch (*length) { case 4: --output; *output = static_cast((input | BYTE_MARK) & BYTE_MASK); input >>= 6; //fall through case 3: --output; *output = static_cast((input | BYTE_MARK) & BYTE_MASK); input >>= 6; //fall through case 2: --output; *output = static_cast((input | BYTE_MARK) & BYTE_MASK); input >>= 6; //fall through case 1: --output; *output = static_cast(input | FIRST_BYTE_MARK[*length]); break; default: TIXMLASSERT( false ); } } const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) { // Presume an entity, and pull it out. *length = 0; if ( *(p+1) == '#' && *(p+2) ) { unsigned long ucs = 0; TIXMLASSERT( sizeof( ucs ) >= 4 ); ptrdiff_t delta = 0; unsigned mult = 1; static const char SEMICOLON = ';'; if ( *(p+2) == 'x' ) { // Hexadecimal. const char* q = p+3; if ( !(*q) ) { return 0; } q = strchr( q, SEMICOLON ); if ( !q ) { return 0; } TIXMLASSERT( *q == SEMICOLON ); delta = q-p; --q; while ( *q != 'x' ) { unsigned int digit = 0; if ( *q >= '0' && *q <= '9' ) { digit = *q - '0'; } else if ( *q >= 'a' && *q <= 'f' ) { digit = *q - 'a' + 10; } else if ( *q >= 'A' && *q <= 'F' ) { digit = *q - 'A' + 10; } else { return 0; } TIXMLASSERT( digit < 16 ); TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); const unsigned int digitScaled = mult * digit; TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); ucs += digitScaled; TIXMLASSERT( mult <= UINT_MAX / 16 ); mult *= 16; --q; } } else { // Decimal. const char* q = p+2; if ( !(*q) ) { return 0; } q = strchr( q, SEMICOLON ); if ( !q ) { return 0; } TIXMLASSERT( *q == SEMICOLON ); delta = q-p; --q; while ( *q != '#' ) { if ( *q >= '0' && *q <= '9' ) { const unsigned int digit = *q - '0'; TIXMLASSERT( digit < 10 ); TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); const unsigned int digitScaled = mult * digit; TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); ucs += digitScaled; } else { return 0; } TIXMLASSERT( mult <= UINT_MAX / 10 ); mult *= 10; --q; } } // convert the UCS to UTF-8 ConvertUTF32ToUTF8( ucs, value, length ); return p + delta + 1; } return p+1; } void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) { TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); } void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) { TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); } void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) { TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse); } /* ToStr() of a number is a very tricky topic. https://github.com/leethomason/tinyxml2/issues/106 */ void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) { TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); } void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) { TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); } void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize ) { // horrible syntax trick to make the compiler happy about %lld TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast(v)); } void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize ) { // horrible syntax trick to make the compiler happy about %llu TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v); } bool XMLUtil::ToInt(const char* str, int* value) { if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%d", value) == 1) { return true; } return false; } bool XMLUtil::ToUnsigned(const char* str, unsigned* value) { if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%u", value) == 1) { return true; } return false; } bool XMLUtil::ToBool( const char* str, bool* value ) { int ival = 0; if ( ToInt( str, &ival )) { *value = (ival==0) ? false : true; return true; } static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 }; static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 }; for (int i = 0; TRUE_VALS[i]; ++i) { if (StringEqual(str, TRUE_VALS[i])) { *value = true; return true; } } for (int i = 0; FALSE_VALS[i]; ++i) { if (StringEqual(str, FALSE_VALS[i])) { *value = false; return true; } } return false; } bool XMLUtil::ToFloat( const char* str, float* value ) { if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { return true; } return false; } bool XMLUtil::ToDouble( const char* str, double* value ) { if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { return true; } return false; } bool XMLUtil::ToInt64(const char* str, int64_t* value) { long long v = 0; // horrible syntax trick to make the compiler happy about %lld if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%lld", &v) == 1) { *value = static_cast(v); return true; } return false; } bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) { unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) { *value = (uint64_t)v; return true; } return false; } char* XMLDocument::Identify( char* p, XMLNode** node ) { TIXMLASSERT( node ); TIXMLASSERT( p ); char* const start = p; int const startLine = _parseCurLineNum; p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); if( !*p ) { *node = 0; TIXMLASSERT( p ); return p; } // These strings define the matching patterns: static const char* xmlHeader = { "( _commentPool ); returnNode->_parseLineNum = _parseCurLineNum; p += xmlHeaderLen; } else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { returnNode = CreateUnlinkedNode( _commentPool ); returnNode->_parseLineNum = _parseCurLineNum; p += commentHeaderLen; } else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { XMLText* text = CreateUnlinkedNode( _textPool ); returnNode = text; returnNode->_parseLineNum = _parseCurLineNum; p += cdataHeaderLen; text->SetCData( true ); } else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { returnNode = CreateUnlinkedNode( _commentPool ); returnNode->_parseLineNum = _parseCurLineNum; p += dtdHeaderLen; } else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { returnNode = CreateUnlinkedNode( _elementPool ); returnNode->_parseLineNum = _parseCurLineNum; p += elementHeaderLen; } else { returnNode = CreateUnlinkedNode( _textPool ); returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character p = start; // Back it up, all the text counts. _parseCurLineNum = startLine; } TIXMLASSERT( returnNode ); TIXMLASSERT( p ); *node = returnNode; return p; } bool XMLDocument::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); if ( visitor->VisitEnter( *this ) ) { for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) { break; } } } return visitor->VisitExit( *this ); } // --------- XMLNode ----------- // XMLNode::XMLNode( XMLDocument* doc ) : _document( doc ), _parent( 0 ), _value(), _parseLineNum( 0 ), _firstChild( 0 ), _lastChild( 0 ), _prev( 0 ), _next( 0 ), _userData( 0 ), _memPool( 0 ) { } XMLNode::~XMLNode() { DeleteChildren(); if ( _parent ) { _parent->Unlink( this ); } } const char* XMLNode::Value() const { // Edge case: XMLDocuments don't have a Value. Return null. if ( this->ToDocument() ) return 0; return _value.GetStr(); } void XMLNode::SetValue( const char* str, bool staticMem ) { if ( staticMem ) { _value.SetInternedStr( str ); } else { _value.SetStr( str ); } } XMLNode* XMLNode::DeepClone(XMLDocument* target) const { XMLNode* clone = this->ShallowClone(target); if (!clone) return 0; for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) { XMLNode* childClone = child->DeepClone(target); TIXMLASSERT(childClone); clone->InsertEndChild(childClone); } return clone; } void XMLNode::DeleteChildren() { while( _firstChild ) { TIXMLASSERT( _lastChild ); DeleteChild( _firstChild ); } _firstChild = _lastChild = 0; } void XMLNode::Unlink( XMLNode* child ) { TIXMLASSERT( child ); TIXMLASSERT( child->_document == _document ); TIXMLASSERT( child->_parent == this ); if ( child == _firstChild ) { _firstChild = _firstChild->_next; } if ( child == _lastChild ) { _lastChild = _lastChild->_prev; } if ( child->_prev ) { child->_prev->_next = child->_next; } if ( child->_next ) { child->_next->_prev = child->_prev; } child->_next = 0; child->_prev = 0; child->_parent = 0; } void XMLNode::DeleteChild( XMLNode* node ) { TIXMLASSERT( node ); TIXMLASSERT( node->_document == _document ); TIXMLASSERT( node->_parent == this ); Unlink( node ); TIXMLASSERT(node->_prev == 0); TIXMLASSERT(node->_next == 0); TIXMLASSERT(node->_parent == 0); DeleteNode( node ); } XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) { TIXMLASSERT( addThis ); if ( addThis->_document != _document ) { TIXMLASSERT( false ); return 0; } InsertChildPreamble( addThis ); if ( _lastChild ) { TIXMLASSERT( _firstChild ); TIXMLASSERT( _lastChild->_next == 0 ); _lastChild->_next = addThis; addThis->_prev = _lastChild; _lastChild = addThis; addThis->_next = 0; } else { TIXMLASSERT( _firstChild == 0 ); _firstChild = _lastChild = addThis; addThis->_prev = 0; addThis->_next = 0; } addThis->_parent = this; return addThis; } XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) { TIXMLASSERT( addThis ); if ( addThis->_document != _document ) { TIXMLASSERT( false ); return 0; } InsertChildPreamble( addThis ); if ( _firstChild ) { TIXMLASSERT( _lastChild ); TIXMLASSERT( _firstChild->_prev == 0 ); _firstChild->_prev = addThis; addThis->_next = _firstChild; _firstChild = addThis; addThis->_prev = 0; } else { TIXMLASSERT( _lastChild == 0 ); _firstChild = _lastChild = addThis; addThis->_prev = 0; addThis->_next = 0; } addThis->_parent = this; return addThis; } XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) { TIXMLASSERT( addThis ); if ( addThis->_document != _document ) { TIXMLASSERT( false ); return 0; } TIXMLASSERT( afterThis ); if ( afterThis->_parent != this ) { TIXMLASSERT( false ); return 0; } if ( afterThis == addThis ) { // Current state: BeforeThis -> AddThis -> OneAfterAddThis // Now AddThis must disappear from it's location and then // reappear between BeforeThis and OneAfterAddThis. // So just leave it where it is. return addThis; } if ( afterThis->_next == 0 ) { // The last node or the only node. return InsertEndChild( addThis ); } InsertChildPreamble( addThis ); addThis->_prev = afterThis; addThis->_next = afterThis->_next; afterThis->_next->_prev = addThis; afterThis->_next = addThis; addThis->_parent = this; return addThis; } const XMLElement* XMLNode::FirstChildElement( const char* name ) const { for( const XMLNode* node = _firstChild; node; node = node->_next ) { const XMLElement* element = node->ToElementWithName( name ); if ( element ) { return element; } } return 0; } const XMLElement* XMLNode::LastChildElement( const char* name ) const { for( const XMLNode* node = _lastChild; node; node = node->_prev ) { const XMLElement* element = node->ToElementWithName( name ); if ( element ) { return element; } } return 0; } const XMLElement* XMLNode::NextSiblingElement( const char* name ) const { for( const XMLNode* node = _next; node; node = node->_next ) { const XMLElement* element = node->ToElementWithName( name ); if ( element ) { return element; } } return 0; } const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const { for( const XMLNode* node = _prev; node; node = node->_prev ) { const XMLElement* element = node->ToElementWithName( name ); if ( element ) { return element; } } return 0; } char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) { // This is a recursive method, but thinking about it "at the current level" // it is a pretty simple flat list: // // // // With a special case: // // // // // Where the closing element (/foo) *must* be the next thing after the opening // element, and the names must match. BUT the tricky bit is that the closing // element will be read by the child. // // 'endTag' is the end tag for this node, it is returned by a call to a child. // 'parentEnd' is the end tag for the parent, which is filled in and returned. XMLDocument::DepthTracker tracker(_document); if (_document->Error()) return 0; while( p && *p ) { XMLNode* node = 0; p = _document->Identify( p, &node ); TIXMLASSERT( p ); if ( node == 0 ) { break; } const int initialLineNum = node->_parseLineNum; StrPair endTag; p = node->ParseDeep( p, &endTag, curLineNumPtr ); if ( !p ) { DeleteNode( node ); if ( !_document->Error() ) { _document->SetError( XML_ERROR_PARSING, initialLineNum, 0); } break; } const XMLDeclaration* const decl = node->ToDeclaration(); if ( decl ) { // Declarations are only allowed at document level // // Multiple declarations are allowed but all declarations // must occur before anything else. // // Optimized due to a security test case. If the first node is // a declaration, and the last node is a declaration, then only // declarations have so far been added. bool wellLocated = false; if (ToDocument()) { if (FirstChild()) { wellLocated = FirstChild() && FirstChild()->ToDeclaration() && LastChild() && LastChild()->ToDeclaration(); } else { wellLocated = true; } } if ( !wellLocated ) { _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); DeleteNode( node ); break; } } XMLElement* ele = node->ToElement(); if ( ele ) { // We read the end tag. Return it to the parent. if ( ele->ClosingType() == XMLElement::CLOSING ) { if ( parentEndTag ) { ele->_value.TransferTo( parentEndTag ); } node->_memPool->SetTracked(); // created and then immediately deleted. DeleteNode( node ); return p; } // Handle an end tag returned to this level. // And handle a bunch of annoying errors. bool mismatch = false; if ( endTag.Empty() ) { if ( ele->ClosingType() == XMLElement::OPEN ) { mismatch = true; } } else { if ( ele->ClosingType() != XMLElement::OPEN ) { mismatch = true; } else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { mismatch = true; } } if ( mismatch ) { _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); DeleteNode( node ); break; } } InsertEndChild( node ); } return 0; } /*static*/ void XMLNode::DeleteNode( XMLNode* node ) { if ( node == 0 ) { return; } TIXMLASSERT(node->_document); if (!node->ToDocument()) { node->_document->MarkInUse(node); } MemPool* pool = node->_memPool; node->~XMLNode(); pool->Free( node ); } void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const { TIXMLASSERT( insertThis ); TIXMLASSERT( insertThis->_document == _document ); if (insertThis->_parent) { insertThis->_parent->Unlink( insertThis ); } else { insertThis->_document->MarkInUse(insertThis); insertThis->_memPool->SetTracked(); } } const XMLElement* XMLNode::ToElementWithName( const char* name ) const { const XMLElement* element = this->ToElement(); if ( element == 0 ) { return 0; } if ( name == 0 ) { return element; } if ( XMLUtil::StringEqual( element->Name(), name ) ) { return element; } return 0; } // --------- XMLText ---------- // char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { if ( this->CData() ) { p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( !p ) { _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 ); } return p; } else { int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; } p = _value.ParseText( p, "<", flags, curLineNumPtr ); if ( p && *p ) { return p-1; } if ( !p ) { _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 ); } } return 0; } XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const { if ( !doc ) { doc = _document; } XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? text->SetCData( this->CData() ); return text; } bool XMLText::ShallowEqual( const XMLNode* compare ) const { TIXMLASSERT( compare ); const XMLText* text = compare->ToText(); return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); } bool XMLText::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); return visitor->Visit( *this ); } // --------- XMLComment ---------- // XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) { } XMLComment::~XMLComment() { } char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { // Comment parses as text. p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr ); if ( p == 0 ) { _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 ); } return p; } XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const { if ( !doc ) { doc = _document; } XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? return comment; } bool XMLComment::ShallowEqual( const XMLNode* compare ) const { TIXMLASSERT( compare ); const XMLComment* comment = compare->ToComment(); return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); } bool XMLComment::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); return visitor->Visit( *this ); } // --------- XMLDeclaration ---------- // XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) { } XMLDeclaration::~XMLDeclaration() { //printf( "~XMLDeclaration\n" ); } char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { // Declaration parses as text. p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( p == 0 ) { _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 ); } return p; } XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const { if ( !doc ) { doc = _document; } XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? return dec; } bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const { TIXMLASSERT( compare ); const XMLDeclaration* declaration = compare->ToDeclaration(); return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); } bool XMLDeclaration::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); return visitor->Visit( *this ); } // --------- XMLUnknown ---------- // XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) { } XMLUnknown::~XMLUnknown() { } char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { // Unknown parses as text. p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( !p ) { _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 ); } return p; } XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const { if ( !doc ) { doc = _document; } XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? return text; } bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const { TIXMLASSERT( compare ); const XMLUnknown* unknown = compare->ToUnknown(); return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); } bool XMLUnknown::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); return visitor->Visit( *this ); } // --------- XMLAttribute ---------- // const char* XMLAttribute::Name() const { return _name.GetStr(); } const char* XMLAttribute::Value() const { return _value.GetStr(); } char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr ) { // Parse using the name rules: bug fix, was using ParseText before p = _name.ParseName( p ); if ( !p || !*p ) { return 0; } // Skip white space before = p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); if ( *p != '=' ) { return 0; } ++p; // move up to opening quote p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); if ( *p != '\"' && *p != '\'' ) { return 0; } const char endTag[2] = { *p, 0 }; ++p; // move past opening quote p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr ); return p; } void XMLAttribute::SetName( const char* n ) { _name.SetStr( n ); } XMLError XMLAttribute::QueryIntValue( int* value ) const { if ( XMLUtil::ToInt( Value(), value )) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const { if ( XMLUtil::ToUnsigned( Value(), value )) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryInt64Value(int64_t* value) const { if (XMLUtil::ToInt64(Value(), value)) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const { if(XMLUtil::ToUnsigned64(Value(), value)) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryBoolValue( bool* value ) const { if ( XMLUtil::ToBool( Value(), value )) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryFloatValue( float* value ) const { if ( XMLUtil::ToFloat( Value(), value )) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryDoubleValue( double* value ) const { if ( XMLUtil::ToDouble( Value(), value )) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } void XMLAttribute::SetAttribute( const char* v ) { _value.SetStr( v ); } void XMLAttribute::SetAttribute( int v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); _value.SetStr( buf ); } void XMLAttribute::SetAttribute( unsigned v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); _value.SetStr( buf ); } void XMLAttribute::SetAttribute(int64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); _value.SetStr(buf); } void XMLAttribute::SetAttribute(uint64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); _value.SetStr(buf); } void XMLAttribute::SetAttribute( bool v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); _value.SetStr( buf ); } void XMLAttribute::SetAttribute( double v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); _value.SetStr( buf ); } void XMLAttribute::SetAttribute( float v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); _value.SetStr( buf ); } // --------- XMLElement ---------- // XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), _closingType( OPEN ), _rootAttribute( 0 ) { } XMLElement::~XMLElement() { while( _rootAttribute ) { XMLAttribute* next = _rootAttribute->_next; DeleteAttribute( _rootAttribute ); _rootAttribute = next; } } const XMLAttribute* XMLElement::FindAttribute( const char* name ) const { for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { if ( XMLUtil::StringEqual( a->Name(), name ) ) { return a; } } return 0; } const char* XMLElement::Attribute( const char* name, const char* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return 0; } if ( !value || XMLUtil::StringEqual( a->Value(), value )) { return a->Value(); } return 0; } int XMLElement::IntAttribute(const char* name, int defaultValue) const { int i = defaultValue; QueryIntAttribute(name, &i); return i; } unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const { unsigned i = defaultValue; QueryUnsignedAttribute(name, &i); return i; } int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const { int64_t i = defaultValue; QueryInt64Attribute(name, &i); return i; } uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const { uint64_t i = defaultValue; QueryUnsigned64Attribute(name, &i); return i; } bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const { bool b = defaultValue; QueryBoolAttribute(name, &b); return b; } double XMLElement::DoubleAttribute(const char* name, double defaultValue) const { double d = defaultValue; QueryDoubleAttribute(name, &d); return d; } float XMLElement::FloatAttribute(const char* name, float defaultValue) const { float f = defaultValue; QueryFloatAttribute(name, &f); return f; } const char* XMLElement::GetText() const { if ( FirstChild() && FirstChild()->ToText() ) { return FirstChild()->Value(); } return 0; } void XMLElement::SetText( const char* inText ) { if ( FirstChild() && FirstChild()->ToText() ) FirstChild()->SetValue( inText ); else { XMLText* theText = GetDocument()->NewText( inText ); InsertFirstChild( theText ); } } void XMLElement::SetText( int v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); SetText( buf ); } void XMLElement::SetText( unsigned v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); SetText( buf ); } void XMLElement::SetText(int64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); SetText(buf); } void XMLElement::SetText(uint64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); SetText(buf); } void XMLElement::SetText( bool v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); SetText( buf ); } void XMLElement::SetText( float v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); SetText( buf ); } void XMLElement::SetText( double v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); SetText( buf ); } XMLError XMLElement::QueryIntText( int* ival ) const { if ( FirstChild() && FirstChild()->ToText() ) { const char* t = FirstChild()->Value(); if ( XMLUtil::ToInt( t, ival ) ) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const { if ( FirstChild() && FirstChild()->ToText() ) { const char* t = FirstChild()->Value(); if ( XMLUtil::ToUnsigned( t, uval ) ) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryInt64Text(int64_t* ival) const { if (FirstChild() && FirstChild()->ToText()) { const char* t = FirstChild()->Value(); if (XMLUtil::ToInt64(t, ival)) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const { if(FirstChild() && FirstChild()->ToText()) { const char* t = FirstChild()->Value(); if(XMLUtil::ToUnsigned64(t, ival)) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryBoolText( bool* bval ) const { if ( FirstChild() && FirstChild()->ToText() ) { const char* t = FirstChild()->Value(); if ( XMLUtil::ToBool( t, bval ) ) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryDoubleText( double* dval ) const { if ( FirstChild() && FirstChild()->ToText() ) { const char* t = FirstChild()->Value(); if ( XMLUtil::ToDouble( t, dval ) ) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryFloatText( float* fval ) const { if ( FirstChild() && FirstChild()->ToText() ) { const char* t = FirstChild()->Value(); if ( XMLUtil::ToFloat( t, fval ) ) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } int XMLElement::IntText(int defaultValue) const { int i = defaultValue; QueryIntText(&i); return i; } unsigned XMLElement::UnsignedText(unsigned defaultValue) const { unsigned i = defaultValue; QueryUnsignedText(&i); return i; } int64_t XMLElement::Int64Text(int64_t defaultValue) const { int64_t i = defaultValue; QueryInt64Text(&i); return i; } uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const { uint64_t i = defaultValue; QueryUnsigned64Text(&i); return i; } bool XMLElement::BoolText(bool defaultValue) const { bool b = defaultValue; QueryBoolText(&b); return b; } double XMLElement::DoubleText(double defaultValue) const { double d = defaultValue; QueryDoubleText(&d); return d; } float XMLElement::FloatText(float defaultValue) const { float f = defaultValue; QueryFloatText(&f); return f; } XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) { XMLAttribute* last = 0; XMLAttribute* attrib = 0; for( attrib = _rootAttribute; attrib; last = attrib, attrib = attrib->_next ) { if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { break; } } if ( !attrib ) { attrib = CreateAttribute(); TIXMLASSERT( attrib ); if ( last ) { TIXMLASSERT( last->_next == 0 ); last->_next = attrib; } else { TIXMLASSERT( _rootAttribute == 0 ); _rootAttribute = attrib; } attrib->SetName( name ); } return attrib; } void XMLElement::DeleteAttribute( const char* name ) { XMLAttribute* prev = 0; for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { if ( XMLUtil::StringEqual( name, a->Name() ) ) { if ( prev ) { prev->_next = a->_next; } else { _rootAttribute = a->_next; } DeleteAttribute( a ); break; } prev = a; } } char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) { XMLAttribute* prevAttribute = 0; // Read the attributes. while( p ) { p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); if ( !(*p) ) { _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() ); return 0; } // attribute. if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) { XMLAttribute* attrib = CreateAttribute(); TIXMLASSERT( attrib ); attrib->_parseLineNum = _document->_parseCurLineNum; const int attrLineNum = attrib->_parseLineNum; p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr ); if ( !p || Attribute( attrib->Name() ) ) { DeleteAttribute( attrib ); _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() ); return 0; } // There is a minor bug here: if the attribute in the source xml // document is duplicated, it will not be detected and the // attribute will be doubly added. However, tracking the 'prevAttribute' // avoids re-scanning the attribute list. Preferring performance for // now, may reconsider in the future. if ( prevAttribute ) { TIXMLASSERT( prevAttribute->_next == 0 ); prevAttribute->_next = attrib; } else { TIXMLASSERT( _rootAttribute == 0 ); _rootAttribute = attrib; } prevAttribute = attrib; } // end of the tag else if ( *p == '>' ) { ++p; break; } // end of the tag else if ( *p == '/' && *(p+1) == '>' ) { _closingType = CLOSED; return p+2; // done; sealed element. } else { _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 ); return 0; } } return p; } void XMLElement::DeleteAttribute( XMLAttribute* attribute ) { if ( attribute == 0 ) { return; } MemPool* pool = attribute->_memPool; attribute->~XMLAttribute(); pool->Free( attribute ); } XMLAttribute* XMLElement::CreateAttribute() { TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); TIXMLASSERT( attrib ); attrib->_memPool = &_document->_attributePool; attrib->_memPool->SetTracked(); return attrib; } XMLElement* XMLElement::InsertNewChildElement(const char* name) { XMLElement* node = _document->NewElement(name); return InsertEndChild(node) ? node : 0; } XMLComment* XMLElement::InsertNewComment(const char* comment) { XMLComment* node = _document->NewComment(comment); return InsertEndChild(node) ? node : 0; } XMLText* XMLElement::InsertNewText(const char* text) { XMLText* node = _document->NewText(text); return InsertEndChild(node) ? node : 0; } XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text) { XMLDeclaration* node = _document->NewDeclaration(text); return InsertEndChild(node) ? node : 0; } XMLUnknown* XMLElement::InsertNewUnknown(const char* text) { XMLUnknown* node = _document->NewUnknown(text); return InsertEndChild(node) ? node : 0; } // // // foobar // char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) { // Read the element name. p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); // The closing element is the form. It is // parsed just like a regular element then deleted from // the DOM. if ( *p == '/' ) { _closingType = CLOSING; ++p; } p = _value.ParseName( p ); if ( _value.Empty() ) { return 0; } p = ParseAttributes( p, curLineNumPtr ); if ( !p || !*p || _closingType != OPEN ) { return p; } p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr ); return p; } XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const { if ( !doc ) { doc = _document; } XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? } return element; } bool XMLElement::ShallowEqual( const XMLNode* compare ) const { TIXMLASSERT( compare ); const XMLElement* other = compare->ToElement(); if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { const XMLAttribute* a=FirstAttribute(); const XMLAttribute* b=other->FirstAttribute(); while ( a && b ) { if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { return false; } a = a->Next(); b = b->Next(); } if ( a || b ) { // different count return false; } return true; } return false; } bool XMLElement::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); if ( visitor->VisitEnter( *this, _rootAttribute ) ) { for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) { break; } } } return visitor->VisitExit( *this ); } // --------- XMLDocument ----------- // // Warning: List must match 'enum XMLError' const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { "XML_SUCCESS", "XML_NO_ATTRIBUTE", "XML_WRONG_ATTRIBUTE_TYPE", "XML_ERROR_FILE_NOT_FOUND", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", "XML_ERROR_FILE_READ_ERROR", "XML_ERROR_PARSING_ELEMENT", "XML_ERROR_PARSING_ATTRIBUTE", "XML_ERROR_PARSING_TEXT", "XML_ERROR_PARSING_CDATA", "XML_ERROR_PARSING_COMMENT", "XML_ERROR_PARSING_DECLARATION", "XML_ERROR_PARSING_UNKNOWN", "XML_ERROR_EMPTY_DOCUMENT", "XML_ERROR_MISMATCHED_ELEMENT", "XML_ERROR_PARSING", "XML_CAN_NOT_CONVERT_TEXT", "XML_NO_TEXT_NODE", "XML_ELEMENT_DEPTH_EXCEEDED" }; XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) : XMLNode( 0 ), _writeBOM( false ), _processEntities( processEntities ), _errorID(XML_SUCCESS), _whitespaceMode( whitespaceMode ), _errorStr(), _errorLineNum( 0 ), _charBuffer( 0 ), _parseCurLineNum( 0 ), _parsingDepth(0), _unlinked(), _elementPool(), _attributePool(), _textPool(), _commentPool() { // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) _document = this; } XMLDocument::~XMLDocument() { Clear(); } void XMLDocument::MarkInUse(const XMLNode* const node) { TIXMLASSERT(node); TIXMLASSERT(node->_parent == 0); for (int i = 0; i < _unlinked.Size(); ++i) { if (node == _unlinked[i]) { _unlinked.SwapRemove(i); break; } } } void XMLDocument::Clear() { DeleteChildren(); while( _unlinked.Size()) { DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete. } #ifdef TINYXML2_DEBUG const bool hadError = Error(); #endif ClearError(); delete [] _charBuffer; _charBuffer = 0; _parsingDepth = 0; #if 0 _textPool.Trace( "text" ); _elementPool.Trace( "element" ); _commentPool.Trace( "comment" ); _attributePool.Trace( "attribute" ); #endif #ifdef TINYXML2_DEBUG if ( !hadError ) { TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); } #endif } void XMLDocument::DeepCopy(XMLDocument* target) const { TIXMLASSERT(target); if (target == this) { return; // technically success - a no-op. } target->Clear(); for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { target->InsertEndChild(node->DeepClone(target)); } } XMLElement* XMLDocument::NewElement( const char* name ) { XMLElement* ele = CreateUnlinkedNode( _elementPool ); ele->SetName( name ); return ele; } XMLComment* XMLDocument::NewComment( const char* str ) { XMLComment* comment = CreateUnlinkedNode( _commentPool ); comment->SetValue( str ); return comment; } XMLText* XMLDocument::NewText( const char* str ) { XMLText* text = CreateUnlinkedNode( _textPool ); text->SetValue( str ); return text; } XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) { XMLDeclaration* dec = CreateUnlinkedNode( _commentPool ); dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); return dec; } XMLUnknown* XMLDocument::NewUnknown( const char* str ) { XMLUnknown* unk = CreateUnlinkedNode( _commentPool ); unk->SetValue( str ); return unk; } static FILE* callfopen( const char* filepath, const char* mode ) { TIXMLASSERT( filepath ); TIXMLASSERT( mode ); #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) FILE* fp = 0; const errno_t err = fopen_s( &fp, filepath, mode ); if ( err ) { return 0; } #else FILE* fp = fopen( filepath, mode ); #endif return fp; } void XMLDocument::DeleteNode( XMLNode* node ) { TIXMLASSERT( node ); TIXMLASSERT(node->_document == this ); if (node->_parent) { node->_parent->DeleteChild( node ); } else { // Isn't in the tree. // Use the parent delete. // Also, we need to mark it tracked: we 'know' // it was never used. node->_memPool->SetTracked(); // Call the static XMLNode version: XMLNode::DeleteNode(node); } } XMLError XMLDocument::LoadFile( const char* filename ) { if ( !filename ) { TIXMLASSERT( false ); SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); return _errorID; } Clear(); FILE* fp = callfopen( filename, "rb" ); if ( !fp ) { SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ); return _errorID; } LoadFile( fp ); fclose( fp ); return _errorID; } XMLError XMLDocument::LoadFile( FILE* fp ) { Clear(); TIXML_FSEEK( fp, 0, SEEK_SET ); if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } TIXML_FSEEK( fp, 0, SEEK_END ); unsigned long long filelength; { const long long fileLengthSigned = TIXML_FTELL( fp ); TIXML_FSEEK( fp, 0, SEEK_SET ); if ( fileLengthSigned == -1L ) { SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } TIXMLASSERT( fileLengthSigned >= 0 ); filelength = static_cast(fileLengthSigned); } const size_t maxSizeT = static_cast(-1); // We'll do the comparison as an unsigned long long, because that's guaranteed to be at // least 8 bytes, even on a 32-bit platform. if ( filelength >= static_cast(maxSizeT) ) { // Cannot handle files which won't fit in buffer together with null terminator SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } if ( filelength == 0 ) { SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return _errorID; } const size_t size = static_cast(filelength); TIXMLASSERT( _charBuffer == 0 ); _charBuffer = new char[size+1]; const size_t read = fread( _charBuffer, 1, size, fp ); if ( read != size ) { SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } _charBuffer[size] = 0; Parse(); return _errorID; } XMLError XMLDocument::SaveFile( const char* filename, bool compact ) { if ( !filename ) { TIXMLASSERT( false ); SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); return _errorID; } FILE* fp = callfopen( filename, "w" ); if ( !fp ) { SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ); return _errorID; } SaveFile(fp, compact); fclose( fp ); return _errorID; } XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) { // Clear any error from the last save, otherwise it will get reported // for *this* call. ClearError(); XMLPrinter stream( fp, compact ); Print( &stream ); return _errorID; } XMLError XMLDocument::Parse( const char* p, size_t len ) { Clear(); if ( len == 0 || !p || !*p ) { SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return _errorID; } if ( len == static_cast(-1) ) { len = strlen( p ); } TIXMLASSERT( _charBuffer == 0 ); _charBuffer = new char[ len+1 ]; memcpy( _charBuffer, p, len ); _charBuffer[len] = 0; Parse(); if ( Error() ) { // clean up now essentially dangling memory. // and the parse fail can put objects in the // pools that are dead and inaccessible. DeleteChildren(); _elementPool.Clear(); _attributePool.Clear(); _textPool.Clear(); _commentPool.Clear(); } return _errorID; } void XMLDocument::Print( XMLPrinter* streamer ) const { if ( streamer ) { Accept( streamer ); } else { XMLPrinter stdoutStreamer( stdout ); Accept( &stdoutStreamer ); } } void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... ) { TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); _errorID = error; _errorLineNum = lineNum; _errorStr.Reset(); const size_t BUFFER_SIZE = 1000; char* buffer = new char[BUFFER_SIZE]; TIXMLASSERT(sizeof(error) <= sizeof(int)); TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum); if (format) { size_t len = strlen(buffer); TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": "); len = strlen(buffer); va_list va; va_start(va, format); TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va); va_end(va); } _errorStr.SetStr(buffer); delete[] buffer; } /*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID) { TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT ); const char* errorName = _errorNames[errorID]; TIXMLASSERT( errorName && errorName[0] ); return errorName; } const char* XMLDocument::ErrorStr() const { return _errorStr.Empty() ? "" : _errorStr.GetStr(); } void XMLDocument::PrintError() const { printf("%s\n", ErrorStr()); } const char* XMLDocument::ErrorName() const { return ErrorIDToName(_errorID); } void XMLDocument::Parse() { TIXMLASSERT( NoChildren() ); // Clear() must have been called previously TIXMLASSERT( _charBuffer ); _parseCurLineNum = 1; _parseLineNum = 1; char* p = _charBuffer; p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); if ( !*p ) { SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return; } ParseDeep(p, 0, &_parseCurLineNum ); } void XMLDocument::PushDepth() { _parsingDepth++; if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) { SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." ); } } void XMLDocument::PopDepth() { TIXMLASSERT(_parsingDepth > 0); --_parsingDepth; } XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : _elementJustOpened( false ), _stack(), _firstElement( true ), _fp( file ), _depth( depth ), _textDepth( -1 ), _processEntities( true ), _compactMode( compact ), _buffer() { for( int i=0; i(entityValue); TIXMLASSERT( flagIndex < ENTITY_RANGE ); _entityFlag[flagIndex] = true; } _restrictedEntityFlag[static_cast('&')] = true; _restrictedEntityFlag[static_cast('<')] = true; _restrictedEntityFlag[static_cast('>')] = true; // not required, but consistency is nice _buffer.Push( 0 ); } void XMLPrinter::Print( const char* format, ... ) { va_list va; va_start( va, format ); if ( _fp ) { vfprintf( _fp, format, va ); } else { const int len = TIXML_VSCPRINTF( format, va ); // Close out and re-start the va-args va_end( va ); TIXMLASSERT( len >= 0 ); va_start( va, format ); TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. TIXML_VSNPRINTF( p, len+1, format, va ); } va_end( va ); } void XMLPrinter::Write( const char* data, size_t size ) { if ( _fp ) { fwrite ( data , sizeof(char), size, _fp); } else { char* p = _buffer.PushArr( static_cast(size) ) - 1; // back up over the null terminator. memcpy( p, data, size ); p[size] = 0; } } void XMLPrinter::Putc( char ch ) { if ( _fp ) { fputc ( ch, _fp); } else { char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator. p[0] = ch; p[1] = 0; } } void XMLPrinter::PrintSpace( int depth ) { for( int i=0; i 0 && *q < ENTITY_RANGE ) { // Check for entities. If one is found, flush // the stream up until the entity, write the // entity, and keep looking. if ( flag[static_cast(*q)] ) { while ( p < q ) { const size_t delta = q - p; const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast(delta); Write( p, toPrint ); p += toPrint; } bool entityPatternPrinted = false; for( int i=0; i(delta); Write( p, toPrint ); } } else { Write( p ); } } void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) { if ( writeBOM ) { static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; Write( reinterpret_cast< const char* >( bom ) ); } if ( writeDec ) { PushDeclaration( "xml version=\"1.0\"" ); } } void XMLPrinter::PrepareForNewNode( bool compactMode ) { SealElementIfJustOpened(); if ( compactMode ) { return; } if ( _firstElement ) { PrintSpace (_depth); } else if ( _textDepth < 0) { Putc( '\n' ); PrintSpace( _depth ); } _firstElement = false; } void XMLPrinter::OpenElement( const char* name, bool compactMode ) { PrepareForNewNode( compactMode ); _stack.Push( name ); Write ( "<" ); Write ( name ); _elementJustOpened = true; ++_depth; } void XMLPrinter::PushAttribute( const char* name, const char* value ) { TIXMLASSERT( _elementJustOpened ); Putc ( ' ' ); Write( name ); Write( "=\"" ); PrintString( value, false ); Putc ( '\"' ); } void XMLPrinter::PushAttribute( const char* name, int v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); PushAttribute( name, buf ); } void XMLPrinter::PushAttribute( const char* name, unsigned v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); PushAttribute( name, buf ); } void XMLPrinter::PushAttribute(const char* name, int64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); PushAttribute(name, buf); } void XMLPrinter::PushAttribute(const char* name, uint64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); PushAttribute(name, buf); } void XMLPrinter::PushAttribute( const char* name, bool v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); PushAttribute( name, buf ); } void XMLPrinter::PushAttribute( const char* name, double v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); PushAttribute( name, buf ); } void XMLPrinter::CloseElement( bool compactMode ) { --_depth; const char* name = _stack.Pop(); if ( _elementJustOpened ) { Write( "/>" ); } else { if ( _textDepth < 0 && !compactMode) { Putc( '\n' ); PrintSpace( _depth ); } Write ( "" ); } if ( _textDepth == _depth ) { _textDepth = -1; } if ( _depth == 0 && !compactMode) { Putc( '\n' ); } _elementJustOpened = false; } void XMLPrinter::SealElementIfJustOpened() { if ( !_elementJustOpened ) { return; } _elementJustOpened = false; Putc( '>' ); } void XMLPrinter::PushText( const char* text, bool cdata ) { _textDepth = _depth-1; SealElementIfJustOpened(); if ( cdata ) { Write( "" ); } else { PrintString( text, true ); } } void XMLPrinter::PushText( int64_t value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushText( uint64_t value ) { char buf[BUF_SIZE]; XMLUtil::ToStr(value, buf, BUF_SIZE); PushText(buf, false); } void XMLPrinter::PushText( int value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushText( unsigned value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushText( bool value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushText( float value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushText( double value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushComment( const char* comment ) { PrepareForNewNode( _compactMode ); Write( "" ); } void XMLPrinter::PushDeclaration( const char* value ) { PrepareForNewNode( _compactMode ); Write( "" ); } void XMLPrinter::PushUnknown( const char* value ) { PrepareForNewNode( _compactMode ); Write( "' ); } bool XMLPrinter::VisitEnter( const XMLDocument& doc ) { _processEntities = doc.ProcessEntities(); if ( doc.HasBOM() ) { PushHeader( true, false ); } return true; } bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) { const XMLElement* parentElem = 0; if ( element.Parent() ) { parentElem = element.Parent()->ToElement(); } const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; OpenElement( element.Name(), compactMode ); while ( attribute ) { PushAttribute( attribute->Name(), attribute->Value() ); attribute = attribute->Next(); } return true; } bool XMLPrinter::VisitExit( const XMLElement& element ) { CloseElement( CompactMode(element) ); return true; } bool XMLPrinter::Visit( const XMLText& text ) { PushText( text.Value(), text.CData() ); return true; } bool XMLPrinter::Visit( const XMLComment& comment ) { PushComment( comment.Value() ); return true; } bool XMLPrinter::Visit( const XMLDeclaration& declaration ) { PushDeclaration( declaration.Value() ); return true; } bool XMLPrinter::Visit( const XMLUnknown& unknown ) { PushUnknown( unknown.Value() ); return true; } } // namespace tinyxml2 ================================================ FILE: TrafficMonitor/tinyxml2/tinyxml2.h ================================================ /* Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef TINYXML2_INCLUDED #define TINYXML2_INCLUDED #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) # include # include # include # include # include # if defined(__PS3__) # include # endif #else # include # include # include # include # include #endif #include /* TODO: intern strings instead of allocation. */ /* gcc: g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe Formatting, Artistic Style: AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h */ #if defined( _DEBUG ) || defined (__DEBUG__) # ifndef TINYXML2_DEBUG # define TINYXML2_DEBUG # endif #endif #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4251) #endif #ifdef _WIN32 # ifdef TINYXML2_EXPORT # define TINYXML2_LIB __declspec(dllexport) # elif defined(TINYXML2_IMPORT) # define TINYXML2_LIB __declspec(dllimport) # else # define TINYXML2_LIB # endif #elif __GNUC__ >= 4 # define TINYXML2_LIB __attribute__((visibility("default"))) #else # define TINYXML2_LIB #endif #if defined(TINYXML2_DEBUG) # if defined(_MSC_VER) # // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like # define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } # elif defined (ANDROID_NDK) # include # define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } # else # include # define TIXMLASSERT assert # endif #else # define TIXMLASSERT( x ) {} #endif /* Versioning, past 1.0.14: http://semver.org/ */ static const int TIXML2_MAJOR_VERSION = 8; static const int TIXML2_MINOR_VERSION = 0; static const int TIXML2_PATCH_VERSION = 0; #define TINYXML2_MAJOR_VERSION 8 #define TINYXML2_MINOR_VERSION 0 #define TINYXML2_PATCH_VERSION 0 // A fixed element depth limit is problematic. There needs to be a // limit to avoid a stack overflow. However, that limit varies per // system, and the capacity of the stack. On the other hand, it's a trivial // attack that can result from ill, malicious, or even correctly formed XML, // so there needs to be a limit in place. static const int TINYXML2_MAX_ELEMENT_DEPTH = 100; namespace tinyxml2 { class XMLDocument; class XMLElement; class XMLAttribute; class XMLComment; class XMLText; class XMLDeclaration; class XMLUnknown; class XMLPrinter; /* A class that wraps strings. Normally stores the start and end pointers into the XML file itself, and will apply normalization and entity translation if actually read. Can also store (and memory manage) a traditional char[] Isn't clear why TINYXML2_LIB is needed; but seems to fix #719 */ class TINYXML2_LIB StrPair { public: enum { NEEDS_ENTITY_PROCESSING = 0x01, NEEDS_NEWLINE_NORMALIZATION = 0x02, NEEDS_WHITESPACE_COLLAPSING = 0x04, TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, ATTRIBUTE_NAME = 0, ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, COMMENT = NEEDS_NEWLINE_NORMALIZATION }; StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} ~StrPair(); void Set( char* start, char* end, int flags ) { TIXMLASSERT( start ); TIXMLASSERT( end ); Reset(); _start = start; _end = end; _flags = flags | NEEDS_FLUSH; } const char* GetStr(); bool Empty() const { return _start == _end; } void SetInternedStr( const char* str ) { Reset(); _start = const_cast(str); } void SetStr( const char* str, int flags=0 ); char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr ); char* ParseName( char* in ); void TransferTo( StrPair* other ); void Reset(); private: void CollapseWhitespace(); enum { NEEDS_FLUSH = 0x100, NEEDS_DELETE = 0x200 }; int _flags; char* _start; char* _end; StrPair( const StrPair& other ); // not supported void operator=( const StrPair& other ); // not supported, use TransferTo() }; /* A dynamic array of Plain Old Data. Doesn't support constructors, etc. Has a small initial memory pool, so that low or no usage will not cause a call to new/delete */ template class DynArray { public: DynArray() : _mem( _pool ), _allocated( INITIAL_SIZE ), _size( 0 ) { } ~DynArray() { if ( _mem != _pool ) { delete [] _mem; } } void Clear() { _size = 0; } void Push( T t ) { TIXMLASSERT( _size < INT_MAX ); EnsureCapacity( _size+1 ); _mem[_size] = t; ++_size; } T* PushArr( int count ) { TIXMLASSERT( count >= 0 ); TIXMLASSERT( _size <= INT_MAX - count ); EnsureCapacity( _size+count ); T* ret = &_mem[_size]; _size += count; return ret; } T Pop() { TIXMLASSERT( _size > 0 ); --_size; return _mem[_size]; } void PopArr( int count ) { TIXMLASSERT( _size >= count ); _size -= count; } bool Empty() const { return _size == 0; } T& operator[](int i) { TIXMLASSERT( i>= 0 && i < _size ); return _mem[i]; } const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < _size ); return _mem[i]; } const T& PeekTop() const { TIXMLASSERT( _size > 0 ); return _mem[ _size - 1]; } int Size() const { TIXMLASSERT( _size >= 0 ); return _size; } int Capacity() const { TIXMLASSERT( _allocated >= INITIAL_SIZE ); return _allocated; } void SwapRemove(int i) { TIXMLASSERT(i >= 0 && i < _size); TIXMLASSERT(_size > 0); _mem[i] = _mem[_size - 1]; --_size; } const T* Mem() const { TIXMLASSERT( _mem ); return _mem; } T* Mem() { TIXMLASSERT( _mem ); return _mem; } private: DynArray( const DynArray& ); // not supported void operator=( const DynArray& ); // not supported void EnsureCapacity( int cap ) { TIXMLASSERT( cap > 0 ); if ( cap > _allocated ) { TIXMLASSERT( cap <= INT_MAX / 2 ); const int newAllocated = cap * 2; T* newMem = new T[newAllocated]; TIXMLASSERT( newAllocated >= _size ); memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs if ( _mem != _pool ) { delete [] _mem; } _mem = newMem; _allocated = newAllocated; } } T* _mem; T _pool[INITIAL_SIZE]; int _allocated; // objects allocated int _size; // number objects in use }; /* Parent virtual class of a pool for fast allocation and deallocation of objects. */ class MemPool { public: MemPool() {} virtual ~MemPool() {} virtual int ItemSize() const = 0; virtual void* Alloc() = 0; virtual void Free( void* ) = 0; virtual void SetTracked() = 0; }; /* Template child class to create pools of the correct type. */ template< int ITEM_SIZE > class MemPoolT : public MemPool { public: MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} ~MemPoolT() { MemPoolT< ITEM_SIZE >::Clear(); } void Clear() { // Delete the blocks. while( !_blockPtrs.Empty()) { Block* lastBlock = _blockPtrs.Pop(); delete lastBlock; } _root = 0; _currentAllocs = 0; _nAllocs = 0; _maxAllocs = 0; _nUntracked = 0; } virtual int ItemSize() const { return ITEM_SIZE; } int CurrentAllocs() const { return _currentAllocs; } virtual void* Alloc() { if ( !_root ) { // Need a new block. Block* block = new Block(); _blockPtrs.Push( block ); Item* blockItems = block->items; for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { blockItems[i].next = &(blockItems[i + 1]); } blockItems[ITEMS_PER_BLOCK - 1].next = 0; _root = blockItems; } Item* const result = _root; TIXMLASSERT( result != 0 ); _root = _root->next; ++_currentAllocs; if ( _currentAllocs > _maxAllocs ) { _maxAllocs = _currentAllocs; } ++_nAllocs; ++_nUntracked; return result; } virtual void Free( void* mem ) { if ( !mem ) { return; } --_currentAllocs; Item* item = static_cast( mem ); #ifdef TINYXML2_DEBUG memset( item, 0xfe, sizeof( *item ) ); #endif item->next = _root; _root = item; } void Trace( const char* name ) { printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs, ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); } void SetTracked() { --_nUntracked; } int Untracked() const { return _nUntracked; } // This number is perf sensitive. 4k seems like a good tradeoff on my machine. // The test file is large, 170k. // Release: VS2010 gcc(no opt) // 1k: 4000 // 2k: 4000 // 4k: 3900 21000 // 16k: 5200 // 32k: 4300 // 64k: 4000 21000 // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK // in private part if ITEMS_PER_BLOCK is private enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE }; private: MemPoolT( const MemPoolT& ); // not supported void operator=( const MemPoolT& ); // not supported union Item { Item* next; char itemData[ITEM_SIZE]; }; struct Block { Item items[ITEMS_PER_BLOCK]; }; DynArray< Block*, 10 > _blockPtrs; Item* _root; int _currentAllocs; int _nAllocs; int _maxAllocs; int _nUntracked; }; /** Implements the interface to the "Visitor pattern" (see the Accept() method.) If you call the Accept() method, it requires being passed a XMLVisitor class to handle callbacks. For nodes that contain other nodes (Document, Element) you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs are simply called with Visit(). If you return 'true' from a Visit method, recursive parsing will continue. If you return false, no children of this node or its siblings will be visited. All flavors of Visit methods have a default implementation that returns 'true' (continue visiting). You need to only override methods that are interesting to you. Generally Accept() is called on the XMLDocument, although all nodes support visiting. You should never change the document from a callback. @sa XMLNode::Accept() */ class TINYXML2_LIB XMLVisitor { public: virtual ~XMLVisitor() {} /// Visit a document. virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; } /// Visit a document. virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; } /// Visit an element. virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; } /// Visit an element. virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; } /// Visit a declaration. virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; } /// Visit a text node. virtual bool Visit( const XMLText& /*text*/ ) { return true; } /// Visit a comment node. virtual bool Visit( const XMLComment& /*comment*/ ) { return true; } /// Visit an unknown node. virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; } }; // WARNING: must match XMLDocument::_errorNames[] enum XMLError { XML_SUCCESS = 0, XML_NO_ATTRIBUTE, XML_WRONG_ATTRIBUTE_TYPE, XML_ERROR_FILE_NOT_FOUND, XML_ERROR_FILE_COULD_NOT_BE_OPENED, XML_ERROR_FILE_READ_ERROR, XML_ERROR_PARSING_ELEMENT, XML_ERROR_PARSING_ATTRIBUTE, XML_ERROR_PARSING_TEXT, XML_ERROR_PARSING_CDATA, XML_ERROR_PARSING_COMMENT, XML_ERROR_PARSING_DECLARATION, XML_ERROR_PARSING_UNKNOWN, XML_ERROR_EMPTY_DOCUMENT, XML_ERROR_MISMATCHED_ELEMENT, XML_ERROR_PARSING, XML_CAN_NOT_CONVERT_TEXT, XML_NO_TEXT_NODE, XML_ELEMENT_DEPTH_EXCEEDED, XML_ERROR_COUNT }; /* Utility functionality. */ class TINYXML2_LIB XMLUtil { public: static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) { TIXMLASSERT( p ); while( IsWhiteSpace(*p) ) { if (curLineNumPtr && *p == '\n') { ++(*curLineNumPtr); } ++p; } TIXMLASSERT( p ); return p; } static char* SkipWhiteSpace( char* const p, int* curLineNumPtr ) { return const_cast( SkipWhiteSpace( const_cast(p), curLineNumPtr ) ); } // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't // correct, but simple, and usually works. static bool IsWhiteSpace( char p ) { return !IsUTF8Continuation(p) && isspace( static_cast(p) ); } inline static bool IsNameStartChar( unsigned char ch ) { if ( ch >= 128 ) { // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() return true; } if ( isalpha( ch ) ) { return true; } return ch == ':' || ch == '_'; } inline static bool IsNameChar( unsigned char ch ) { return IsNameStartChar( ch ) || isdigit( ch ) || ch == '.' || ch == '-'; } inline static bool IsPrefixHex( const char* p) { p = SkipWhiteSpace(p, 0); return p && *p == '0' && ( *(p + 1) == 'x' || *(p + 1) == 'X'); } inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { if ( p == q ) { return true; } TIXMLASSERT( p ); TIXMLASSERT( q ); TIXMLASSERT( nChar >= 0 ); return strncmp( p, q, nChar ) == 0; } inline static bool IsUTF8Continuation( const char p ) { return ( p & 0x80 ) != 0; } static const char* ReadBOM( const char* p, bool* hasBOM ); // p is the starting location, // the UTF-8 value of the entity will be placed in value, and length filled in. static const char* GetCharacterRef( const char* p, char* value, int* length ); static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); // converts primitive types to strings static void ToStr( int v, char* buffer, int bufferSize ); static void ToStr( unsigned v, char* buffer, int bufferSize ); static void ToStr( bool v, char* buffer, int bufferSize ); static void ToStr( float v, char* buffer, int bufferSize ); static void ToStr( double v, char* buffer, int bufferSize ); static void ToStr(int64_t v, char* buffer, int bufferSize); static void ToStr(uint64_t v, char* buffer, int bufferSize); // converts strings to primitive types static bool ToInt( const char* str, int* value ); static bool ToUnsigned( const char* str, unsigned* value ); static bool ToBool( const char* str, bool* value ); static bool ToFloat( const char* str, float* value ); static bool ToDouble( const char* str, double* value ); static bool ToInt64(const char* str, int64_t* value); static bool ToUnsigned64(const char* str, uint64_t* value); // Changes what is serialized for a boolean value. // Default to "true" and "false". Shouldn't be changed // unless you have a special testing or compatibility need. // Be careful: static, global, & not thread safe. // Be sure to set static const memory as parameters. static void SetBoolSerialization(const char* writeTrue, const char* writeFalse); private: static const char* writeBoolTrue; static const char* writeBoolFalse; }; /** XMLNode is a base class for every object that is in the XML Document Object Model (DOM), except XMLAttributes. Nodes have siblings, a parent, and children which can be navigated. A node is always in a XMLDocument. The type of a XMLNode can be queried, and it can be cast to its more defined type. A XMLDocument allocates memory for all its Nodes. When the XMLDocument gets deleted, all its Nodes will also be deleted. @verbatim A Document can contain: Element (container or leaf) Comment (leaf) Unknown (leaf) Declaration( leaf ) An Element can contain: Element (container or leaf) Text (leaf) Attributes (not on tree) Comment (leaf) Unknown (leaf) @endverbatim */ class TINYXML2_LIB XMLNode { friend class XMLDocument; friend class XMLElement; public: /// Get the XMLDocument that owns this XMLNode. const XMLDocument* GetDocument() const { TIXMLASSERT( _document ); return _document; } /// Get the XMLDocument that owns this XMLNode. XMLDocument* GetDocument() { TIXMLASSERT( _document ); return _document; } /// Safely cast to an Element, or null. virtual XMLElement* ToElement() { return 0; } /// Safely cast to Text, or null. virtual XMLText* ToText() { return 0; } /// Safely cast to a Comment, or null. virtual XMLComment* ToComment() { return 0; } /// Safely cast to a Document, or null. virtual XMLDocument* ToDocument() { return 0; } /// Safely cast to a Declaration, or null. virtual XMLDeclaration* ToDeclaration() { return 0; } /// Safely cast to an Unknown, or null. virtual XMLUnknown* ToUnknown() { return 0; } virtual const XMLElement* ToElement() const { return 0; } virtual const XMLText* ToText() const { return 0; } virtual const XMLComment* ToComment() const { return 0; } virtual const XMLDocument* ToDocument() const { return 0; } virtual const XMLDeclaration* ToDeclaration() const { return 0; } virtual const XMLUnknown* ToUnknown() const { return 0; } /** The meaning of 'value' changes for the specific type. @verbatim Document: empty (NULL is returned, not an empty string) Element: name of the element Comment: the comment text Unknown: the tag contents Text: the text string @endverbatim */ const char* Value() const; /** Set the Value of an XML node. @sa Value() */ void SetValue( const char* val, bool staticMem=false ); /// Gets the line number the node is in, if the document was parsed from a file. int GetLineNum() const { return _parseLineNum; } /// Get the parent of this node on the DOM. const XMLNode* Parent() const { return _parent; } XMLNode* Parent() { return _parent; } /// Returns true if this node has no children. bool NoChildren() const { return !_firstChild; } /// Get the first child node, or null if none exists. const XMLNode* FirstChild() const { return _firstChild; } XMLNode* FirstChild() { return _firstChild; } /** Get the first child element, or optionally the first child element with the specified name. */ const XMLElement* FirstChildElement( const char* name = 0 ) const; XMLElement* FirstChildElement( const char* name = 0 ) { return const_cast(const_cast(this)->FirstChildElement( name )); } /// Get the last child node, or null if none exists. const XMLNode* LastChild() const { return _lastChild; } XMLNode* LastChild() { return _lastChild; } /** Get the last child element or optionally the last child element with the specified name. */ const XMLElement* LastChildElement( const char* name = 0 ) const; XMLElement* LastChildElement( const char* name = 0 ) { return const_cast(const_cast(this)->LastChildElement(name) ); } /// Get the previous (left) sibling node of this node. const XMLNode* PreviousSibling() const { return _prev; } XMLNode* PreviousSibling() { return _prev; } /// Get the previous (left) sibling element of this node, with an optionally supplied name. const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; XMLElement* PreviousSiblingElement( const char* name = 0 ) { return const_cast(const_cast(this)->PreviousSiblingElement( name ) ); } /// Get the next (right) sibling node of this node. const XMLNode* NextSibling() const { return _next; } XMLNode* NextSibling() { return _next; } /// Get the next (right) sibling element of this node, with an optionally supplied name. const XMLElement* NextSiblingElement( const char* name = 0 ) const; XMLElement* NextSiblingElement( const char* name = 0 ) { return const_cast(const_cast(this)->NextSiblingElement( name ) ); } /** Add a child node as the last (right) child. If the child node is already part of the document, it is moved from its old location to the new location. Returns the addThis argument or 0 if the node does not belong to the same document. */ XMLNode* InsertEndChild( XMLNode* addThis ); XMLNode* LinkEndChild( XMLNode* addThis ) { return InsertEndChild( addThis ); } /** Add a child node as the first (left) child. If the child node is already part of the document, it is moved from its old location to the new location. Returns the addThis argument or 0 if the node does not belong to the same document. */ XMLNode* InsertFirstChild( XMLNode* addThis ); /** Add a node after the specified child node. If the child node is already part of the document, it is moved from its old location to the new location. Returns the addThis argument or 0 if the afterThis node is not a child of this node, or if the node does not belong to the same document. */ XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); /** Delete all the children of this node. */ void DeleteChildren(); /** Delete a child of this node. */ void DeleteChild( XMLNode* node ); /** Make a copy of this node, but not its children. You may pass in a Document pointer that will be the owner of the new Node. If the 'document' is null, then the node returned will be allocated from the current Document. (this->GetDocument()) Note: if called on a XMLDocument, this will return null. */ virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; /** Make a copy of this node and all its children. If the 'target' is null, then the nodes will be allocated in the current document. If 'target' is specified, the memory will be allocated is the specified XMLDocument. NOTE: This is probably not the correct tool to copy a document, since XMLDocuments can have multiple top level XMLNodes. You probably want to use XMLDocument::DeepCopy() */ XMLNode* DeepClone( XMLDocument* target ) const; /** Test if 2 nodes are the same, but don't test children. The 2 nodes do not need to be in the same Document. Note: if called on a XMLDocument, this will return false. */ virtual bool ShallowEqual( const XMLNode* compare ) const = 0; /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the XMLVisitor interface. This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this interface versus any other.) The interface has been based on ideas from: - http://www.saxproject.org/ - http://c2.com/cgi/wiki?HierarchicalVisitorPattern Which are both good references for "visiting". An example of using Accept(): @verbatim XMLPrinter printer; tinyxmlDoc.Accept( &printer ); const char* xmlcstr = printer.CStr(); @endverbatim */ virtual bool Accept( XMLVisitor* visitor ) const = 0; /** Set user data into the XMLNode. TinyXML-2 in no way processes or interprets user data. It is initially 0. */ void SetUserData(void* userData) { _userData = userData; } /** Get user data set into the XMLNode. TinyXML-2 in no way processes or interprets user data. It is initially 0. */ void* GetUserData() const { return _userData; } protected: explicit XMLNode( XMLDocument* ); virtual ~XMLNode(); virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); XMLDocument* _document; XMLNode* _parent; mutable StrPair _value; int _parseLineNum; XMLNode* _firstChild; XMLNode* _lastChild; XMLNode* _prev; XMLNode* _next; void* _userData; private: MemPool* _memPool; void Unlink( XMLNode* child ); static void DeleteNode( XMLNode* node ); void InsertChildPreamble( XMLNode* insertThis ) const; const XMLElement* ToElementWithName( const char* name ) const; XMLNode( const XMLNode& ); // not supported XMLNode& operator=( const XMLNode& ); // not supported }; /** XML text. Note that a text node can have child element nodes, for example: @verbatim This is bold @endverbatim A text node can have 2 ways to output the next. "normal" output and CDATA. It will default to the mode it was parsed from the XML file and you generally want to leave it alone, but you can change the output mode with SetCData() and query it with CData(). */ class TINYXML2_LIB XMLText : public XMLNode { friend class XMLDocument; public: virtual bool Accept( XMLVisitor* visitor ) const; virtual XMLText* ToText() { return this; } virtual const XMLText* ToText() const { return this; } /// Declare whether this should be CDATA or standard text. void SetCData( bool isCData ) { _isCData = isCData; } /// Returns true if this is a CDATA text element. bool CData() const { return _isCData; } virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual bool ShallowEqual( const XMLNode* compare ) const; protected: explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} virtual ~XMLText() {} char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); private: bool _isCData; XMLText( const XMLText& ); // not supported XMLText& operator=( const XMLText& ); // not supported }; /** An XML Comment. */ class TINYXML2_LIB XMLComment : public XMLNode { friend class XMLDocument; public: virtual XMLComment* ToComment() { return this; } virtual const XMLComment* ToComment() const { return this; } virtual bool Accept( XMLVisitor* visitor ) const; virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual bool ShallowEqual( const XMLNode* compare ) const; protected: explicit XMLComment( XMLDocument* doc ); virtual ~XMLComment(); char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); private: XMLComment( const XMLComment& ); // not supported XMLComment& operator=( const XMLComment& ); // not supported }; /** In correct XML the declaration is the first entry in the file. @verbatim @endverbatim TinyXML-2 will happily read or write files without a declaration, however. The text of the declaration isn't interpreted. It is parsed and written as a string. */ class TINYXML2_LIB XMLDeclaration : public XMLNode { friend class XMLDocument; public: virtual XMLDeclaration* ToDeclaration() { return this; } virtual const XMLDeclaration* ToDeclaration() const { return this; } virtual bool Accept( XMLVisitor* visitor ) const; virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual bool ShallowEqual( const XMLNode* compare ) const; protected: explicit XMLDeclaration( XMLDocument* doc ); virtual ~XMLDeclaration(); char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); private: XMLDeclaration( const XMLDeclaration& ); // not supported XMLDeclaration& operator=( const XMLDeclaration& ); // not supported }; /** Any tag that TinyXML-2 doesn't recognize is saved as an unknown. It is a tag of text, but should not be modified. It will be written back to the XML, unchanged, when the file is saved. DTD tags get thrown into XMLUnknowns. */ class TINYXML2_LIB XMLUnknown : public XMLNode { friend class XMLDocument; public: virtual XMLUnknown* ToUnknown() { return this; } virtual const XMLUnknown* ToUnknown() const { return this; } virtual bool Accept( XMLVisitor* visitor ) const; virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual bool ShallowEqual( const XMLNode* compare ) const; protected: explicit XMLUnknown( XMLDocument* doc ); virtual ~XMLUnknown(); char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); private: XMLUnknown( const XMLUnknown& ); // not supported XMLUnknown& operator=( const XMLUnknown& ); // not supported }; /** An attribute is a name-value pair. Elements have an arbitrary number of attributes, each with a unique name. @note The attributes are not XMLNodes. You may only query the Next() attribute in a list. */ class TINYXML2_LIB XMLAttribute { friend class XMLElement; public: /// The name of the attribute. const char* Name() const; /// The value of the attribute. const char* Value() const; /// Gets the line number the attribute is in, if the document was parsed from a file. int GetLineNum() const { return _parseLineNum; } /// The next attribute in the list. const XMLAttribute* Next() const { return _next; } /** IntValue interprets the attribute as an integer, and returns the value. If the value isn't an integer, 0 will be returned. There is no error checking; use QueryIntValue() if you need error checking. */ int IntValue() const { int i = 0; QueryIntValue(&i); return i; } int64_t Int64Value() const { int64_t i = 0; QueryInt64Value(&i); return i; } uint64_t Unsigned64Value() const { uint64_t i = 0; QueryUnsigned64Value(&i); return i; } /// Query as an unsigned integer. See IntValue() unsigned UnsignedValue() const { unsigned i=0; QueryUnsignedValue( &i ); return i; } /// Query as a boolean. See IntValue() bool BoolValue() const { bool b=false; QueryBoolValue( &b ); return b; } /// Query as a double. See IntValue() double DoubleValue() const { double d=0; QueryDoubleValue( &d ); return d; } /// Query as a float. See IntValue() float FloatValue() const { float f=0; QueryFloatValue( &f ); return f; } /** QueryIntValue interprets the attribute as an integer, and returns the value in the provided parameter. The function will return XML_SUCCESS on success, and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. */ XMLError QueryIntValue( int* value ) const; /// See QueryIntValue XMLError QueryUnsignedValue( unsigned int* value ) const; /// See QueryIntValue XMLError QueryInt64Value(int64_t* value) const; /// See QueryIntValue XMLError QueryUnsigned64Value(uint64_t* value) const; /// See QueryIntValue XMLError QueryBoolValue( bool* value ) const; /// See QueryIntValue XMLError QueryDoubleValue( double* value ) const; /// See QueryIntValue XMLError QueryFloatValue( float* value ) const; /// Set the attribute to a string value. void SetAttribute( const char* value ); /// Set the attribute to value. void SetAttribute( int value ); /// Set the attribute to value. void SetAttribute( unsigned value ); /// Set the attribute to value. void SetAttribute(int64_t value); /// Set the attribute to value. void SetAttribute(uint64_t value); /// Set the attribute to value. void SetAttribute( bool value ); /// Set the attribute to value. void SetAttribute( double value ); /// Set the attribute to value. void SetAttribute( float value ); private: enum { BUF_SIZE = 200 }; XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {} virtual ~XMLAttribute() {} XMLAttribute( const XMLAttribute& ); // not supported void operator=( const XMLAttribute& ); // not supported void SetName( const char* name ); char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr ); mutable StrPair _name; mutable StrPair _value; int _parseLineNum; XMLAttribute* _next; MemPool* _memPool; }; /** The element is a container class. It has a value, the element name, and can contain other elements, text, comments, and unknowns. Elements also contain an arbitrary number of attributes. */ class TINYXML2_LIB XMLElement : public XMLNode { friend class XMLDocument; public: /// Get the name of an element (which is the Value() of the node.) const char* Name() const { return Value(); } /// Set the name of the element. void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); } virtual XMLElement* ToElement() { return this; } virtual const XMLElement* ToElement() const { return this; } virtual bool Accept( XMLVisitor* visitor ) const; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. For example: @verbatim const char* value = ele->Attribute( "foo" ); @endverbatim The 'value' parameter is normally null. However, if specified, the attribute will only be returned if the 'name' and 'value' match. This allow you to write code: @verbatim if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); @endverbatim rather than: @verbatim if ( ele->Attribute( "foo" ) ) { if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); } @endverbatim */ const char* Attribute( const char* name, const char* value=0 ) const; /** Given an attribute name, IntAttribute() returns the value of the attribute interpreted as an integer. The default value will be returned if the attribute isn't present, or if there is an error. (For a method with error checking, see QueryIntAttribute()). */ int IntAttribute(const char* name, int defaultValue = 0) const; /// See IntAttribute() unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const; /// See IntAttribute() int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; /// See IntAttribute() uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const; /// See IntAttribute() bool BoolAttribute(const char* name, bool defaultValue = false) const; /// See IntAttribute() double DoubleAttribute(const char* name, double defaultValue = 0) const; /// See IntAttribute() float FloatAttribute(const char* name, float defaultValue = 0) const; /** Given an attribute name, QueryIntAttribute() returns XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion can't be performed, or XML_NO_ATTRIBUTE if the attribute doesn't exist. If successful, the result of the conversion will be written to 'value'. If not successful, nothing will be written to 'value'. This allows you to provide default value: @verbatim int value = 10; QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 @endverbatim */ XMLError QueryIntAttribute( const char* name, int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return XML_NO_ATTRIBUTE; } return a->QueryIntValue( value ); } /// See QueryIntAttribute() XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return XML_NO_ATTRIBUTE; } return a->QueryUnsignedValue( value ); } /// See QueryIntAttribute() XMLError QueryInt64Attribute(const char* name, int64_t* value) const { const XMLAttribute* a = FindAttribute(name); if (!a) { return XML_NO_ATTRIBUTE; } return a->QueryInt64Value(value); } /// See QueryIntAttribute() XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const { const XMLAttribute* a = FindAttribute(name); if(!a) { return XML_NO_ATTRIBUTE; } return a->QueryUnsigned64Value(value); } /// See QueryIntAttribute() XMLError QueryBoolAttribute( const char* name, bool* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return XML_NO_ATTRIBUTE; } return a->QueryBoolValue( value ); } /// See QueryIntAttribute() XMLError QueryDoubleAttribute( const char* name, double* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return XML_NO_ATTRIBUTE; } return a->QueryDoubleValue( value ); } /// See QueryIntAttribute() XMLError QueryFloatAttribute( const char* name, float* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return XML_NO_ATTRIBUTE; } return a->QueryFloatValue( value ); } /// See QueryIntAttribute() XMLError QueryStringAttribute(const char* name, const char** value) const { const XMLAttribute* a = FindAttribute(name); if (!a) { return XML_NO_ATTRIBUTE; } *value = a->Value(); return XML_SUCCESS; } /** Given an attribute name, QueryAttribute() returns XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion can't be performed, or XML_NO_ATTRIBUTE if the attribute doesn't exist. It is overloaded for the primitive types, and is a generally more convenient replacement of QueryIntAttribute() and related functions. If successful, the result of the conversion will be written to 'value'. If not successful, nothing will be written to 'value'. This allows you to provide default value: @verbatim int value = 10; QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 @endverbatim */ XMLError QueryAttribute( const char* name, int* value ) const { return QueryIntAttribute( name, value ); } XMLError QueryAttribute( const char* name, unsigned int* value ) const { return QueryUnsignedAttribute( name, value ); } XMLError QueryAttribute(const char* name, int64_t* value) const { return QueryInt64Attribute(name, value); } XMLError QueryAttribute(const char* name, uint64_t* value) const { return QueryUnsigned64Attribute(name, value); } XMLError QueryAttribute( const char* name, bool* value ) const { return QueryBoolAttribute( name, value ); } XMLError QueryAttribute( const char* name, double* value ) const { return QueryDoubleAttribute( name, value ); } XMLError QueryAttribute( const char* name, float* value ) const { return QueryFloatAttribute( name, value ); } XMLError QueryAttribute(const char* name, const char** value) const { return QueryStringAttribute(name, value); } /// Sets the named attribute to value. void SetAttribute( const char* name, const char* value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /// Sets the named attribute to value. void SetAttribute( const char* name, int value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /// Sets the named attribute to value. void SetAttribute( const char* name, unsigned value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /// Sets the named attribute to value. void SetAttribute(const char* name, int64_t value) { XMLAttribute* a = FindOrCreateAttribute(name); a->SetAttribute(value); } /// Sets the named attribute to value. void SetAttribute(const char* name, uint64_t value) { XMLAttribute* a = FindOrCreateAttribute(name); a->SetAttribute(value); } /// Sets the named attribute to value. void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /// Sets the named attribute to value. void SetAttribute( const char* name, double value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /// Sets the named attribute to value. void SetAttribute( const char* name, float value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /** Delete an attribute. */ void DeleteAttribute( const char* name ); /// Return the first attribute in the list. const XMLAttribute* FirstAttribute() const { return _rootAttribute; } /// Query a specific attribute in the list. const XMLAttribute* FindAttribute( const char* name ) const; /** Convenience function for easy access to the text inside an element. Although easy and concise, GetText() is limited compared to getting the XMLText child and accessing it directly. If the first child of 'this' is a XMLText, the GetText() returns the character string of the Text node, else null is returned. This is a convenient method for getting the text of simple contained text: @verbatim This is text const char* str = fooElement->GetText(); @endverbatim 'str' will be a pointer to "This is text". Note that this function can be misleading. If the element foo was created from this XML: @verbatim This is text @endverbatim then the value of str would be null. The first child node isn't a text node, it is another element. From this XML: @verbatim This is text @endverbatim GetText() will return "This is ". */ const char* GetText() const; /** Convenience function for easy access to the text inside an element. Although easy and concise, SetText() is limited compared to creating an XMLText child and mutating it directly. If the first child of 'this' is a XMLText, SetText() sets its value to the given string, otherwise it will create a first child that is an XMLText. This is a convenient method for setting the text of simple contained text: @verbatim This is text fooElement->SetText( "Hullaballoo!" ); Hullaballoo! @endverbatim Note that this function can be misleading. If the element foo was created from this XML: @verbatim This is text @endverbatim then it will not change "This is text", but rather prefix it with a text element: @verbatim Hullaballoo!This is text @endverbatim For this XML: @verbatim @endverbatim SetText() will generate @verbatim Hullaballoo! @endverbatim */ void SetText( const char* inText ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( int value ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( unsigned value ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText(int64_t value); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText(uint64_t value); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( bool value ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( double value ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( float value ); /** Convenience method to query the value of a child text node. This is probably best shown by example. Given you have a document is this form: @verbatim 1 1.4 @endverbatim The QueryIntText() and similar functions provide a safe and easier way to get to the "value" of x and y. @verbatim int x = 0; float y = 0; // types of x and y are contrived for example const XMLElement* xElement = pointElement->FirstChildElement( "x" ); const XMLElement* yElement = pointElement->FirstChildElement( "y" ); xElement->QueryIntText( &x ); yElement->QueryFloatText( &y ); @endverbatim @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. */ XMLError QueryIntText( int* ival ) const; /// See QueryIntText() XMLError QueryUnsignedText( unsigned* uval ) const; /// See QueryIntText() XMLError QueryInt64Text(int64_t* uval) const; /// See QueryIntText() XMLError QueryUnsigned64Text(uint64_t* uval) const; /// See QueryIntText() XMLError QueryBoolText( bool* bval ) const; /// See QueryIntText() XMLError QueryDoubleText( double* dval ) const; /// See QueryIntText() XMLError QueryFloatText( float* fval ) const; int IntText(int defaultValue = 0) const; /// See QueryIntText() unsigned UnsignedText(unsigned defaultValue = 0) const; /// See QueryIntText() int64_t Int64Text(int64_t defaultValue = 0) const; /// See QueryIntText() uint64_t Unsigned64Text(uint64_t defaultValue = 0) const; /// See QueryIntText() bool BoolText(bool defaultValue = false) const; /// See QueryIntText() double DoubleText(double defaultValue = 0) const; /// See QueryIntText() float FloatText(float defaultValue = 0) const; /** Convenience method to create a new XMLElement and add it as last (right) child of this node. Returns the created and inserted element. */ XMLElement* InsertNewChildElement(const char* name); /// See InsertNewChildElement() XMLComment* InsertNewComment(const char* comment); /// See InsertNewChildElement() XMLText* InsertNewText(const char* text); /// See InsertNewChildElement() XMLDeclaration* InsertNewDeclaration(const char* text); /// See InsertNewChildElement() XMLUnknown* InsertNewUnknown(const char* text); // internal: enum ElementClosingType { OPEN, // CLOSED, // CLOSING // }; ElementClosingType ClosingType() const { return _closingType; } virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual bool ShallowEqual( const XMLNode* compare ) const; protected: char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); private: XMLElement( XMLDocument* doc ); virtual ~XMLElement(); XMLElement( const XMLElement& ); // not supported void operator=( const XMLElement& ); // not supported XMLAttribute* FindOrCreateAttribute( const char* name ); char* ParseAttributes( char* p, int* curLineNumPtr ); static void DeleteAttribute( XMLAttribute* attribute ); XMLAttribute* CreateAttribute(); enum { BUF_SIZE = 200 }; ElementClosingType _closingType; // The attribute list is ordered; there is no 'lastAttribute' // because the list needs to be scanned for dupes before adding // a new attribute. XMLAttribute* _rootAttribute; }; enum Whitespace { PRESERVE_WHITESPACE, COLLAPSE_WHITESPACE }; /** A Document binds together all the functionality. It can be saved, loaded, and printed to the screen. All Nodes are connected and allocated to a Document. If the Document is deleted, all its Nodes are also deleted. */ class TINYXML2_LIB XMLDocument : public XMLNode { friend class XMLElement; // Gives access to SetError and Push/PopDepth, but over-access for everything else. // Wishing C++ had "internal" scope. friend class XMLNode; friend class XMLText; friend class XMLComment; friend class XMLDeclaration; friend class XMLUnknown; public: /// constructor XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); ~XMLDocument(); virtual XMLDocument* ToDocument() { TIXMLASSERT( this == _document ); return this; } virtual const XMLDocument* ToDocument() const { TIXMLASSERT( this == _document ); return this; } /** Parse an XML file from a character string. Returns XML_SUCCESS (0) on success, or an errorID. You may optionally pass in the 'nBytes', which is the number of bytes which will be parsed. If not specified, TinyXML-2 will assume 'xml' points to a null terminated string. */ XMLError Parse( const char* xml, size_t nBytes=static_cast(-1) ); /** Load an XML file from disk. Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError LoadFile( const char* filename ); /** Load an XML file from disk. You are responsible for providing and closing the FILE*. NOTE: The file should be opened as binary ("rb") not text in order for TinyXML-2 to correctly do newline normalization. Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError LoadFile( FILE* ); /** Save the XML file to disk. Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError SaveFile( const char* filename, bool compact = false ); /** Save the XML file to disk. You are responsible for providing and closing the FILE*. Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError SaveFile( FILE* fp, bool compact = false ); bool ProcessEntities() const { return _processEntities; } Whitespace WhitespaceMode() const { return _whitespaceMode; } /** Returns true if this document has a leading Byte Order Mark of UTF8. */ bool HasBOM() const { return _writeBOM; } /** Sets whether to write the BOM when writing the file. */ void SetBOM( bool useBOM ) { _writeBOM = useBOM; } /** Return the root element of DOM. Equivalent to FirstChildElement(). To get the first node, use FirstChild(). */ XMLElement* RootElement() { return FirstChildElement(); } const XMLElement* RootElement() const { return FirstChildElement(); } /** Print the Document. If the Printer is not provided, it will print to stdout. If you provide Printer, this can print to a file: @verbatim XMLPrinter printer( fp ); doc.Print( &printer ); @endverbatim Or you can use a printer to print to memory: @verbatim XMLPrinter printer; doc.Print( &printer ); // printer.CStr() has a const char* to the XML @endverbatim */ void Print( XMLPrinter* streamer=0 ) const; virtual bool Accept( XMLVisitor* visitor ) const; /** Create a new Element associated with this Document. The memory for the Element is managed by the Document. */ XMLElement* NewElement( const char* name ); /** Create a new Comment associated with this Document. The memory for the Comment is managed by the Document. */ XMLComment* NewComment( const char* comment ); /** Create a new Text associated with this Document. The memory for the Text is managed by the Document. */ XMLText* NewText( const char* text ); /** Create a new Declaration associated with this Document. The memory for the object is managed by the Document. If the 'text' param is null, the standard declaration is used.: @verbatim @endverbatim */ XMLDeclaration* NewDeclaration( const char* text=0 ); /** Create a new Unknown associated with this Document. The memory for the object is managed by the Document. */ XMLUnknown* NewUnknown( const char* text ); /** Delete a node associated with this document. It will be unlinked from the DOM. */ void DeleteNode( XMLNode* node ); void ClearError() { SetError(XML_SUCCESS, 0, 0); } /// Return true if there was an error parsing the document. bool Error() const { return _errorID != XML_SUCCESS; } /// Return the errorID. XMLError ErrorID() const { return _errorID; } const char* ErrorName() const; static const char* ErrorIDToName(XMLError errorID); /** Returns a "long form" error description. A hopefully helpful diagnostic with location, line number, and/or additional info. */ const char* ErrorStr() const; /// A (trivial) utility function that prints the ErrorStr() to stdout. void PrintError() const; /// Return the line where the error occurred, or zero if unknown. int ErrorLineNum() const { return _errorLineNum; } /// Clear the document, resetting it to the initial state. void Clear(); /** Copies this document to a target document. The target will be completely cleared before the copy. If you want to copy a sub-tree, see XMLNode::DeepClone(). NOTE: that the 'target' must be non-null. */ void DeepCopy(XMLDocument* target) const; // internal char* Identify( char* p, XMLNode** node ); // internal void MarkInUse(const XMLNode* const); virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { return 0; } virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { return false; } private: XMLDocument( const XMLDocument& ); // not supported void operator=( const XMLDocument& ); // not supported bool _writeBOM; bool _processEntities; XMLError _errorID; Whitespace _whitespaceMode; mutable StrPair _errorStr; int _errorLineNum; char* _charBuffer; int _parseCurLineNum; int _parsingDepth; // Memory tracking does add some overhead. // However, the code assumes that you don't // have a bunch of unlinked nodes around. // Therefore it takes less memory to track // in the document vs. a linked list in the XMLNode, // and the performance is the same. DynArray _unlinked; MemPoolT< sizeof(XMLElement) > _elementPool; MemPoolT< sizeof(XMLAttribute) > _attributePool; MemPoolT< sizeof(XMLText) > _textPool; MemPoolT< sizeof(XMLComment) > _commentPool; static const char* _errorNames[XML_ERROR_COUNT]; void Parse(); void SetError( XMLError error, int lineNum, const char* format, ... ); // Something of an obvious security hole, once it was discovered. // Either an ill-formed XML or an excessively deep one can overflow // the stack. Track stack depth, and error out if needed. class DepthTracker { public: explicit DepthTracker(XMLDocument * document) { this->_document = document; document->PushDepth(); } ~DepthTracker() { _document->PopDepth(); } private: XMLDocument * _document; }; void PushDepth(); void PopDepth(); template NodeType* CreateUnlinkedNode( MemPoolT& pool ); }; template inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT& pool ) { TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() ); NodeType* returnNode = new (pool.Alloc()) NodeType( this ); TIXMLASSERT( returnNode ); returnNode->_memPool = &pool; _unlinked.Push(returnNode); return returnNode; } /** A XMLHandle is a class that wraps a node pointer with null checks; this is an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 DOM structure. It is a separate utility class. Take an example: @verbatim @endverbatim Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very easy to write a *lot* of code that looks like: @verbatim XMLElement* root = document.FirstChildElement( "Document" ); if ( root ) { XMLElement* element = root->FirstChildElement( "Element" ); if ( element ) { XMLElement* child = element->FirstChildElement( "Child" ); if ( child ) { XMLElement* child2 = child->NextSiblingElement( "Child" ); if ( child2 ) { // Finally do something useful. @endverbatim And that doesn't even cover "else" cases. XMLHandle addresses the verbosity of such code. A XMLHandle checks for null pointers so it is perfectly safe and correct to use: @verbatim XMLHandle docHandle( &document ); XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); if ( child2 ) { // do something useful @endverbatim Which is MUCH more concise and useful. It is also safe to copy handles - internally they are nothing more than node pointers. @verbatim XMLHandle handleCopy = handle; @endverbatim See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. */ class TINYXML2_LIB XMLHandle { public: /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. explicit XMLHandle( XMLNode* node ) : _node( node ) { } /// Create a handle from a node. explicit XMLHandle( XMLNode& node ) : _node( &node ) { } /// Copy constructor XMLHandle( const XMLHandle& ref ) : _node( ref._node ) { } /// Assignment XMLHandle& operator=( const XMLHandle& ref ) { _node = ref._node; return *this; } /// Get the first child of this handle. XMLHandle FirstChild() { return XMLHandle( _node ? _node->FirstChild() : 0 ); } /// Get the first child element of this handle. XMLHandle FirstChildElement( const char* name = 0 ) { return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); } /// Get the last child of this handle. XMLHandle LastChild() { return XMLHandle( _node ? _node->LastChild() : 0 ); } /// Get the last child element of this handle. XMLHandle LastChildElement( const char* name = 0 ) { return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); } /// Get the previous sibling of this handle. XMLHandle PreviousSibling() { return XMLHandle( _node ? _node->PreviousSibling() : 0 ); } /// Get the previous sibling element of this handle. XMLHandle PreviousSiblingElement( const char* name = 0 ) { return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); } /// Get the next sibling of this handle. XMLHandle NextSibling() { return XMLHandle( _node ? _node->NextSibling() : 0 ); } /// Get the next sibling element of this handle. XMLHandle NextSiblingElement( const char* name = 0 ) { return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); } /// Safe cast to XMLNode. This can return null. XMLNode* ToNode() { return _node; } /// Safe cast to XMLElement. This can return null. XMLElement* ToElement() { return ( _node ? _node->ToElement() : 0 ); } /// Safe cast to XMLText. This can return null. XMLText* ToText() { return ( _node ? _node->ToText() : 0 ); } /// Safe cast to XMLUnknown. This can return null. XMLUnknown* ToUnknown() { return ( _node ? _node->ToUnknown() : 0 ); } /// Safe cast to XMLDeclaration. This can return null. XMLDeclaration* ToDeclaration() { return ( _node ? _node->ToDeclaration() : 0 ); } private: XMLNode* _node; }; /** A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the same in all regards, except for the 'const' qualifiers. See XMLHandle for API. */ class TINYXML2_LIB XMLConstHandle { public: explicit XMLConstHandle( const XMLNode* node ) : _node( node ) { } explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) { } XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) { } XMLConstHandle& operator=( const XMLConstHandle& ref ) { _node = ref._node; return *this; } const XMLConstHandle FirstChild() const { return XMLConstHandle( _node ? _node->FirstChild() : 0 ); } const XMLConstHandle FirstChildElement( const char* name = 0 ) const { return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); } const XMLConstHandle LastChild() const { return XMLConstHandle( _node ? _node->LastChild() : 0 ); } const XMLConstHandle LastChildElement( const char* name = 0 ) const { return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); } const XMLConstHandle PreviousSibling() const { return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); } const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); } const XMLConstHandle NextSibling() const { return XMLConstHandle( _node ? _node->NextSibling() : 0 ); } const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); } const XMLNode* ToNode() const { return _node; } const XMLElement* ToElement() const { return ( _node ? _node->ToElement() : 0 ); } const XMLText* ToText() const { return ( _node ? _node->ToText() : 0 ); } const XMLUnknown* ToUnknown() const { return ( _node ? _node->ToUnknown() : 0 ); } const XMLDeclaration* ToDeclaration() const { return ( _node ? _node->ToDeclaration() : 0 ); } private: const XMLNode* _node; }; /** Printing functionality. The XMLPrinter gives you more options than the XMLDocument::Print() method. It can: -# Print to memory. -# Print to a file you provide. -# Print XML without a XMLDocument. Print to Memory @verbatim XMLPrinter printer; doc.Print( &printer ); SomeFunction( printer.CStr() ); @endverbatim Print to a File You provide the file pointer. @verbatim XMLPrinter printer( fp ); doc.Print( &printer ); @endverbatim Print without a XMLDocument When loading, an XML parser is very useful. However, sometimes when saving, it just gets in the way. The code is often set up for streaming, and constructing the DOM is just overhead. The Printer supports the streaming case. The following code prints out a trivially simple XML file without ever creating an XML document. @verbatim XMLPrinter printer( fp ); printer.OpenElement( "foo" ); printer.PushAttribute( "foo", "bar" ); printer.CloseElement(); @endverbatim */ class TINYXML2_LIB XMLPrinter : public XMLVisitor { public: /** Construct the printer. If the FILE* is specified, this will print to the FILE. Else it will print to memory, and the result is available in CStr(). If 'compact' is set to true, then output is created with only required whitespace and newlines. */ XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); virtual ~XMLPrinter() {} /** If streaming, write the BOM and declaration. */ void PushHeader( bool writeBOM, bool writeDeclaration ); /** If streaming, start writing an element. The element must be closed with CloseElement() */ void OpenElement( const char* name, bool compactMode=false ); /// If streaming, add an attribute to an open element. void PushAttribute( const char* name, const char* value ); void PushAttribute( const char* name, int value ); void PushAttribute( const char* name, unsigned value ); void PushAttribute( const char* name, int64_t value ); void PushAttribute( const char* name, uint64_t value ); void PushAttribute( const char* name, bool value ); void PushAttribute( const char* name, double value ); /// If streaming, close the Element. virtual void CloseElement( bool compactMode=false ); /// Add a text node. void PushText( const char* text, bool cdata=false ); /// Add a text node from an integer. void PushText( int value ); /// Add a text node from an unsigned. void PushText( unsigned value ); /// Add a text node from a signed 64bit integer. void PushText( int64_t value ); /// Add a text node from an unsigned 64bit integer. void PushText( uint64_t value ); /// Add a text node from a bool. void PushText( bool value ); /// Add a text node from a float. void PushText( float value ); /// Add a text node from a double. void PushText( double value ); /// Add a comment void PushComment( const char* comment ); void PushDeclaration( const char* value ); void PushUnknown( const char* value ); virtual bool VisitEnter( const XMLDocument& /*doc*/ ); virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; } virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); virtual bool VisitExit( const XMLElement& element ); virtual bool Visit( const XMLText& text ); virtual bool Visit( const XMLComment& comment ); virtual bool Visit( const XMLDeclaration& declaration ); virtual bool Visit( const XMLUnknown& unknown ); /** If in print to memory mode, return a pointer to the XML file in memory. */ const char* CStr() const { return _buffer.Mem(); } /** If in print to memory mode, return the size of the XML file in memory. (Note the size returned includes the terminating null.) */ int CStrSize() const { return _buffer.Size(); } /** If in print to memory mode, reset the buffer to the beginning. */ void ClearBuffer( bool resetToFirstElement = true ) { _buffer.Clear(); _buffer.Push(0); _firstElement = resetToFirstElement; } protected: virtual bool CompactMode( const XMLElement& ) { return _compactMode; } /** Prints out the space before an element. You may override to change the space and tabs used. A PrintSpace() override should call Print(). */ virtual void PrintSpace( int depth ); virtual void Print( const char* format, ... ); virtual void Write( const char* data, size_t size ); virtual void Putc( char ch ); inline void Write(const char* data) { Write(data, strlen(data)); } void SealElementIfJustOpened(); bool _elementJustOpened; DynArray< const char*, 10 > _stack; private: /** Prepares to write a new node. This includes sealing an element that was just opened, and writing any whitespace necessary if not in compact mode. */ void PrepareForNewNode( bool compactMode ); void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. bool _firstElement; FILE* _fp; int _depth; int _textDepth; bool _processEntities; bool _compactMode; enum { ENTITY_RANGE = 64, BUF_SIZE = 200 }; bool _entityFlag[ENTITY_RANGE]; bool _restrictedEntityFlag[ENTITY_RANGE]; DynArray< char, 20 > _buffer; // Prohibit cloning, intentionally not implemented XMLPrinter( const XMLPrinter& ); XMLPrinter& operator=( const XMLPrinter& ); }; } // tinyxml2 #if defined(_MSC_VER) # pragma warning(pop) #endif #endif // TINYXML2_INCLUDED ================================================ FILE: TrafficMonitor.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31515.178 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TrafficMonitor", "TrafficMonitor\TrafficMonitor.vcxproj", "{09483BED-B1E9-4827-8120-A18302C84AA8}" ProjectSection(ProjectDependencies) = postProject {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26} = {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenHardwareMonitorApi", "OpenHardwareMonitorApi\OpenHardwareMonitorApi.vcxproj", "{C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PluginDemo", "PluginDemo\PluginDemo.vcxproj", "{D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug (lite)|x64 = Debug (lite)|x64 Debug (lite)|x86 = Debug (lite)|x86 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release (lite)|x64 = Release (lite)|x64 Release (lite)|x86 = Release (lite)|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {09483BED-B1E9-4827-8120-A18302C84AA8}.Debug (lite)|x64.ActiveCfg = Debug (lite)|x64 {09483BED-B1E9-4827-8120-A18302C84AA8}.Debug (lite)|x64.Build.0 = Debug (lite)|x64 {09483BED-B1E9-4827-8120-A18302C84AA8}.Debug (lite)|x86.ActiveCfg = Debug (lite)|Win32 {09483BED-B1E9-4827-8120-A18302C84AA8}.Debug (lite)|x86.Build.0 = Debug (lite)|Win32 {09483BED-B1E9-4827-8120-A18302C84AA8}.Debug|x64.ActiveCfg = Debug|x64 {09483BED-B1E9-4827-8120-A18302C84AA8}.Debug|x64.Build.0 = Debug|x64 {09483BED-B1E9-4827-8120-A18302C84AA8}.Debug|x86.ActiveCfg = Debug|Win32 {09483BED-B1E9-4827-8120-A18302C84AA8}.Debug|x86.Build.0 = Debug|Win32 {09483BED-B1E9-4827-8120-A18302C84AA8}.Release (lite)|x64.ActiveCfg = Release (lite)|x64 {09483BED-B1E9-4827-8120-A18302C84AA8}.Release (lite)|x64.Build.0 = Release (lite)|x64 {09483BED-B1E9-4827-8120-A18302C84AA8}.Release (lite)|x86.ActiveCfg = Release (lite)|Win32 {09483BED-B1E9-4827-8120-A18302C84AA8}.Release (lite)|x86.Build.0 = Release (lite)|Win32 {09483BED-B1E9-4827-8120-A18302C84AA8}.Release|x64.ActiveCfg = Release|x64 {09483BED-B1E9-4827-8120-A18302C84AA8}.Release|x64.Build.0 = Release|x64 {09483BED-B1E9-4827-8120-A18302C84AA8}.Release|x86.ActiveCfg = Release|Win32 {09483BED-B1E9-4827-8120-A18302C84AA8}.Release|x86.Build.0 = Release|Win32 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Debug (lite)|x64.ActiveCfg = Debug|x64 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Debug (lite)|x86.ActiveCfg = Debug|Win32 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Debug|x64.ActiveCfg = Debug|x64 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Debug|x64.Build.0 = Debug|x64 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Debug|x86.ActiveCfg = Debug|Win32 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Debug|x86.Build.0 = Debug|Win32 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Release (lite)|x64.ActiveCfg = Release|x64 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Release (lite)|x86.ActiveCfg = Release|Win32 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Release|x64.ActiveCfg = Release|x64 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Release|x64.Build.0 = Release|x64 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Release|x86.ActiveCfg = Release|Win32 {C0A42F4A-ABB3-4575-B4D5-CEDD8379AC26}.Release|x86.Build.0 = Release|Win32 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Debug (lite)|x64.ActiveCfg = Debug|x64 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Debug (lite)|x64.Build.0 = Debug|x64 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Debug (lite)|x86.ActiveCfg = Debug|Win32 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Debug (lite)|x86.Build.0 = Debug|Win32 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Debug|x64.ActiveCfg = Debug|x64 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Debug|x64.Build.0 = Debug|x64 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Debug|x86.ActiveCfg = Debug|Win32 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Debug|x86.Build.0 = Debug|Win32 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Release (lite)|x64.ActiveCfg = Release|x64 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Release (lite)|x64.Build.0 = Release|x64 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Release (lite)|x86.ActiveCfg = Release|Win32 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Release (lite)|x86.Build.0 = Release|Win32 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Release|x64.ActiveCfg = Release|x64 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Release|x64.Build.0 = Release|x64 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Release|x86.ActiveCfg = Release|Win32 {D1CA3ECC-DC32-445A-B734-C4DB08D4BA34}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2DE8C8C3-89CE-4313-978B-DADEC5CB141A} EndGlobalSection EndGlobal ================================================ FILE: UpdateLog/update_log.md ================================================ **简体中文 | [繁體中文](./update_log_zh-tw.md) | [English](./update_log_en-us.md)** # TrafficMonitor 更新日志 ## V1.83 (2022/02/03) * 修正当已经存在一个开机自启动的任务计划时,无法设置开机自启动的问题, * 新增当已经存在TrafficMonitor进程时启动程序,弹出“程序已经在运行”对话框。 * 鼠标提示中新增插件信息的显示。 * 修正插件被禁用后仍然会被加载的问题。 * 任务栏中的插件项目支持自由排序。 * 选项设置中新增可以选择要在“网络连接列表”中显示的网络的功能。 * 新增显示总网速的功能。 * 新增在任务栏中显示网速占用图的功能。 * 修正硬件监控中有多个名称相同的硬盘时只能显示一个硬盘的问题。 * 优化任务栏窗口横向滚动图的显示效果。 * 任务栏窗口右键菜单中的“显示设置”由菜单改为对话框形式。 * “选择网络连接”菜单中添加“刷新网络连接列表”命令。 * 修正几处导致程序崩溃的问题。 ## V1.82 (2021/12/12) * 新增插件系统,可以通过插件在任务栏窗口和主窗口显示更多自定义内容。 * 任务栏右键菜单中增加“任务管理器”命令。 * 选项设置中新增“应用”按钮。 * 历史流量统计中增加周视图。 * 新增任务栏项目间距的设置。 * 修正Windows11深色模式下任务栏右键菜单无法弹出的问题。 * 修正Windows11下使用StartAllBack等软件将任务栏恢复为Windows10样式时,任务栏窗口无法显示的问题。 ## V1.81 (2021/07/27) * 修正1.80版本以来的一些崩溃的问题 * 任务栏窗口显示项目支持自定义排序 * 任务栏窗口中显示的项目数量为奇数时,最后一个项目垂直排列,以节省任务栏空间 * 新增显示硬盘利用率的功能 * 将右键菜单中的一些设置添加到选项设置界面中 * 新增主窗口对多显示器的支持,在不勾选“允许超出屏幕边界”的情况下也能移动到其他显示器了 ## V1.80.3 (2021/05/29) * 修正无法显示CPU温度的问题 * 新增可以选择监控指定CPU核心的温度的功能 * 修正一处导致程序崩溃的问题 ## V1.80.2 (2021/05/22) * 修正几处导致程序崩溃的问题 * 获取温度信息改用LibreHardwareMonitor * 新增可选择要监控哪块硬盘的温度的功能 * 新增可选择要监控哪些硬件的功能 * 修正程序退出时LibreHardwareMonitorLib.sys文件没有解除占用的问题 ## V1.80.1 (2021/05/17) * 修正无法获取AMD显卡温度的问题 * 修正自动切换为浅色模式颜色预设时程序崩溃的问题 * 修正无法获取11代Intel处理器温度的问题 * 修正设置开机自启动无效的问题 ## V1.80 (2021/05/15) * 新增CPU、显卡、硬盘和主板温度监控的功能 * 新增显卡利用率监控的功能 * 修正历史流量统计数值溢出导致统计数值不正确的问题 * 修正屏幕分辨率更改后主窗口位置不正确的问题 * 修正系统DPI更改后,主窗口和任务栏窗口界面元素的大小不会随DPI变化的问题 * 新增任务栏窗口自由指定显示项目的功能 * 新增xml格式的主窗口皮肤,支持温度显示 * 修正使用触屏设备时,选项设置中的子窗口无法使用触屏滚动的问题 * 将检查更新的处理放到后台线程中,以解决检查更新时程序长时间没有响应的问题 * 修正任务栏窗口中按Alt+F4后程序异常的问题 * 新增对每秒4GB以上网速的支持 * 新增可选择更新源为Gitee,以解决中国大陆地区有时无法访问GitHub导致程序无法更新的问题 * 新增内存显示方式设置 * 修正当前监控的网卡被关闭或禁用,再次启动后无法自动选择之前监控的网卡的问题 * 开机自启动采用任务计划实现,以解决有时开机自启动无效的问题 * 修正一些崩溃的问题 * 其他细节方面的改进 ## V1.79.1 (2020/08/05) * 修正注册表句柄泄漏的问题。 * 修正当主窗口和任务栏窗口都不显示时,不统计CPU和内存利用率的问题。 ## V1.79 (2020/07/30) * 新增任务栏窗口颜色自动适应Windows10深色/浅色主题的功能。 * 新增通知区图标自动适应Windows10深色/浅色主题的功能。 * 增加CPU获取方式的设置,解决部分用户出现的CPU利用率始终为0的问题。 * 选项设置>任务栏设置中去掉“透明色”的设置,新增“背景色透明”的选项。 * 新增允许任务栏只显示CPU和内存利用率而不显示网速。 * 修正了关机后设置可能会没有保存的问题。 * 历史流量统计-日历视图中增加了每周第一天的设置。 * 历史流量统计-列表视图中增加了按年、月、日、季度统计的功能。 * 可能解决了历史流量数据有小概率丢失的问题。 * 修正Windows10浅色主题时,如果任务栏窗口背景设置为透明,会无法弹出右键菜单的问题。 * 修正流量统计不支持统计超过2TB数据的问题。 * 为菜单项添加了图标。 * 当程序所在目录无法写入时,将数据保存到AppData目录。 * 新增设置监控时间间隔的功能。 ## V1.78 (2020/03/21) * 新增双击主窗口或任务栏窗口打开指定应用程序的功能 * 新增任务栏窗口中显示CPU和内存利用率状态条的功能 * 修正Windows10中CPU利用率和任务管理器不一致的问题 * 新增是否显示鼠标提示的选项 * 新增程序首次启启动时根据Windows10浅色模式设置任务栏颜色的功能 * 任务栏设置中增加预设方案的功能 * 其他细节方面的改进 ## V1.77 (2019/05/01) * 增加任务窗口透明色设置,修正任务栏为白色时任务栏窗口文字颜色无法设置为黑色的问题(在“选项”——“任务栏窗口设置”中设置透明色) * 新增程序崩溃时显示崩溃信息的功能 * 修正显示任务栏窗口的情况下,资源管理器重启时会导致屏幕闪烁的问题 * 新增鼠标指向通知区图标时显示监控信息 * 修正使用蓝牙网络时无法显示网速的问题 * 新增x64的版本 * 其他细节方面的改进 ### 更新说明: 本次更新在一定程度上解决了Win10最新版本中白色任务栏时文字看不清的问题。需要手动在“选项”——“任务栏窗口设置”——“透明色”设置透明色。当透明色不为黑色且和背景色不同时为不透明效果,如果和背景色相同则为透明效果。在Win10白色任务栏中建议如下图所示设置: ![白色任务栏截图](https://user-images.githubusercontent.com/30562462/57004858-36b55300-6c05-11e9-89d8-9911dc99f09c.PNG) ## V1.76 (2018/11/11) * 修正了分辨率更改可能会导致程序崩溃的问题; * 新增配置文件保存位置的选项; * 修正了当分辨率变化时任务栏窗口的垂直位置不正确的问题; * 新增今日上传和下载流量的显示,历史流量统计中增加上传和下载流量的统计; * 其他细节方面的改进。 ## V1.75 (2018/08/11) * 任务栏窗口右键菜单增加“选择网络连接”菜单项 * 写入配置文件时改为使用UTF8编码 * 新增网速单位为B(字节)或b(比特)的设置 * 修正部分电脑中无法获取网速的问题 * 修正部分电脑中会反复产生错误日志的问题 * 皮肤11 UI调整,修正有时文本显示不全的问题 其他细节方面的改进 ## V1.74 (2018/06/17) * 修正两处导致程序崩溃的问题 * 新增:监控所有连接的网速的功能 * 右键菜单“选择网络连接”中显示所有的网络接口,不显示loopback接口 * 新增:任务栏窗口项目可以水平排列 * 新增:繁体中文语言支持 * 其他细节方面的改进。 ## V1.73 (2018/05/13) * 新增:多语言支持,增加英语 * 新增:字体设置支持粗体、斜体、下划线等字体样式 * 新增:历史流量统计中的日历视图 * 修正:当悬浮窗在右下角时,有时程序启动后悬浮窗会往左或往上移动一段距离的问题 * 配置文件转移到C:\Users\用户名\AppData\Roaming\TrafficMonitor目录下,防止由于程序所在目录无法写入数据导致配置文件无法保存的问题 * 新增:网速数据位数设置的选项;修正有时当网速超过10M/s时数据显示的全的问题 ## V1.72 (2018/04/21) * 新增:任务栏窗口数值右对齐的选项 * 新增:每个项目文本颜色单独设置的功能 * 新增:设置鼠标双击动作的功能 * 新增:设置当流量或内存使用率超过一定值时弹出通知的功能 * 新增:获取外网IP地址的功能 * 其他细节方面的改进。 ## V1.71 (2018/04/06) * 优化背景图片的显示效果,解决了由于图片缩放时导致的失真的问题 * 增加不规则形状皮肤的支持 * 增加可以通过皮肤文件设定项目的对齐方式和字体 * 改善了优化通知区图标在125%缩放比时的显示效果 * 一些细节方面的改进。 ## V1.70 (2018/03/30) * 新增:自定义皮肤功能,可以通过皮肤文件更加自由地定义悬浮窗中的每个项目的大小和位置 * “更换皮肤”对话框中预览图可以预览悬浮窗中显示的文本和字体,当预览图过大时会显示滚动条 * “更换皮肤”对话框中增加“皮肤制作教程”和“更多皮肤下载”链接 * 新增允许悬浮窗超出屏幕边界的选项,解决多显示器时无法移动到其他显示器的问题 ## V1.69 (2018/03/17) * 新增单位设置,允许隐藏单位 * 新增:单位设置、网速显示简洁模式可应用到主窗口 * 新增更换通知区图标的功能 * 一些细节方面的改进 * 增加两款皮肤。 ## V1.68 (2018/03/03) * 修正当程序启动时,如果设置了隐藏主窗口,主窗口还是会显示1秒钟再消失的问题 * 修正当窗口为左上角(0,0)时,下次启动时无法记住该位置的问题 * 修正有时在进入选项设置再点击“确定”时,会弹出“注册表项删除失败”提示框的问题 * 新增任务栏窗口网速显示简洁模式(选项——任务栏窗口设置——网速显示简洁模式) ## V1.67 (2018/01/21) * 修正当主窗口和任务栏窗口都不显示CPU和内存利用率时,鼠标提示中的CPU和内存利用率不刷新的问题 * 修正了当任务栏左侧有自定义工具栏或快速启动栏时,任务栏窗口位置不正确的问题 * 新增自动检查更新功能 * 开机自启动功能改为写入注册表实现,去掉右键菜单中的“开机自动运行”项,移至选项设置——常规设置 * 增加任务栏窗口可以放在任务栏的左侧 * 其他细节方面的改进 ## V1.66 (2017/12/31) * 新增鼠标悬浮提示会实时更新 * 优化关于启动时弹出“已经有一个程序正在运行”对话框的处理 * 增加无法嵌入任务栏时自动重试的处理 * 增加任务栏窗口的刷新频率,在一定程度上解决通知区域图标变化时任务栏窗口闪烁的问题 * 历史流量统计对话框中增加图形指示 ## V1.65 (2017/11.16) * 修正了更新Win10秋季创意者更新后,设置了开机启动时会弹出“已经有一个程序正在运行”的对话框的问题 * 增加了选项设置对话框,将字体和字体颜色设置放到了选项设置对话框中,增加了显示文本的设置 * 修正了有时开机启动时会弹出“窗口无法嵌入任务栏”的提示的问题 * 增加程序全屏时隐藏悬浮窗的选项,并修正了全屏视频或游戏时悬浮窗会自己跳出来的问题 * 任务栏窗口的宽度不再固定,而是会根据文本宽度自动调整 * 连接详情对话框中增加右键菜单复制功能 ## V1.64 (2017/07/28) * 任务栏窗口信息显示改成了双缓冲绘图,彻底修正了任务栏窗口显示出现难看的色块的问题 * 当任务栏从桌面底部移动到两旁时,任务栏窗口会实时切换横排和竖排显示 ## V1.63 (2017/07/05) * 增加当无法保存设置时的警告信息 * 优化通知区图标行为,当设置了隐藏主窗口时,双击通知区图标才显示主窗口 * 调整了任务栏窗口显示网速部分的宽度,以修正网速过大时显示不全的问题 * 任务栏窗口右键菜单中增加显示通知区图标选项 * 修正有时设置了去掉通知区图标后再次启动时图标还在的问题 * 如果设置了主窗口总是置顶,每隔5分钟自动执行一次置顶操作,以解决有时窗口没有置顶的问题 ## V1.62 (2017/05/29) * 启动时如果检测到历史流量统计中有重复的日期就将它们合并 * 去掉一些菜单项中不必要的省略号 * 其他细节方面的改进 ## V1.61 (2017/05/19) * 连接详情中增加物理地址、IP地址、子网掩码和默认网关几个项目显示 * 鼠标提示信息合并为一个提示,如果设置为不显示CPU和内存利用率时在提示信息里显示 * 修正了连接详情窗口中的鼠标提示显示在窗口后面的问题 * 修正了主窗口没有置顶时任务栏窗口的鼠标提示在窗口后面的问题 * 修正了切换网络连接后的1秒网速显示为一个很大的值的问题 * 修正了当切换网络连接时统计的流量不正确的问题 ## V1.60 (2017/05/11) * 连接详情界面改为列表显示,增加程序已运行时间项目 * 新增历史流量统计功能,可以记录每一天总共使用的流量 * 关于对话框中增加捐赠功能 * 关于对话框中增加检查更新链接,点击可跳转到百度网盘链接 * 优化了自动选择的处理,在较大程度上解决了有时无法显示网速的问题 * 较大程度上解决了少数情况下设置总是置顶、鼠标穿透时无效的问题 * 新增当鼠标指向主窗口或任务栏窗口对应的项目时,提示今日已使用流量和内存使用详情 * 更换了程序图标和通知区域图标,风格更加简洁 ## V1.54 (2017/04/29) * 修正当设置了隐藏主窗口和显示任务栏窗口时,在任务视图中有一个看不见的窗口的问题 * 修正某些情况下会导致变成灰色的菜单项变回可用状态的问题 * 修正在“自动选择”模式时,当断开WIFI再重新连接后可能会出现无法自动选择有网络的连接的问题 优化:当显示任务栏窗口时,允许隐藏通知区图标。 ## V1.53 (2017/03/07) * 修正选择皮肤时可能会出现顺序错乱的问题 * 优化:ini文件保存选择的皮肤的名称而不是序号,以解决添加或删除皮肤后选择的皮肤不正确的问题 * 修正将焦点设置到任务栏窗口后按回车或ESC键任务栏窗口关闭的问题 * 新增设置字体功能 ## V1.52 (2017/03/04) * 修正当显示任务栏窗口时,打开或关闭通知区图标会导致资源管理器卡住的问题 * 优化:打开任务栏窗口时,窗口中的信息可以立即显示出来 * 新增:允许取消开机自启动,“开机自动运行”菜单项增加复选标志 ## V1.51 (2017/03/02) * 修正重启资源管理器之后任务栏窗口无法正常显示的问题 * 修正重启资源管理器之后通知区图标消失的问题 * 修正任务栏窗口上网速显示字符串过长时字符显示不全的问题 * 修正在特定情况下可能会导致程序停止工作的问题 * 优化:当任务栏在屏幕左侧或右侧时,任务栏窗口的4个项目以竖排显示(必须关闭任务栏窗口再打开才能生效) * “关于”对话框中增加“联系作者”超链接 ## V1.50 (2017/02/25) * 新增更换皮肤功能(点击右键菜单——其他功能——更换皮肤,新增了7套皮肤) * 新增当网络变化时,自动更新“选择网络连接”中的子菜单项 * 新增允许交换上传和下载的位置 ## V1.43 (2017/02/22) * 优化自动选择连接的处理,不选择已断开的连接 * 修正任务栏窗口切换“显示CPU和内容利用率”后,“隐藏主窗口”的复选框消失的问题 * 优化:当任务栏窗口无法嵌入任务栏时(如被安全软件阻止),如果任务栏把窗口覆盖,则窗口自动置顶。 ## V1.42 (2017/02/19) * 优化:任务栏窗口的位置不再总是固定,当任务栏最小化区域宽度变化时自动调整任务栏窗口的位置 * 修正了当把任务放在桌面的左边或右边时任务栏窗口位置不正确的问题 ## V1.41 (2017/02/18) * 新增隐藏主界面功能 * 更改设置时实时保存,解决关机时无法保存设置的问题 * 新增开机自动运行功能,程序会创建快捷方式到开始菜单的启动目录 * 新增在无法嵌入任务栏时强行将窗口移动到正确的位置,并弹出提示信息 ## V1.40 (2017/02/16) * 增加任务栏窗口,作为工具栏样式嵌入任务栏,不再占用屏幕区域 * 增加主悬浮窗文字颜色设置 * 任务栏窗口支持背景颜色和文字颜色设置 ## V1.30 (2017/02/13) * 增加CPU和内存利用率显示。 * 增加鼠标穿透功能,悬浮窗不再影响鼠标操作 ## V1.20 (2017/02/11) * 去掉任务栏图标,增加通知区图标,右击通知区图标可弹出右键菜单 * 右键菜单增加“锁定窗口位置”、“显示通知区域图标”项目 * 增加移动时不允许超过屏幕边界的处理 * 增加程序只允许一个实例运行的处理 * 连接详情中增加自程序启动以来已发送和接收字节数显示,并增加数据以KB、MB或GB为单位的显示 * 修正了当上传速度的字符串太长时可能会导致下载速度显示不全的BUG ## V1.00 (2017/02/10) * 初版发行 ================================================ FILE: UpdateLog/update_log_en-us.md ================================================ **[简体中文](./update_log.md) | [繁體中文](./update_log_zh-tw.md) | English**
# TrafficMonitor Update log ## V1.83 (2022/02/03) * Fixed the problem that when there is already a task plan of auto-run, the auto-run at start up will be failed to set. * Added the "Program is already running" dialog box at the program is started when there is already a TrafficMonitor process running. * Added the plug-in information in the mouse tool tips. * Fixed an issue where plugins could still be loaded if they were disabled. * Added the support of free sorting of plugin items in the taskbar. * Added the function to select the network connections to be displayed in the "Network Connection List" in the option settings. * Added the function of displaying the total network speed. * Added the function of displaying the network speed graph in the taskbar. * Fixed the problem that only one hard disk can be displayed when there are multiple hard disks with the same name in the hardware monitor. * Optimize the display effect of the resource usage graph in plot mode of the taskbar window. * Change the "Display Settings" in the taskbar window context menu from menu to dialog box. * Added "Refresh connection list" command to "Select Network Connections" menu. * Fixed some crashes. ## V1.82 (2021/12/12) * Added a new plug-in system, you can display more customized content in the taskbar window and the main window through the plug-in. * Added the "Task Manager" command to the taskbar window context menu. * Added the "Apply" button to the option settings dialog. * Added weekly view in historical traffic statistics. * Added the setting of task bar item spacing. * Fixed the problem that the taskbar window context menu cannot pop up in the dark mode of Windows 11. * Fixed the problem that the taskbar window could not be displayed when the taskbar was restored to the Windows 10 style using software such as StartAllBack under Windows 11. ## V1.81 (2021/07/27) * Fixed some crashes since version 1.80. * Added the support of custom sorting of the items in the taskbar window. * When the number of items displayed in the taskbar window is odd, the last item is arranged vertically to save space on the taskbar. * Added the function of monitoring the hard disk usage. * Add some settings in the right-click menu to the option settings dialog. * Added the support for multiple monitors of the main window. You can move the main window to other monitors without checking "Allow out of screen boundaries". ## V1.80.3 (2021/05/29) * Fixed the problem that the CPU temperature cannot be displayed * Added the function to select the temperature of specified CPU core to monitor. * Fixed a problem that caused the program crashed. ## V1.80.2 (2021/05/22) * Fixed several issues that cause the program crashed. * Use LibreHardwareMonitor to obtain temperature information. * Added the function to select the temperature of which hard drive to monitor. * Added the function to select the hardware to monitor. * Fix the problem that the LibreHardwareMonitorLib.sys file is not released when the program exits. ## V1.80.1 (2021/05/17) * Fixed the problem that the temperature of AMD GPU could not be obtained. * Fixed the problem that the program crashes when automatically switching to the light mode color preset. * Fixed the problem that the temperature of the 11th generation Intel processor cannot be obtained. * Fixed the problem that the auto-start setting does not work. ## V1.80 (2021/05/15) * Added the function of monitoring the temperature of CPU, GPU, hard disk and main board. * Added the function of monitoring the GPU usage. * Fixed the problem that the historical traffic statistics is not correct caused by the data overflowed. * Fixed the problem that the main window position was incorrect after the screen resolution was changed. * Fixed the problem that the size of the interface elements of the main window and taskbar window would not change after the system DPI was changed. * Added the ability to freely specify display items in the taskbar window. * Added xml format of the main window skin, supporting temperature display. * Fixed the problem that the sub-windows in the option settings cannot be scrolled by the touch screen when using a touch screen device. * Put the processing of checking for updates into a background thread to solve the problem that the program does not respond for a long time when checking for update. * Fix the problem that the program is abnormal after pressing Alt+F4 in the taskbar window. * Added support for net speeds above 4GB per second. * Added the option to set the update source as Gitee to solve the problem that the program cannot be updated sometimes due to the inaccessibility of GitHub in mainland China. * Added setting of memory display mode. * Fix the problem that the currently monitored network connection is closed or disabled, the previously monitored network connection cannot be automatically selected after restarted. * Auto run at boot is realized by Task Scheduler to solve the problem that the auto run at boot dose not work sometimes. * Fix some crashes. * Improvements in other details. ## V1.79.1 (2020/08/05) * Fix the problem of registry handle leak. * Fixed the problem that CPU and memory usage are not counted when the main window and taskbar window are not displayed. ## V1.79 (2020/07/30) * Add the function of automatically adapts to the Windows 10 dark/light theme of the taskbar window color. * Add the function of automatically adapts to the Windows 10 dark/light theme of the notification area icon. * Add the option of CPU usage acquisition method. Fix the problem that the CPU usage may always 0 of some users. * Remove the option of "Transparent color" in "Options"-"Taskbar Window Settings", and add the option of "Background Color Transparent". * Allows only CPU and memory usage displayed in the taskbar window without the net speed. * Fixes an problem that the settings may not be saved after the shutdown. * Add the setting of "the first day of the week" in the "Historical Traffic Statistics"-"Calendar View". * Add the function of displaying history traffic by day, month, quarter and year in the "Historical Traffic Statistics"-"List View". * May fixed the problem of the loss of historical traffic data in small probability. * Fixed the problem that the right-click menu cannot pop up if the taskbar window background is set to transparent in Windows 10 light theme. * Fixed the problem that traffic statistics does not support data exceeding 2TB. * Added icons for menu items. * Save the data to the AppData directory when the program's directory cannot be written. * Add the function of setting the monitoring interval. ## V1.78 (2020/03/21) * Add the function to open the specified application by double-clicking the main window or taskbar window. * Add the function to display the CPU and memory utilization status bar in the taskbar window. * Fix the inconsistence of CPU usage with the task manager in Windows 10. * Added option to show mouse tool tips. * Added the function to set the taskbar color according to Windows 10 light mode when the program is first started. * Added the function of preset schemes in the taskbar settings. * Improvements in other details. ## V1.77 (2019/05/01) * Add the transparent color setting of the task window. Fix the problem that the text color of the taskbar window cannot be set to black when the taskbar is white (Set the transparent color in "Options" - "Taskbar Window Settings"). * Add the function to display crash information when the program crashes. * Fix the problem that the screen will flicker when the Windows Explorer restarts if the taskbar window is displayed. * Display monitoring information when the mouse points to the notification area icon. * Fixed the problem that the network speed could not be displayed when using a Bluetooth network. * Added x64 version. * Improvements in other details. ### Release Notes: This update solves the problem that the text is not clear in the taskbar when the taskbar is white in the latest version of Windows 10. You need to manually set the transparent color in "Options" - "Taskbar Window Settings" - "Transparent Color". It is an opaque effect when the transparent color is not black and is different from the background color, and is transparent if it is the same as the background color. In the Windows 10 white taskbar, it is recommended to set as the following picture: ![白色任务栏截图](https://user-images.githubusercontent.com/30562462/57004858-36b55300-6c05-11e9-89d8-9911dc99f09c.PNG) ## V1.76 (2018/11/11) * Fix the problem that the resolution changes may cause the program crash. * Add the options for the saving location of the configuration files. * Fix the problem that the vertical position of the taskbar window was incorrect when the resolution changed. * Add the display of today’s upload and download traffic. Add the upload and download traffic statics in the history traffic static dialog. * Improvements in other details. ================================================ FILE: UpdateLog/update_log_zh-tw.md ================================================ **[简体中文](./update_log.md) | 繁體中文 | [English](./update_log_en-us.md)**
# TrafficMonitor 更新日誌 ## V1.82 (2021/12/12) * 修正當已經存在一個開機自啟動的任務計劃時,無法設定開機自啟動的問題, * 新增當已經存在TrafficMonitor程序時啟動程式,彈出“程式已經在執行”對話方塊。 * 滑鼠提示中新增外掛資訊的顯示。 * 修正外掛被禁用後仍然會被載入的問題。 * 工作列中的外掛專案支援自由排序。 * 選項設定中新增可以選擇要在“網路連線列表”中顯示的網路的功能。 * 新增顯示總網速的功能。 * 新增在工作列中顯示網速佔用圖的功能。 * 修正硬體監控中有多個名稱相同的硬碟時只能顯示一個硬碟的問題。 * 最佳化工作列視窗橫向滾動圖的顯示效果。 * 工作列視窗右鍵選單中的“顯示設定”由選單改為對話方塊形式。 * “選擇網路連線”選單中新增“重新整理網路連線列表”命令。 * 修正幾處導致程式崩潰的問題。 ## V1.82 (2021/12/12) * 新增外掛系統,可以透過外掛在工作列視窗和主視窗顯示更多自定義內容。 * 工作列右鍵選單中增加“工作管理員”命令。 * 選項設定中新增“應用”按鈕。 * 歷史流量統計中增加周檢視。 * 新增工作列專案間距的設定。 * 修正Windows11深色模式下工作列右鍵選單無法彈出的問題。 * 修正Windows11下使用StartAllBack等軟體將工作列恢復為Windows10樣式時,工作列視窗無法顯示的問題。 ## V1.81 (2021/07/27) * 修正1.80版本以來的一些崩潰的問題 * 工作列視窗顯示專案支援自定義排序 * 工作列視窗中顯示的專案數量為奇數時,最後一個專案垂直排列,以節省工作列空間 * 新增顯示硬碟利用率的功能 * 將右鍵選單中的一些設定新增到選項設定介面中 * 新增主視窗對多顯示器的支援,在不勾選“允許超出螢幕邊界”的情況下也能移動到其他顯示器了 ## V1.80.3 (2021/05/29) * 修正無法顯示CPU溫度的問題 * 新增可以選擇監控指定CPU核心的溫度的功能 * 修正一處導致程式崩潰的問題 ## V1.80.2 (2021/05/22) * 修正幾處導致程式崩潰的問題 * 獲取溫度資訊改用LibreHardwareMonitor * 新增可選擇要監控哪塊硬碟的溫度的功能 * 新增可選擇要監控哪些硬體的功能 * 修正程式退出時LibreHardwareMonitorLib.sys檔案沒有解除佔用的問題 ## V1.80.1 (2021/05/17) * 修正無法獲取AMD顯示卡溫度的問題 * 修正自動切換為淺色模式顏色預設時程式崩潰的問題 * 修正無法獲取11代Intel處理器溫度的問題 * 修正設定開機自啟動無效的問題 ## V1.80 (2021/05/15) * 新增CPU、顯示卡、硬碟和主機板溫度監控的功能 * 新增顯示卡利用率監控的功能 * 修正歷史流量統計數值溢位導致統計數值不正確的問題 * 修正螢幕解析度更改後主視窗位置不正確的問題 * 修正系統DPI更改後,主視窗和工作列視窗介面元素的大小不會隨DPI變化的問題 * 新增工作列視窗自由指定顯示專案的功能 * 新增xml格式的主視窗面板,支援溫度顯示 * 修正使用觸屏裝置時,選項設定中的子視窗無法使用觸屏滾動的問題 * 將檢查更新的處理放到後臺執行緒中,以解決檢查更新時程式長時間沒有響應的問題 * 修正工作列視窗中按Alt+F4後程序異常的問題 * 新增對每秒4GB以上網速的支援 * 新增可選擇更新源為Gitee,以解決中國大陸地區有時無法訪問GitHub導致程式無法更新的問題 * 新增記憶體顯示方式設定 * 修正當前監控的網絡卡被關閉或禁用,再次啟動後無法自動選擇之前監控的網絡卡的問題 * 開機自啟動採用任務計劃實現,以解決有時開機自啟動無效的問題 * 修正一些崩潰的問題 * 其他細節方面的改進 ## V1.79.1 (2020/08/05) * 修正登錄檔控制碼洩漏的問題。 * 修正當主視窗和工作列視窗都不顯示時,不統計CPU和記憶體利用率的問題。 ## V1.79 (2020/07/30) * 新增工作列視窗顏色自動適應Windows10深色/淺色主題的功能。 * 新增通知區圖示自動適應Windows10深色/淺色主題的功能。 * 增加CPU獲取方式的設定,解決部分使用者出現的CPU利用率始終為0的問題。 * 選項設定>工作列設定中去掉「透明色」選項,新增「背景色透明」的選項。 * 新增允許工作列只顯示CPU和記憶體利用量而不顯示網速。 * 修正了關機後設置可能會沒有儲存的問題。 * 歷史流量統計-日曆檢視中增加了每週第一天的設定。 * 歷史流量統計-列表檢視中增加了按年、月、日、季度統計的功能。 * 可能解決了歷史流量資料有小概率丟失的問題。 * 修正Windows10淺色主題時,如果工作列視窗背景設定為透明,會無法彈出右鍵選單的問題。 * 修正流量統計不支援統計超過2TB的問題。 * 為選單項添加了圖示。 * 當程式所在目錄無法寫入時,將資料儲存到AppData目錄。 * 新增設定監視時間間隔的功能。 ## V1.78 (2020/03/21) * 新增按兩下主視窗或工作列視窗開啟指定應用程式的功能 * 新增工作列視窗中顯示CPU和RAM可用狀態條的功能 * 修正 Windows 10 中 CPU 使用量和工作管理員不一致的問題 * 新增是否顯示游標提示的選項 * 新增程式首次啟動時根據 Windows 10 淺色模式設定工作列顏色的功能 * 工作列設定中增加預設方案的功能 * 其他細節方面的改進 ## V1.77 (2019/05/01) * 新增工作列視窗透明色設定,修正工作列為白色時工作列視窗文字顏色無法設定為黑色的問題(在 [選項] —— [工作列視窗設定] 中設定透明色) * 新增程式崩潰時顯示崩潰資訊的功能 * 修正顯示工作列視窗的情况下,檔案總管重新啟動時會導致螢幕畫面閃爍的問題 * 新增滑鼠指向通知區域圖示時顯示監控資訊 * 修正使用藍牙網路時無法顯示網速的問題 * 新增x64的版本 * 其他細節方面的改進 ### 更新說明: 本次更新在一定程度上解決了Win10最新版本中白色工作列時文字看不清的問題。需要手動在“選項”——“工作列視窗設定”——“透明色”設定透明色。當透明色不為黑色且和背景色不同時為不透明效果,如果和背景色相同則為透明效果。在Win10白色工作列中建議如下圖所示設定: ![白色任务栏截图](https://user-images.githubusercontent.com/30562462/57004858-36b55300-6c05-11e9-89d8-9911dc99f09c.PNG) ## V1.76 (2018/11/11) * 修正了解析度更改可能會導致程式崩潰的問題; * 新增設定檔儲存位置的選項; * 修正了當解析度更改時工作列視窗的垂直位置不正確的問題; * 新增今日上傳和下載流量的顯示,歷史流量統計中增加上傳和下載流量的統計; * 其他細節方面的改進。 ================================================ FILE: include/OpenHardwareMonitor/OpenHardwareMonitorApi.h ================================================ #pragma once #include #include "OpenHardwareMonitorGlobal.h" #include #include namespace OpenHardwareMonitorApi { class IOpenHardwareMonitor { public: virtual void GetHardwareInfo() = 0; //获取一次硬件信息 virtual float CpuTemperature() = 0; //返回获取到的CPU温度 virtual float GpuTemperature() = 0; //返回获取到的GPU温度 virtual float HDDTemperature() = 0; //返回获取到的硬盘温度 virtual float MainboardTemperature() = 0; //返回获取到的主板温度 virtual float GpuUsage() = 0; //返回获取到的GPU利用率 virtual float CpuFreq() = 0; //返回获取到的CPU频率 virtual const std::map& AllHDDTemperature() = 0; //返回所有硬盘的温度。map的key是硬盘的名称,value是硬盘的温度 virtual const std::map& AllCpuTemperature() = 0; //返回所有CPU(核心)的温度。map的key是CPU的名称,value是硬盘的温度 virtual const std::map& AllHDDUsage() = 0; //返回所有硬盘的使用率 virtual void SetCpuEnable(bool enable) = 0; virtual void SetGpuEnable(bool enable) = 0; virtual void SetHddEnable(bool enable) = 0; virtual void SetMainboardEnable(bool enable) = 0; }; OPENHARDWAREMONITOR_API std::shared_ptr CreateInstance(); OPENHARDWAREMONITOR_API std::wstring GetErrorMessage(); } ================================================ FILE: include/OpenHardwareMonitor/OpenHardwareMonitorGlobal.h ================================================ #pragma once #ifdef OPENHARDWAREMONITOR_EXPORTS #define OPENHARDWAREMONITOR_API __declspec(dllexport) #else #define OPENHARDWAREMONITOR_API __declspec(dllimport) #endif ================================================ FILE: include/PluginInterface.h ================================================ /********************************************************* * TrafficMonitor 插件接口 * Copyright (C) by Zhong Yang 2021 * zhongyang219@hotmail.com **********************************************************/ #pragma once //插件显示项目的接口 class IPluginItem { public: /** * @brief 获取显示项目的名称 * @return const wchar_t* */ virtual const wchar_t* GetItemName() const = 0; /** * @brief 获取显示项目的唯一ID * @return const wchar_t* */ virtual const wchar_t* GetItemId() const = 0; /** * @brief 获取项目标签的文本 * @return const wchar_t* */ virtual const wchar_t* GetItemLableText() const = 0; /** * @brief 获取项目数值的文本 * @detail 由于此函数可能会被频繁调用,因此不要在这里获取监控数据, * 而是在ITMPlugin::DataRequired函数中获取数据后保存起来,然后在这里返回获取的数值 * @return const wchar_t* */ virtual const wchar_t* GetItemValueText() const = 0; /** * @brief 获取项目数值的示例文本 * @detail 此函数返回的字符串的长度会用于计算显示区域的宽度 * @return const wchar_t* */ virtual const wchar_t* GetItemValueSampleText() const = 0; /** * @brief 显示区域是否由插件自行绘制 * @detail * 如果返回false,则根据GetItemLableText和GetItemValueText返回的文本由主程序绘制显示区域,重写DrawItem函数将不起作用。 * 如果重写此函数并返回true,则必须重写DrawItem函数并在里面添加绘制显示区域的代码, * 此时GetItemLableText、GetItemValueText和GetItemValueSampleText的返回值将被主程序忽略 * @return bool */ virtual bool IsCustomDraw() const { return false; } /** * @brief 获取显示区域的宽度 * @detail * 只有当CustomDraw()函数返回true时重写此函数才有效。 * 返回的值为DPI为96(100%)时的宽度,主程序会根据当前系统DPI的设置自动按比例放大, * 因此你不需要为不同的DPI设置返回不同的值。 * 需要注意的是,这里的返回值代表了自绘区域所需要的最小宽度,DrawItem函数中的参数w的值可能会大于这个值 * @return int */ virtual int GetItemWidth() const { return 0; } /** * @brief 自定义绘制显示区域的函数,只有当CustomDraw()函数返回true时重写此函数才有效 * @param void * hDC 绘图的上下文句柄 * @param int x 绘图的矩形区域 * @param int y * @param int w * @param int h * @param bool dark_mode 深色模式为true,浅色模式为false * @return void */ virtual void DrawItem(void* hDC, int x, int y, int w, int h, bool dark_mode) {} /** * @brief 获取显示区域的宽度 * @detail * 只有当CustomDraw()函数返回true时重写此函数才有效。 * 此函数和GetItemWidth不同,插件可以根据参数hDC来计算需要的宽度, * 它返回的是实际的宽度,主程序不会根据当前系统的DPI对返回值进行放大。 * 需要注意的是,这里的返回值代表了自绘区域所需要的最小宽度,DrawItem函数中的参数w的值可能会大于这个值 * @param void * hDC 绘图的上下文句柄 * @return int */ virtual int GetItemWidthEx(void* hDC) const { return 0; } /** 鼠标事件的类型 */ enum MouseEventType { MT_LCLICKED, /**< 点击了鼠标左键 */ MT_RCLICKED, /**< 点击了鼠标右键 */ MT_DBCLICKED, /**< 双击了鼠标左键 */ }; enum MouseEventFlag { MF_TASKBAR_WND = 1 << 0, /**< 是否为任务栏窗口的鼠标事件 */ }; /** * @brief 当插件显示区域有鼠标事件时由主程序调用 * @param MouseEventType type 鼠标事件的类型 * @param int x 鼠标指针所在的x坐标 * @param int y 鼠标指针所在的y坐标 * @param void* hWnd 产生此鼠标事件的窗口的句柄(主窗口或任务栏窗口) * @param int flag 为若干MouseEventFlag枚举常量的组合 * @return int 如果返回非0,则主程序认为插件已经对此鼠标事件作出了全部的响应,主程序将不会再对此鼠标事件做额外的响应。 * 例如当type为MT_RCLICKED时,如果程序返回0,则会弹出主程序提供的右键菜单;而返回非0时,主程序不会再做任何处理。 */ virtual int OnMouseEvent(MouseEventType type, int x, int y, void* hWnd, int flag) { return 0; } enum ItemInfoType { }; virtual void* OnItemInfo(ItemInfoType, void* para1, void* para2) { return 0; } }; //插件接口 class ITMPlugin { public: /** * @brief 插件接口的版本,仅当修改了插件接口时才会修改这里的返回值。 * @attention 插件开发者不应该修改这里的返回值,也不应该重写此虚函数。 * @return int */ virtual int GetAPIVersion() const { return 3; } /** * @brief 获取插件显示项目的对象 * @detail 一个插件dll可以提供多个实现IPluginItem接口的对象,对应多个显示项目。 * 当index的值大于或等于0且小于IPluginItem接口的对象的个数时,返回对象的IPluginItem接口的指针,其他情况应该返回空指针。 * 例如插件提供两个显示项目,则当index等于0或1时返回对应IPluginItem接口的对象,其他值时必须返回空指针。 * @param int index 对象的索引 * @return IPluginItem* 插件显示项目的对象 */ virtual IPluginItem* GetItem(int index) = 0; /** * @brief 主程序会每隔一定时间调用此函数,插件需要在函数里获取一次监控的数据 */ virtual void DataRequired() = 0; /** 选项设置对话框的返回值 */ enum OptionReturn { OR_OPTION_CHANGED, /**< 选项设置对话框中更改了选项设置 */ OR_OPTION_UNCHANGED, /**< 选项设置对话框中未更改选项设置 */ OR_OPTION_NOT_PROVIDED /**< 未提供选项设置对话框 */ }; /** * @brief 主程序调用此函数以打开插件的选项设置对话框 * @detail 此函数不一定要重写。如果插件提供了选项设置界面,则应该重写此函数,并在最后返回OR_OPTION_CHANGED或OR_OPTION_UNCHANGED。 * @param void * hParent 父窗口的句柄 * 返回值为OR_OPTION_NOT_PRVIDED则认为插件不提供选项设置对话框。 * @return ITMPlugin::OptionReturn */ virtual OptionReturn ShowOptionsDialog(void* hParent) { return OR_OPTION_NOT_PROVIDED; } /** 插件信息的索引 */ enum PluginInfoIndex { TMI_NAME, /**< 名称 */ TMI_DESCRIPTION, /**< 描述 */ TMI_AUTHOR, /**< 作者 */ TMI_COPYRIGHT, /**< 版权 */ TMI_VERSION, /**< 版本 */ TMI_URL, /**< 主页 */ TMI_MAX /**< 插件信息的最大值 */ }; /** * @brief 获取此插件的信息,根据index的值返回对应的信息 */ virtual const wchar_t* GetInfo(PluginInfoIndex index) = 0; /** 主程序的监控信息 */ struct MonitorInfo { unsigned long long up_speed{}; unsigned long long down_speed{}; int cpu_usage{}; int memory_usage{}; int gpu_usage{}; int hdd_usage{}; int cpu_temperature{}; int gpu_temperature{}; int hdd_temperature{}; int main_board_temperature{}; int cpu_freq{}; }; /** * @brief 主程序调用此函数以向插件传递所有获取到的监控信息 */ virtual void OnMonitorInfo(const MonitorInfo& monitor_info) {} /** * @brief 获取插件要在鼠标提示中显示的文本 */ virtual const wchar_t* GetTooltipInfo() { return L""; } enum ExtendedInfoIndex { EI_LABEL_TEXT_COLOR, //绘图的标签文本颜色 EI_VALUE_TEXT_COLOR, //绘图的数值文本颜色 EI_DRAW_TASKBAR_WND, //是否绘制任务栏窗口 //主窗口选项设置 EI_NAIN_WND_NET_SPEED_SHORT_MODE, //网速显示简洁模式 EI_MAIN_WND_SPERATE_WITH_SPACE, //数值和单位使用空格分隔 EI_MAIN_WND_UNIT_BYTE, //网速单位是否使用B(字节) EI_MAIN_WND_UNIT_SELECT, //网速单位选择(0:自动,1:固定为KB/s,2:固定为MB/s) EI_MAIN_WND_NOT_SHOW_UNIT, //不显示网速单位 EI_MAIN_WND_NOT_SHOW_PERCENT, //不显示百分号 //任务栏窗口设置 EI_TASKBAR_WND_NET_SPEED_SHORT_MODE, //网速显示简洁模式 EI_TASKBAR_WND_SPERATE_WITH_SPACE, //数值和单位使用空格分隔 EI_TASKBAR_WND_VALUE_RIGHT_ALIGN, //数值右对齐 EI_TASKBAR_WND_NET_SPEED_WIDTH, //网速数据宽度 EI_TASKBAR_WND_UNIT_BYTE, //网速单位是否使用B(字节) EI_TASKBAR_WND_UNIT_SELECT, //网速单位选择(0:自动,1:固定为KB/s,2:固定为MB/s) EI_TASKBAR_WND_NOT_SHOW_UNIT, //不显示网速单位 EI_TASKBAR_WND_NOT_SHOW_PERCENT, //不显示百分号 EI_CONFIG_DIR, //配置文件的目录 }; /** * @brief 主程序调用此函数以向插件传递更多信息 * @param ExtendedInfoIndex index 信息的索引,用于区分向插件传递的信息 * @param const wchar_t* data 传递的数据 * @return void */ virtual void OnExtenedInfo(ExtendedInfoIndex index, const wchar_t* data) {} }; /* * 注意:插件dll需导出以下函数 * ITMPlugin* TMPluginGetInstance(); * 函数返回一个ITMPlugin接口的对象的指针。 * 此对象通常应该为一个全局或静态的对象,在程序运行结束前,它都不应该被释放。 */ /* * 更新记录: * ------------------------------------------------------------------------- * API version | 更新内容 * ------------------------------------------------------------------------- * 1 | 第一个版本 * ------------------------------------------------------------------------- * 2 | 新增 ITMPlugin::GetTooltipInfo 函数 * ------------------------------------------------------------------------- * 3 | 新增 IPluginItem::GetItemWidthEx, IPluginItem::OnMouseEvent 函数 * ------------------------------------------------------------------------- */ ================================================ FILE: version.info ================================================ 1.83 https://gitee.com/zhongyang219/TrafficMonitor/attach_files/958687/download/TrafficMonitor_V1.83_x86_Lite.zip https://gitee.com/zhongyang219/TrafficMonitor/attach_files/958688/download/TrafficMonitor_V1.83_x64_Lite.zip Ѿһƻʱ޷ÿ⣬\nѾTrafficMonitorʱ򣬵ѾСԻ\nʾϢʾ\núȻᱻص⡣\nеIJĿ֧\nѡѡҪڡбʾĹܡ\nʾٵĹܡ\nʾռͼĹܡ\nӲжͬӲʱֻʾһӲ̵⡣\nŻںͼʾЧ\nҼ˵еġʾáɲ˵ΪԻʽ\nѡӡ˵ӡˢб\n³⡣ ================================================ FILE: version_utf8.info ================================================ 1.83 https://github.com/zhongyang219/TrafficMonitor/releases/download/V1.83/TrafficMonitor_V1.83_x86.zip https://github.com/zhongyang219/TrafficMonitor/releases/download/V1.83/TrafficMonitor_V1.83_x64.zip https://github.com/zhongyang219/TrafficMonitor/releases/download/V1.83/TrafficMonitor_V1.83_x86_Lite.zip https://github.com/zhongyang219/TrafficMonitor/releases/download/V1.83/TrafficMonitor_V1.83_x64_Lite.zip https://gitee.com/zhongyang219/TrafficMonitor/attach_files/958690/download/TrafficMonitor_V1.83_x86.zip https://gitee.com/zhongyang219/TrafficMonitor/attach_files/958689/download/TrafficMonitor_V1.83_x64.zip https://gitee.com/zhongyang219/TrafficMonitor/attach_files/958687/download/TrafficMonitor_V1.83_x86_Lite.zip https://gitee.com/zhongyang219/TrafficMonitor/attach_files/958688/download/TrafficMonitor_V1.83_x64_Lite.zip 修正当已经存在一个开机自启动的任务计划时,无法设置开机自启动的问题,\n新增当已经存在TrafficMonitor进程时启动程序,弹出“程序已经在运行”对话框。\n鼠标提示中新增插件信息的显示。\n修正插件被禁用后仍然会被加载的问题。\n任务栏中的插件项目支持自由排序。\n选项设置中新增可以选择要在“网络连接列表”中显示的网络的功能。\n新增显示总网速的功能。\n新增在任务栏中显示网速占用图的功能。\n修正硬件监控中有多个名称相同的硬盘时只能显示一个硬盘的问题。\n优化任务栏窗口横向滚动图的显示效果。\n任务栏窗口右键菜单中的“显示设置”由菜单改为对话框形式。\n“选择网络连接”菜单中添加“刷新网络连接列表”命令。\n修正几处导致程序崩溃的问题。 Fixed the problem that when there is already a task plan of auto-run, the auto-run at start up will be failed to set.\nAdded the "Program is already running" dialog box at the program is started when there is already a TrafficMonitor process running.\nAdded the plug-in information in the mouse tool tips.\nFixed an issue where plugins could still be loaded if they were disabled.\nAdded the support of free sorting of plugin items in the taskbar.\nAdded the function to select the network connections to be displayed in the "Network Connection List" in the option settings.\nAdded the function of displaying the total network speed.\nAdded the function of displaying the network speed graph in the taskbar.\nFixed the problem that only one hard disk can be displayed when there are multiple hard disks with the same name in the hardware monitor.\nOptimize the display effect of the resource usage graph in plot mode of the taskbar window.\nChange the "Display Settings" in the taskbar window context menu from menu to dialog box.\nAdded "Refresh connection list" command to "Select Network Connections" menu.\nFixed some crashes.\n 修正當已經存在一個開機自啟動的任務計劃時,無法設定開機自啟動的問題,\n新增當已經存在TrafficMonitor程序時啟動程式,彈出“程式已經在執行”對話方塊。\n滑鼠提示中新增外掛資訊的顯示。\n修正外掛被禁用後仍然會被載入的問題。\n工作列中的外掛專案支援自由排序。\n選項設定中新增可以選擇要在“網路連線列表”中顯示的網路的功能。\n新增顯示總網速的功能。\n新增在工作列中顯示網速佔用圖的功能。\n修正硬體監控中有多個名稱相同的硬碟時只能顯示一個硬碟的問題。\n最佳化工作列視窗橫向滾動圖的顯示效果。\n工作列視窗右鍵選單中的“顯示設定”由選單改為對話方塊形式。\n“選擇網路連線”選單中新增“重新整理網路連線列表”命令。\n修正幾處導致程式崩潰的問題。 ================================================ FILE: 皮肤制作教程.md ================================================ **皮肤制作教程已经移至Wiki页面:** [皮肤制作教程 · zhongyang219/TrafficMonitor Wiki (github.com)](https://github.com/zhongyang219/TrafficMonitor/wiki/皮肤制作教程)