├── .gitattributes ├── .gitignore ├── .gitmodules ├── DevExp ├── AboutDlg.cpp ├── AboutDlg.h ├── AppSettings.cpp ├── AppSettings.h ├── DevExp.cpp ├── DevExp.h ├── DevExp.rc ├── DevExp.vcxproj ├── DevExp.vcxproj.filters ├── DevNodeListView.cpp ├── DevNodeListView.h ├── DevNodeView.cpp ├── DevNodeView.h ├── DeviceClassesView.cpp ├── DeviceClassesView.h ├── DeviceInterfacesView.cpp ├── DeviceInterfacesView.h ├── DriversPropertyPage.cpp ├── DriversPropertyPage.h ├── DriversView.cpp ├── DriversView.h ├── DxgiView.cpp ├── DxgiView.h ├── GeneralPropertyPage.cpp ├── GeneralPropertyPage.h ├── Helpers.cpp ├── Helpers.h ├── Interfaces.h ├── MainFrm.cpp ├── MainFrm.h ├── MultiStringListDlg.cpp ├── MultiStringListDlg.h ├── ResourcesPropertyPage.cpp ├── ResourcesPropertyPage.h ├── SecurityHelper.cpp ├── SecurityHelper.h ├── ViewBase.h ├── packages.config ├── pch.cpp ├── pch.h ├── res │ ├── Adapter.ico │ ├── Binary.ico │ ├── Check.ico │ ├── DevExp.ico │ ├── Go.ico │ ├── Install.ico │ ├── LPT-plug.ico │ ├── Properties.ico │ ├── Stop.ico │ ├── Text.ico │ ├── close-all.ico │ ├── close.ico │ ├── copy.ico │ ├── delete.ico │ ├── device.ico │ ├── devices.ico │ ├── directx.ico │ ├── disable.ico │ ├── driver-kmdf.ico │ ├── driver-umdf.ico │ ├── driver.ico │ ├── enable.ico │ ├── enum.ico │ ├── find.ico │ ├── flag.ico │ ├── gear_refresh.ico │ ├── globe.ico │ ├── info.ico │ ├── interface.ico │ ├── interrupt.ico │ ├── link.ico │ ├── list.ico │ ├── memory.ico │ ├── number-4.ico │ ├── piece.ico │ ├── power.ico │ ├── radio.ico │ ├── rectangle.ico │ ├── refresh.ico │ ├── resolution.ico │ ├── resource.ico │ ├── show-hidden.ico │ ├── tree.ico │ └── uninstall.ico └── resource.h ├── DevExpC ├── DevExpC.cpp ├── DevExpC.vcxproj ├── DevExpC.vcxproj.filters ├── packages.config ├── pch.cpp └── pch.h ├── DevExpCore ├── DevExpCore.vcxproj ├── DevExpCore.vcxproj.filters ├── DeviceManager.cpp ├── DeviceManager.h ├── DeviceNode.cpp ├── DeviceNode.h ├── DriverManager.cpp ├── DriverManager.h ├── packages.config ├── pch.cpp └── pch.h ├── DeviceExplorer.sln ├── README.md └── instdrv ├── instdrv.cpp ├── instdrv.vcxproj └── instdrv.vcxproj.filters /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "WTLHelper"] 2 | path = WTLHelper 3 | url = https://github.com/zodiacon/WTLHelper.git 4 | -------------------------------------------------------------------------------- /DevExp/AboutDlg.cpp: -------------------------------------------------------------------------------- 1 | // aboutdlg.cpp : implementation of the CAboutDlg class 2 | // 3 | ///////////////////////////////////////////////////////////////////////////// 4 | 5 | #include "pch.h" 6 | #include "resource.h" 7 | 8 | #include "aboutdlg.h" 9 | 10 | LRESULT CAboutDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { 11 | CenterWindow(GetParent()); 12 | return TRUE; 13 | } 14 | 15 | LRESULT CAboutDlg::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { 16 | EndDialog(wID); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /DevExp/AboutDlg.h: -------------------------------------------------------------------------------- 1 | // aboutdlg.h : interface of the CAboutDlg class 2 | // 3 | ///////////////////////////////////////////////////////////////////////////// 4 | 5 | #pragma once 6 | 7 | class CAboutDlg : public CDialogImpl 8 | { 9 | public: 10 | enum { IDD = IDD_ABOUTBOX }; 11 | 12 | BEGIN_MSG_MAP(CAboutDlg) 13 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) 14 | COMMAND_ID_HANDLER(IDOK, OnCloseCmd) 15 | COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd) 16 | END_MSG_MAP() 17 | 18 | // Handler prototypes (uncomment arguments if needed): 19 | // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 20 | // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 21 | // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) 22 | 23 | LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 24 | LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 25 | }; 26 | -------------------------------------------------------------------------------- /DevExp/AppSettings.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "AppSettings.h" 3 | -------------------------------------------------------------------------------- /DevExp/AppSettings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct AppSettings : Settings { 6 | BEGIN_SETTINGS(AppSettings) 7 | SETTING(MainWindowPlacement, WINDOWPLACEMENT{}, SettingType::Binary); 8 | SETTING(Font, LOGFONT{}, SettingType::Binary); 9 | SETTING(AlwaysOnTop, 0, SettingType::Bool); 10 | SETTING(SingleInstance, 0, SettingType::Bool); 11 | SETTING(DarkMode, 0, SettingType::Bool); 12 | END_SETTINGS 13 | 14 | DEF_SETTING(AlwaysOnTop, bool) 15 | DEF_SETTING(SingleInstance, bool) 16 | DEF_SETTING(DarkMode, bool) 17 | DEF_SETTING(MainWindowPlacement, WINDOWPLACEMENT) 18 | }; 19 | -------------------------------------------------------------------------------- /DevExp/DevExp.cpp: -------------------------------------------------------------------------------- 1 | // DevExp.cpp : main source file for DevExp.exe 2 | // 3 | 4 | #include "pch.h" 5 | #include "resource.h" 6 | #include "MainFrm.h" 7 | #include 8 | 9 | CAppModule _Module; 10 | 11 | int Run(LPTSTR /*lpstrCmdLine*/ = nullptr, int nCmdShow = SW_SHOWDEFAULT) { 12 | CMessageLoop theLoop; 13 | _Module.AddMessageLoop(&theLoop); 14 | 15 | CMainFrame wndMain; 16 | 17 | if (wndMain.CreateEx() == nullptr) { 18 | ATLTRACE(_T("Main window creation failed!\n")); 19 | return 0; 20 | } 21 | 22 | wndMain.ShowWindow(nCmdShow); 23 | 24 | int nRet = theLoop.Run(); 25 | 26 | _Module.RemoveMessageLoop(); 27 | return nRet; 28 | } 29 | 30 | int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow) { 31 | HRESULT hRes = ::CoInitialize(nullptr); 32 | ATLASSERT(SUCCEEDED(hRes)); 33 | 34 | AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES | ICC_TREEVIEW_CLASSES | ICC_LISTVIEW_CLASSES); 35 | 36 | hRes = _Module.Init(nullptr, hInstance); 37 | ATLASSERT(SUCCEEDED(hRes)); 38 | 39 | ThemeHelper::Init(); 40 | 41 | int nRet = Run(lpstrCmdLine, nCmdShow); 42 | 43 | _Module.Term(); 44 | ::CoUninitialize(); 45 | 46 | return nRet; 47 | } 48 | -------------------------------------------------------------------------------- /DevExp/DevExp.h: -------------------------------------------------------------------------------- 1 | // DevExp.h 2 | -------------------------------------------------------------------------------- /DevExp/DevExp.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/DevExp.rc -------------------------------------------------------------------------------- /DevExp/DevExp.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {f2c22c0f-e93c-444b-aaa5-d63b3697b352} 6 | cpp;c;cxx;def;odl;idl;hpj;bat;asm 7 | 8 | 9 | {14ef3ad7-7297-4dea-92bd-517d993b6b4a} 10 | h;hpp;hxx;hm;inl;inc 11 | 12 | 13 | {57cf9fa9-224f-4e3c-a91e-1c99c3f25723} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest 15 | 16 | 17 | {c7eb6f60-5c76-47bb-8acc-b2ad318401fb} 18 | 19 | 20 | {76805f94-7243-440d-8fa8-651ecc1b7517} 21 | 22 | 23 | {abbdf13d-4b2e-42b6-8810-fdf795c519a8} 24 | 25 | 26 | {6d84be13-073d-4601-ad30-73096477d2c4} 27 | 28 | 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Views 41 | 42 | 43 | Views 44 | 45 | 46 | Helpers 47 | 48 | 49 | Dialogs 50 | 51 | 52 | Helpers 53 | 54 | 55 | Views 56 | 57 | 58 | Views 59 | 60 | 61 | Dialogs 62 | 63 | 64 | Dialogs 65 | 66 | 67 | Dialogs 68 | 69 | 70 | Dialogs 71 | 72 | 73 | Views 74 | 75 | 76 | Source Files 77 | 78 | 79 | Views 80 | 81 | 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Views 91 | 92 | 93 | Resource Files 94 | 95 | 96 | Helpers 97 | 98 | 99 | Views 100 | 101 | 102 | Header Files 103 | 104 | 105 | Dialogs 106 | 107 | 108 | Header Files 109 | 110 | 111 | Views 112 | 113 | 114 | Helpers 115 | 116 | 117 | Views 118 | 119 | 120 | Views 121 | 122 | 123 | Dialogs 124 | 125 | 126 | Dialogs 127 | 128 | 129 | Dialogs 130 | 131 | 132 | Dialogs 133 | 134 | 135 | Views 136 | 137 | 138 | Views 139 | 140 | 141 | 142 | 143 | Resource Files 144 | 145 | 146 | 147 | 148 | Resource Files\Icons 149 | 150 | 151 | Resource Files\Icons 152 | 153 | 154 | Resource Files\Icons 155 | 156 | 157 | Resource Files\Icons 158 | 159 | 160 | Resource Files\Icons 161 | 162 | 163 | Resource Files\Icons 164 | 165 | 166 | Resource Files\Icons 167 | 168 | 169 | Resource Files\Icons 170 | 171 | 172 | Resource Files\Icons 173 | 174 | 175 | Resource Files\Icons 176 | 177 | 178 | Resource Files\Icons 179 | 180 | 181 | Resource Files\Icons 182 | 183 | 184 | Resource Files\Icons 185 | 186 | 187 | Resource Files\Icons 188 | 189 | 190 | Resource Files\Icons 191 | 192 | 193 | Resource Files\Icons 194 | 195 | 196 | Resource Files\Icons 197 | 198 | 199 | Resource Files\Icons 200 | 201 | 202 | Resource Files\Icons 203 | 204 | 205 | Resource Files\Icons 206 | 207 | 208 | Resource Files\Icons 209 | 210 | 211 | Resource Files\Icons 212 | 213 | 214 | Resource Files\Icons 215 | 216 | 217 | Resource Files\Icons 218 | 219 | 220 | Resource Files\Icons 221 | 222 | 223 | Resource Files\Icons 224 | 225 | 226 | Resource Files\Icons 227 | 228 | 229 | Resource Files\Icons 230 | 231 | 232 | Resource Files\Icons 233 | 234 | 235 | Resource Files\Icons 236 | 237 | 238 | Resource Files\Icons 239 | 240 | 241 | Resource Files\Icons 242 | 243 | 244 | Resource Files\Icons 245 | 246 | 247 | Resource Files\Icons 248 | 249 | 250 | Resource Files\Icons 251 | 252 | 253 | Resource Files\Icons 254 | 255 | 256 | 257 | 258 | 259 | -------------------------------------------------------------------------------- /DevExp/DevNodeListView.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DevNodeListView.h" 3 | #include "Helpers.h" 4 | #include "SortHelper.h" 5 | #include "AppSettings.h" 6 | #include "ListViewhelper.h" 7 | #include "ClipboardHelper.h" 8 | #include "SecurityHelper.h" 9 | 10 | DWORD CDevNodeListView::OnPrePaint(int, LPNMCUSTOMDRAW cd) { 11 | return CDRF_NOTIFYITEMDRAW; 12 | } 13 | 14 | DWORD CDevNodeListView::OnItemPrePaint(int, LPNMCUSTOMDRAW cd) { 15 | return CDRF_NOTIFYSUBITEMDRAW; 16 | } 17 | 18 | DWORD CDevNodeListView::OnSubItemPrePaint(int, LPNMCUSTOMDRAW cd) { 19 | auto lv = (NMLVCUSTOMDRAW*)cd; 20 | if (lv->iSubItem != 1) 21 | return CDRF_SKIPPOSTPAINT; 22 | 23 | auto& item = m_Items[(int)cd->dwItemSpec]; 24 | if ((DeviceNode(item.Data.DevInst).GetStatus() & DeviceNodeStatus::HasProblem) == DeviceNodeStatus::HasProblem) { 25 | ::DrawIconEx(cd->hdc, 12, cd->rc.top + 4, AtlLoadSysIcon(IDI_WARNING), 16, 16, 0, nullptr, DI_NORMAL); 26 | } 27 | 28 | return CDRF_SKIPPOSTPAINT; 29 | } 30 | 31 | 32 | void CDevNodeListView::Refresh() { 33 | bool first = m_Items.empty(); 34 | m_Items = m_dm->EnumDevices(m_ShowHiddenDevices); 35 | m_List.GetImageList(LVSIL_SMALL).RemoveAll(); 36 | if (first) { 37 | m_List.SetItemCount((int)m_Items.size()); 38 | } 39 | else { 40 | m_List.SetItemCountEx((int)m_Items.size(), LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL); 41 | DoSort(GetSortInfo(m_List)); 42 | m_List.RedrawItems(m_List.GetTopIndex(), m_List.GetTopIndex() + m_List.GetCountPerPage()); 43 | } 44 | } 45 | 46 | CString CDevNodeListView::GetColumnText(HWND, int row, int col) { 47 | auto& item = m_Items[row]; 48 | switch (GetColumnManager(m_List)->GetColumnTag(col)) { 49 | case ColumnType::Name: return item.Description.empty() ? L"This PC" : item.Description.c_str(); 50 | case ColumnType::Instance: return std::to_wstring(item.Data.DevInst).c_str(); 51 | case ColumnType::Class: 52 | return GetDeviceClassName(item); 53 | case ColumnType::Status: 54 | return Helpers::DevNodeStatusToString(DeviceNode(item.Data.DevInst).GetStatus()); 55 | case ColumnType::Driver: 56 | return GetStringProperty(item, DEVPKEY_Device_Driver); 57 | case ColumnType::PDOName: 58 | return GetStringProperty(item, DEVPKEY_Device_PDOName); 59 | case ColumnType::Parent: 60 | return GetStringProperty(item, DEVPKEY_Device_Parent); 61 | case ColumnType::Enumerator: 62 | return GetStringProperty(item, DEVPKEY_Device_EnumeratorName); 63 | case ColumnType::Depth: return std::to_wstring(DeviceNode(item.Data.DevInst).GetDepth()).c_str(); 64 | } 65 | return L""; 66 | } 67 | 68 | bool CDevNodeListView::OnRightClickList(HWND, int row, int col, POINT const& pt) { 69 | CMenu menu; 70 | menu.LoadMenu(IDR_CONTEXT); 71 | return GetFrame()->TrackPopupMenu(menu.GetSubMenu(0), TPM_RIGHTBUTTON, pt.x, pt.y); 72 | } 73 | 74 | bool CDevNodeListView::OnDoubleClickList(HWND, int row, int col, POINT const&) { 75 | LRESULT result; 76 | ProcessWindowMessage(m_hWnd, WM_COMMAND, ID_DEVICE_PROPERTIES, 0, result, 1); 77 | return true; 78 | } 79 | 80 | LRESULT CDevNodeListView::OnCreate(UINT, WPARAM, LPARAM, BOOL&) { 81 | m_hWndClient = m_List.Create(m_hWnd, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN 82 | | LVS_OWNERDATA | LVS_REPORT | LVS_SHOWSELALWAYS); 83 | m_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP); 84 | CImageList images; 85 | images.Create(16, 16, ILC_COLOR32 | ILC_MASK, 64, 32); 86 | m_List.SetImageList(images, LVSIL_SMALL); 87 | 88 | auto cm = GetColumnManager(m_List); 89 | cm->AddColumn(L"Name", LVCFMT_LEFT, 250, ColumnType::Name); 90 | cm->AddColumn(L"Instance", LVCFMT_RIGHT, 80, ColumnType::Instance); 91 | cm->AddColumn(L"Class", LVCFMT_LEFT, 140, ColumnType::Class); 92 | cm->AddColumn(L"Depth", LVCFMT_RIGHT, 60, ColumnType::Depth); 93 | cm->AddColumn(L"Status", LVCFMT_LEFT, 240, ColumnType::Status); 94 | cm->AddColumn(L"PDO Name", LVCFMT_LEFT, 160, ColumnType::PDOName); 95 | cm->AddColumn(L"Enumerator", LVCFMT_LEFT, 120, ColumnType::Enumerator); 96 | cm->AddColumn(L"Parent", LVCFMT_LEFT, 220, ColumnType::Parent); 97 | 98 | m_dm = DeviceManager::Create(); 99 | 100 | Refresh(); 101 | 102 | return 0; 103 | } 104 | 105 | LRESULT CDevNodeListView::OnSetFocus(UINT, WPARAM, LPARAM, BOOL&) { 106 | m_List.SetFocus(); 107 | 108 | return 0; 109 | } 110 | 111 | CString CDevNodeListView::GetStringProperty(DeviceItem& item, DEVPROPKEY const& key) { 112 | return DeviceNode(item.Data.DevInst).GetProperty(key).c_str(); 113 | } 114 | 115 | CString const& CDevNodeListView::GetDeviceClassName(DeviceItem& item) { 116 | if (item.Class.IsEmpty()) { 117 | item.Class = DeviceManager::GetDeviceClassDescription(item.Data.ClassGuid).c_str(); 118 | if (item.Class.IsEmpty()) 119 | item.Class = DeviceNode(item.Data.DevInst).GetProperty(DEVPKEY_Device_Class).c_str(); 120 | } 121 | return item.Class; 122 | } 123 | 124 | int CDevNodeListView::GetRowImage(HWND, int row, int) { 125 | auto& item = m_Items[row]; 126 | if (item.Image >= 0) 127 | return item.Image; 128 | auto icon = m_dm->GetDeviceIcon(item); 129 | if (icon) { 130 | item.Image = m_List.GetImageList(LVSIL_SMALL).AddIcon(icon); 131 | ::DestroyIcon(icon); 132 | } 133 | return item.Image; 134 | } 135 | 136 | void CDevNodeListView::DoSort(const SortInfo* si) { 137 | if (si == nullptr) 138 | return; 139 | 140 | auto compare = [&](auto& d1, auto& d2) { 141 | switch (GetColumnManager(m_List)->GetColumnTag(si->SortColumn)) { 142 | case ColumnType::Name: return SortHelper::Sort(d1.Description, d2.Description, si->SortAscending); 143 | case ColumnType::Class: return SortHelper::Sort(GetDeviceClassName(d1), GetDeviceClassName(d2), si->SortAscending); 144 | case ColumnType::Instance: return SortHelper::Sort(d1.Data.DevInst, d2.Data.DevInst, si->SortAscending); 145 | case ColumnType::Status: return SortHelper::Sort(DeviceNode(d1.Data.DevInst).GetStatus(), DeviceNode(d2.Data.DevInst).GetStatus(), si->SortAscending); 146 | case ColumnType::Enumerator: return SortHelper::Sort(GetStringProperty(d1, DEVPKEY_Device_EnumeratorName), GetStringProperty(d2, DEVPKEY_Device_EnumeratorName), si->SortAscending); 147 | case ColumnType::PDOName: return SortHelper::Sort(GetStringProperty(d1, DEVPKEY_Device_PDOName), GetStringProperty(d2, DEVPKEY_Device_PDOName), si->SortAscending); 148 | case ColumnType::Parent: return SortHelper::Sort(GetStringProperty(d1, DEVPKEY_Device_Parent), GetStringProperty(d2, DEVPKEY_Device_Parent), si->SortAscending); 149 | case ColumnType::Depth: return SortHelper::Sort(DeviceNode(d1.Data.DevInst).GetDepth(), DeviceNode(d2.Data.DevInst).GetDepth(), si->SortAscending); 150 | } 151 | return false; 152 | }; 153 | 154 | std::sort(m_Items.begin(), m_Items.end(), compare); 155 | } 156 | 157 | LRESULT CDevNodeListView::OnShowHiddenDevices(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { 158 | m_ShowHiddenDevices = !m_ShowHiddenDevices; 159 | GetFrame()->GetUI().UISetCheck(ID_VIEW_SHOWHIDDENDEVICES, m_ShowHiddenDevices); 160 | 161 | Refresh(); 162 | return 0; 163 | } 164 | 165 | LRESULT CDevNodeListView::OnViewRefresh(WORD, WORD, HWND, BOOL&) { 166 | Refresh(); 167 | return 0; 168 | } 169 | 170 | LRESULT CDevNodeListView::OnCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { 171 | CString text; 172 | for (auto i = m_List.GetNextItem(-1, LVIS_SELECTED); i >= 0; i = m_List.GetNextItem(i, LVIS_SELECTED)) { 173 | text += ListViewHelper::GetRowAsString(m_List, i); 174 | text += L"\n"; 175 | } 176 | ClipboardHelper::CopyText(m_hWnd, text.Left(text.GetLength() - 1)); 177 | return 0; 178 | } 179 | 180 | void CDevNodeListView::UpdateUI(CUpdateUIBase& ui) { 181 | ui.UISetCheck(ID_VIEW_SHOWHIDDENDEVICES, m_ShowHiddenDevices); 182 | int selected = m_List.GetSelectionMark(); 183 | auto dev = selected >= 0 ? m_Items[selected].Data.DevInst : 0; 184 | ui.UIEnable(ID_DEVICE_PROPERTIES, m_List.GetSelectedCount() == 1 && dev != (DEVINST)m_dm->GetRootDeviceNode()); 185 | 186 | if (SecurityHelper::IsRunningElevated() && m_List.GetSelectedCount() == 1) { 187 | DeviceNode dn(dev); 188 | bool enabled = dn.IsEnabled(); 189 | ui.UIEnable(ID_DEVICE_ENABLE, !enabled); 190 | ui.UIEnable(ID_DEVICE_DISABLE, enabled); 191 | ui.UIEnable(ID_DEVICE_UNINSTALL, true); 192 | } 193 | else { 194 | ui.UIEnable(ID_DEVICE_ENABLE, false); 195 | ui.UIEnable(ID_DEVICE_DISABLE, false); 196 | ui.UIEnable(ID_DEVICE_UNINSTALL, false); 197 | } 198 | } 199 | 200 | void CDevNodeListView::OnPageActivated(bool active) { 201 | if (active && IsRefreshNeeded()) 202 | Refresh(); 203 | } 204 | 205 | LRESULT CDevNodeListView::OnEnableDisableDevice(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { 206 | auto& item = m_Items[m_List.GetSelectionMark()]; 207 | DeviceNode dn(item.Data.DevInst); 208 | auto result = dn.IsEnabled() ? dn.Disable() : dn.Enable(); 209 | return 0; 210 | } 211 | 212 | LRESULT CDevNodeListView::OnItemChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) { 213 | UpdateUI(GetFrame()->GetUI()); 214 | return 0; 215 | } 216 | 217 | LRESULT CDevNodeListView::OnDeviceProperties(WORD, WORD, HWND, BOOL&) { 218 | auto& item = m_Items[m_List.GetSelectionMark()]; 219 | Helpers::DisplayProperties(item.Description.c_str(), *m_dm, item); 220 | return 0; 221 | } 222 | 223 | -------------------------------------------------------------------------------- /DevExp/DevNodeListView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "VirtualListView.h" 4 | #include "DeviceManager.h" 5 | #include "ViewBase.h" 6 | #include "resource.h" 7 | 8 | class DeviceNode; 9 | 10 | class CDevNodeListView : 11 | public CViewBase, 12 | public CCustomDraw, 13 | public CVirtualListView { 14 | public: 15 | using CViewBase::CViewBase; 16 | DECLARE_WND_CLASS(nullptr) 17 | 18 | DWORD OnPrePaint(int, LPNMCUSTOMDRAW cd); 19 | DWORD OnItemPrePaint(int, LPNMCUSTOMDRAW cd); 20 | DWORD OnSubItemPrePaint(int, LPNMCUSTOMDRAW cd); 21 | 22 | void Refresh(); 23 | 24 | protected: 25 | BEGIN_MSG_MAP(CDevNodeListView) 26 | MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) 27 | NOTIFY_CODE_HANDLER(LVN_ITEMCHANGED, OnItemChanged) 28 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 29 | CHAIN_MSG_MAP(CVirtualListView) 30 | CHAIN_MSG_MAP(CCustomDraw) 31 | CHAIN_MSG_MAP(CViewBase) 32 | ALT_MSG_MAP(1) 33 | COMMAND_ID_HANDLER(ID_EDIT_COPY, OnCopy) 34 | COMMAND_ID_HANDLER(ID_VIEW_SHOWHIDDENDEVICES, OnShowHiddenDevices) 35 | COMMAND_ID_HANDLER(ID_DEVICE_PROPERTIES, OnDeviceProperties) 36 | COMMAND_ID_HANDLER(ID_VIEW_REFRESH, OnViewRefresh) 37 | COMMAND_ID_HANDLER(ID_DEVICE_ENABLE, OnEnableDisableDevice) 38 | COMMAND_ID_HANDLER(ID_DEVICE_DISABLE, OnEnableDisableDevice) 39 | END_MSG_MAP() 40 | 41 | CString GetColumnText(HWND, int row, int col); 42 | int GetRowImage(HWND, int row, int col); 43 | void DoSort(const SortInfo* si); 44 | bool OnRightClickList(HWND, int row, int col, POINT const& pt); 45 | bool OnDoubleClickList(HWND, int row, int col, POINT const&); 46 | 47 | // Handler prototypes (uncomment arguments if needed): 48 | // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 49 | // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 50 | // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) 51 | 52 | enum class ColumnType { 53 | Name, Class, ClassGuid, 54 | Status, Instance, Driver, Enumerator, PDOName, Parent, Depth 55 | }; 56 | 57 | // 58 | // CViewBase overridables 59 | // 60 | void UpdateUI(CUpdateUIBase& ui); 61 | void OnPageActivated(bool activate); 62 | 63 | private: 64 | 65 | struct DeviceItem : DeviceInfo { 66 | CString Class; 67 | int Image{ -1 }; 68 | }; 69 | 70 | CString const& GetDeviceClassName(DeviceItem& di); 71 | CString GetStringProperty(DeviceItem& item, DEVPROPKEY const& key); 72 | 73 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 74 | LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 75 | LRESULT OnCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 76 | LRESULT OnShowHiddenDevices(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 77 | LRESULT OnViewRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 78 | LRESULT OnEnableDisableDevice(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 79 | LRESULT OnItemChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/); 80 | LRESULT OnDeviceProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 81 | 82 | CListViewCtrl m_List; 83 | std::vector m_Items; 84 | std::unique_ptr m_dm; 85 | bool m_ShowHiddenDevices{ false }; 86 | }; 87 | -------------------------------------------------------------------------------- /DevExp/DevNodeView.cpp: -------------------------------------------------------------------------------- 1 | // View.cpp : implementation of the CView class 2 | // 3 | ///////////////////////////////////////////////////////////////////////////// 4 | 5 | #include "pch.h" 6 | #include "DevNodeView.h" 7 | #include "IconHelper.h" 8 | #include "Helpers.h" 9 | #include "SortHelper.h" 10 | #include "resource.h" 11 | #include "ClipboardHelper.h" 12 | #include "ListViewhelper.h" 13 | #include "AppSettings.h" 14 | #include "SecurityHelper.h" 15 | 16 | CString CDevNodeView::GetColumnText(HWND, int row, int col) { 17 | auto& item = m_Items[row]; 18 | switch (col) { 19 | case 0: return item.Name; 20 | case 1: return item.ValueAsString; 21 | case 2: return Helpers::GetPropertyDetails(item.Key, item.Value.get(), item.ValueSize); 22 | } 23 | return L""; 24 | } 25 | 26 | void CDevNodeView::DoSort(SortInfo const* si) { 27 | auto compare = [&](auto const& n1, auto const& n2) { 28 | return SortHelper::Sort(n1.Name, n2.Name, si->SortAscending); 29 | }; 30 | 31 | std::ranges::sort(m_Items, compare); 32 | } 33 | 34 | bool CDevNodeView::OnDoubleClickList(HWND, int row, int col, POINT const& pt) const { 35 | if (row < 0) 36 | return false; 37 | 38 | auto const& item = m_Items[row]; 39 | return Helpers::DisplayProperty(item.Key, DeviceNode(GetItemData(m_Tree, m_Tree.GetSelectedItem())), item.Name); 40 | } 41 | 42 | void CDevNodeView::OnTreeSelChanged(HWND, HTREEITEM hOld, HTREEITEM hNew) { 43 | auto inst = GetItemData(m_Tree, hNew); 44 | DeviceNode node(inst); 45 | m_Items.clear(); 46 | auto keys = node.GetPropertyKeys(); 47 | m_Items.reserve(keys.size() + 2); 48 | { 49 | Property p{}; 50 | p.ValueAsString = std::to_wstring(inst).c_str(); 51 | p.Name = L"Index"; 52 | m_Items.push_back(std::move(p)); 53 | } 54 | { 55 | Property p{}; 56 | p.Name = L"Depth"; 57 | p.ValueAsString = std::to_wstring(node.GetDepth()).c_str(); 58 | m_Items.push_back(std::move(p)); 59 | } 60 | for (auto& key : keys) { 61 | Property prop; 62 | prop.Key = key; 63 | prop.Value = m_DevMgr->GetPropertyValue(node, key, prop.Type, &prop.ValueSize); //node.GetPropertyValue(key, prop.Type, &prop.ValueSize); 64 | prop.ValueAsString = Helpers::GetPropertyValueAsString(prop.Value.get(), prop.Type, prop.ValueSize); 65 | prop.Name = Helpers::GetPropertyName(key); 66 | m_Items.push_back(std::move(prop)); 67 | } 68 | 69 | auto si = GetSortInfo(m_List); 70 | if (si) 71 | DoSort(si); 72 | m_List.SetItemCount((int)keys.size()); 73 | UpdateUI(GetFrame()->GetUI()); 74 | } 75 | 76 | bool CDevNodeView::OnTreeRightClick(HWND, HTREEITEM hItem, POINT const& pt) { 77 | m_Tree.SelectItem(hItem); 78 | CMenu menu; 79 | menu.LoadMenu(IDR_CONTEXT); 80 | auto cmd = GetFrame()->TrackPopupMenu(menu.GetSubMenu(0), TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y); 81 | LRESULT result; 82 | if (cmd) { 83 | ProcessWindowMessage(m_hWnd, WM_COMMAND, cmd, 0, result, 1); 84 | } 85 | return false; 86 | } 87 | 88 | bool CDevNodeView::OnTreeDoubleClick(HWND, HTREEITEM hItem) { 89 | LRESULT result; 90 | ProcessWindowMessage(m_hWnd, WM_COMMAND, ID_DEVICE_PROPERTIES, 0, result, 1); 91 | return true; 92 | } 93 | 94 | BOOL CDevNodeView::PreTranslateMessage(MSG* pMsg) { 95 | pMsg; 96 | return FALSE; 97 | } 98 | 99 | void CDevNodeView::UpdateUI(CUpdateUIBase& ui) { 100 | ui.UISetCheck(ID_VIEW_SHOWHIDDENDEVICES, m_ShowHiddenDevices); 101 | auto dev = GetItemData(m_Tree, m_Tree.GetSelectedItem()); 102 | ui.UIEnable(ID_DEVICE_PROPERTIES, dev < 0x8000 && m_Tree.GetSelectedItem() != m_Tree.GetRootItem()); 103 | int selected = m_List.GetSelectionMark(); 104 | if (SecurityHelper::IsRunningElevated()) { 105 | DeviceNode dn(dev); 106 | bool enabled = dn.IsEnabled(); 107 | ui.UIEnable(ID_DEVICE_ENABLE, !enabled); 108 | ui.UIEnable(ID_DEVICE_DISABLE, enabled); 109 | ui.UIEnable(ID_DEVICE_UNINSTALL, true); 110 | } 111 | else { 112 | ui.UIEnable(ID_DEVICE_ENABLE, false); 113 | ui.UIEnable(ID_DEVICE_DISABLE, false); 114 | ui.UIEnable(ID_DEVICE_UNINSTALL, false); 115 | } 116 | } 117 | 118 | void CDevNodeView::OnPageActivated(bool active) { 119 | if (active && IsRefreshNeeded()) 120 | BuildDevNodeTree(); 121 | if (active && m_Focus) 122 | ::SetFocus(m_Focus); 123 | } 124 | 125 | LRESULT CDevNodeView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { 126 | m_hWndClient = m_Splitter.Create(m_hWnd, rcDefault, nullptr, WS_CLIPCHILDREN | WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS); 127 | m_Tree.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | 128 | TVS_HASBUTTONS | TVS_HASLINES | TVS_SHOWSELALWAYS); 129 | m_Tree.SetExtendedStyle(TVS_EX_DOUBLEBUFFER, 0); 130 | 131 | CImageList images; 132 | images.Create(16, 16, ILC_COLOR32 | ILC_MASK, 64, 64); 133 | m_Tree.SetImageList(images); 134 | 135 | images.AddIcon(AtlLoadIconImage(IDI_DEVICES, 0, 16, 16)); 136 | 137 | m_List.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN 138 | | LVS_OWNERDATA | LVS_REPORT | LVS_SHOWSELALWAYS); 139 | m_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP); 140 | 141 | auto cm = GetColumnManager(m_List); 142 | cm->AddColumn(L"Property", LVCFMT_LEFT, 320, 0); 143 | cm->AddColumn(L"Value", LVCFMT_LEFT, 360, 1); 144 | cm->AddColumn(L"Details", LVCFMT_LEFT, 550, 2); 145 | cm->UpdateColumns(); 146 | 147 | m_Splitter.SetSplitterPosPct(30); 148 | m_Splitter.SetSplitterPanes(m_Tree, m_List); 149 | 150 | BuildDevNodeTree(); 151 | 152 | return 0; 153 | } 154 | 155 | LRESULT CDevNodeView::OnSetFocus(UINT, WPARAM, LPARAM, BOOL&) { 156 | if (m_Focus == nullptr) 157 | m_Tree.SetFocus(); 158 | return 0; 159 | } 160 | 161 | LRESULT CDevNodeView::OnCopy(WORD, WORD, HWND, BOOL&) { 162 | if (m_Focus == m_Tree) { 163 | auto hItem = m_Tree.GetSelectedItem(); 164 | if (hItem) { 165 | CString text; 166 | m_Tree.GetItemText(hItem, text); 167 | ClipboardHelper::CopyText(m_hWnd, text); 168 | return 0; 169 | } 170 | } 171 | else if (m_Focus == m_List) { 172 | CString text; 173 | for (auto i = m_List.GetNextItem(-1, LVIS_SELECTED); i >= 0; i = m_List.GetNextItem(i, LVIS_SELECTED)) { 174 | text += ListViewHelper::GetRowAsString(m_List, i); 175 | text += L"\n"; 176 | } 177 | ClipboardHelper::CopyText(m_hWnd, text.Left(text.GetLength() - 1)); 178 | } 179 | return 0; 180 | } 181 | 182 | LRESULT CDevNodeView::OnNotifySetFocus(int, LPNMHDR hdr, BOOL&) { 183 | m_Focus = hdr->hwndFrom; 184 | return 0; 185 | } 186 | 187 | LRESULT CDevNodeView::OnViewRefresh(WORD, WORD, HWND, BOOL&) { 188 | auto node = (DEVINST)m_Tree.GetItemData(m_Tree.GetSelectedItem()); 189 | BuildDevNodeTree(); 190 | auto hItem = FindItemByData(m_Tree, m_Tree.GetRootItem(), node); 191 | if (hItem) { 192 | m_Tree.SelectItem(hItem); 193 | m_Tree.EnsureVisible(hItem); 194 | m_Tree.SetFocus(); 195 | } 196 | return 0; 197 | } 198 | 199 | LRESULT CDevNodeView::OnShowHiddenDevices(WORD, WORD, HWND, BOOL&) { 200 | m_ShowHiddenDevices = !m_ShowHiddenDevices; 201 | GetFrame()->GetUI().UISetCheck(ID_VIEW_SHOWHIDDENDEVICES, m_ShowHiddenDevices); 202 | 203 | BuildDevNodeTree(); 204 | return 0; 205 | } 206 | 207 | void CDevNodeView::BuildDevNodeTree() { 208 | m_Tree.SetRedraw(FALSE); 209 | 210 | m_Tree.DeleteAllItems(); 211 | m_DevMgr = DeviceManager::Create(); 212 | m_Devices = m_DevMgr->EnumDevices(m_ShowHiddenDevices); 213 | auto root = DeviceManager::GetRootDeviceNode(); 214 | WCHAR name[MAX_COMPUTERNAME_LENGTH + 1]; 215 | DWORD size = _countof(name); 216 | auto ok = ::GetComputerName(name, &size); 217 | auto hRoot = InsertTreeItem(m_Tree, ok ? name : L"This PC", 0, root); 218 | BuildChildDevNodes(hRoot, root); 219 | m_Tree.Expand(hRoot, TVE_EXPAND); 220 | 221 | m_Tree.SetRedraw(TRUE); 222 | } 223 | 224 | void CDevNodeView::BuildChildDevNodes(HTREEITEM hParent, DeviceNode const& node) { 225 | auto showHidden = m_ShowHiddenDevices; 226 | 227 | for (auto& dn : node.GetChildren()) { 228 | int index = m_DevMgr->GetDeviceIndex(dn); 229 | if (index < 0) 230 | continue; 231 | auto icon = m_DevMgr->GetDeviceIcon(m_Devices[index]); 232 | int image = -1; 233 | if (icon) { 234 | image = m_Tree.GetImageList(TVSIL_NORMAL).AddIcon(icon); 235 | ::DestroyIcon(icon); 236 | } 237 | auto isHidden = (dn.GetStatus() & DeviceNodeStatus::NoShowInDeviceManager) == DeviceNodeStatus::NoShowInDeviceManager; 238 | if (showHidden || !isHidden) { 239 | auto hItem = InsertTreeItem(m_Tree, (dn.GetName() + (dn.IsEnabled() ? L"" : L" (Disabled)")).c_str(), image, dn, hParent, TVI_SORT); 240 | if(isHidden) 241 | m_Tree.SetItemState(hItem, TVIS_CUT, TVIS_CUT); 242 | BuildChildDevNodes(hItem, dn); 243 | } 244 | } 245 | } 246 | 247 | LRESULT CDevNodeView::OnEnableDisableDevice(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { 248 | auto selected = m_Tree.GetSelectedItem(); 249 | DeviceNode dn((DEVINST)m_Tree.GetItemData(selected)); 250 | auto result = dn.IsEnabled() ? dn.Disable() : dn.Enable(); 251 | if (result) { 252 | m_Tree.SetItemText(selected, dn.IsEnabled() ? dn.GetName().c_str() : (dn.GetName() + L" (Disabled)").c_str()); 253 | } 254 | return 0; 255 | } 256 | 257 | LRESULT CDevNodeView::OnViewProperties(WORD, WORD, HWND, BOOL&) { 258 | auto inst = (DEVINST)m_Tree.GetItemData(m_Tree.GetSelectedItem()); 259 | auto index = m_DevMgr->GetDeviceIndex(inst); 260 | CString name; 261 | m_Tree.GetItemText(m_Tree.GetSelectedItem(), name); 262 | Helpers::DisplayProperties(name, *m_DevMgr, m_Devices[index]); 263 | 264 | return 0; 265 | } 266 | -------------------------------------------------------------------------------- /DevExp/DevNodeView.h: -------------------------------------------------------------------------------- 1 | // View.h : interface of the CView class 2 | // 3 | ///////////////////////////////////////////////////////////////////////////// 4 | 5 | #pragma once 6 | 7 | #include "VirtualListView.h" 8 | #include "TreeViewHelper.h" 9 | #include "DeviceManager.h" 10 | #include "ViewBase.h" 11 | #include "resource.h" 12 | #include 13 | 14 | class DeviceNode; 15 | 16 | class CDevNodeView : 17 | public CViewBase, 18 | public CVirtualListView, 19 | public CCustomDraw, 20 | public CTreeViewHelper { 21 | public: 22 | using CViewBase::CViewBase; 23 | 24 | DECLARE_WND_CLASS(nullptr) 25 | 26 | // 27 | // list view callbacks 28 | // 29 | CString GetColumnText(HWND, int row, int col); 30 | bool IsSortable(HWND, int col) const { 31 | return col == 0; 32 | } 33 | void DoSort(SortInfo const*); 34 | bool OnDoubleClickList(HWND, int row, int col, POINT const& pt) const; 35 | 36 | // 37 | // tree view callbacks 38 | // 39 | void OnTreeSelChanged(HWND, HTREEITEM hOld, HTREEITEM hNew); 40 | bool OnTreeRightClick(HWND, HTREEITEM hItem, POINT const& pt); 41 | bool OnTreeDoubleClick(HWND, HTREEITEM hItem); 42 | 43 | BOOL PreTranslateMessage(MSG* pMsg); 44 | 45 | // 46 | // CViewBase overridables 47 | // 48 | void UpdateUI(CUpdateUIBase& ui); 49 | void OnPageActivated(bool active); 50 | 51 | BEGIN_MSG_MAP(CDevNodeView) 52 | MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) 53 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 54 | NOTIFY_CODE_HANDLER(NM_SETFOCUS, OnNotifySetFocus) 55 | CHAIN_MSG_MAP(CVirtualListView) 56 | CHAIN_MSG_MAP(CCustomDraw) 57 | CHAIN_MSG_MAP(CTreeViewHelper) 58 | CHAIN_MSG_MAP(CViewBase) 59 | ALT_MSG_MAP(1) 60 | COMMAND_ID_HANDLER(ID_EDIT_COPY, OnCopy) 61 | COMMAND_ID_HANDLER(ID_VIEW_REFRESH, OnViewRefresh) 62 | COMMAND_ID_HANDLER(ID_DEVICE_ENABLE, OnEnableDisableDevice) 63 | COMMAND_ID_HANDLER(ID_DEVICE_DISABLE, OnEnableDisableDevice) 64 | COMMAND_ID_HANDLER(ID_VIEW_SHOWHIDDENDEVICES, OnShowHiddenDevices) 65 | COMMAND_ID_HANDLER(ID_DEVICE_PROPERTIES, OnViewProperties) 66 | END_MSG_MAP() 67 | 68 | // Handler prototypes (uncomment arguments if needed): 69 | // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 70 | // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 71 | // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) 72 | 73 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 74 | LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 75 | LRESULT OnCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 76 | LRESULT OnShowHiddenDevices(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 77 | LRESULT OnNotifySetFocus(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/); 78 | LRESULT OnViewRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 79 | LRESULT OnEnableDisableDevice(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 80 | LRESULT OnViewProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 81 | 82 | private: 83 | struct Property { 84 | DEVPROPKEY Key; 85 | DEVPROPTYPE Type; 86 | CString Name; 87 | CString ValueAsString; 88 | std::unique_ptr Value; 89 | ULONG ValueSize; 90 | }; 91 | 92 | void BuildDevNodeTree(); 93 | void BuildChildDevNodes(HTREEITEM hParent, DeviceNode const& node); 94 | 95 | CListViewCtrl m_List; 96 | CTreeViewCtrl m_Tree; 97 | CCustomSplitterWindow m_Splitter; 98 | std::unique_ptr m_DevMgr; 99 | std::vector m_Devices; 100 | std::vector m_Items; 101 | HWND m_Focus{ nullptr }; 102 | bool m_ShowHiddenDevices{ false }; 103 | }; 104 | -------------------------------------------------------------------------------- /DevExp/DeviceClassesView.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DeviceClassesView.h" 3 | #include "Helpers.h" 4 | #include "resource.h" 5 | #include "SecurityHelper.h" 6 | #include "SortHelper.h" 7 | #include "ClipboardHelper.h" 8 | #include "ListViewhelper.h" 9 | #include 10 | 11 | CString CDeviceClassesView::GetColumnText(HWND, int row, int col) { 12 | auto& item = m_Items[row]; 13 | switch (static_cast(GetColumnManager(m_List)->GetColumnTag(col))) { 14 | case ColumnType::Name: return item.Name; 15 | case ColumnType::Value: return item.ValueAsString; 16 | case ColumnType::Details: return Helpers::GetPropertyDetails(item.Key, item.Value.get(), item.ValueSize); 17 | } 18 | ATLASSERT(false); 19 | return L""; 20 | } 21 | 22 | int CDeviceClassesView::GetRowImage(HWND h, int row, int col) { 23 | return 0; 24 | } 25 | 26 | void CDeviceClassesView::DoSort(SortInfo const* si) { 27 | auto compare = [&](auto const& n1, auto const& n2) { 28 | return SortHelper::Sort(n1.Name, n2.Name, si->SortAscending); 29 | }; 30 | 31 | std::sort(m_Items.begin(), m_Items.end(), compare); 32 | } 33 | 34 | LRESULT CDeviceClassesView::OnShowHiddenDevices(WORD, WORD, HWND, BOOL&) { 35 | m_ShowHiddenDevices = !m_ShowHiddenDevices; 36 | GetFrame()->GetUI().UISetCheck(ID_VIEW_SHOWHIDDENDEVICES, m_ShowHiddenDevices); 37 | 38 | Refresh(); 39 | return 0; 40 | } 41 | 42 | void CDeviceClassesView::Refresh() { 43 | m_Tree.SetRedraw(FALSE); 44 | auto selected = m_Tree.GetSelectedItem(); 45 | m_DataSelected = selected ? m_Tree.GetItemData(selected) : 0; 46 | 47 | CImageList images(DeviceManager::GetClassImageList()); 48 | auto images2 = images.Duplicate(); 49 | int computerIcon = images2.AddIcon(AtlLoadIconImage(IDI_DEVICES, 0, 16, 16)); 50 | m_Tree.DeleteAllItems(); 51 | m_Tree.SetImageList(images2); 52 | 53 | m_DevMgr = DeviceManager::Create(); 54 | m_Devices = m_DevMgr->EnumDevices(m_ShowHiddenDevices); 55 | auto root = DeviceManager::GetRootDeviceNode(); 56 | WCHAR name[MAX_COMPUTERNAME_LENGTH + 1]; 57 | DWORD size = _countof(name); 58 | auto ok = ::GetComputerName(name, &size); 59 | auto hRoot = InsertTreeItem(m_Tree, ok ? name : L"This PC", computerIcon, root); 60 | 61 | m_Guids.clear(); 62 | m_Guids.reserve(64); 63 | m_Classes = DeviceManager::EnumDeviceClassesGuids(); 64 | int c = 0; 65 | for (auto& guid : m_Classes) { 66 | auto hItem = InsertTreeItem(m_Tree, 67 | DeviceManager::GetDeviceClassDescription(guid).c_str(), 68 | DeviceManager::GetClassImageIndex(guid), 0x8000 + c, hRoot, TVI_SORT); 69 | if (m_DataSelected && m_Tree.GetItemData(hItem) == m_DataSelected) { 70 | m_Tree.SelectItem(hItem); 71 | m_DataSelected = 0; 72 | } 73 | 74 | c++; 75 | m_Guids.insert({ guid, hItem }); 76 | } 77 | for (auto& di : m_Devices) { 78 | if (auto it = m_Guids.find(di.Data.ClassGuid); it != m_Guids.end()) { 79 | auto hIcon = m_DevMgr->GetDeviceIcon(di); 80 | int image = -1; 81 | if (hIcon) { 82 | image = images2.AddIcon(hIcon); 83 | ::DestroyIcon(hIcon); 84 | } 85 | DeviceNode dn(di.Data.DevInst); 86 | auto isHidden = (dn.GetStatus() & DeviceNodeStatus::NoShowInDeviceManager) == DeviceNodeStatus::NoShowInDeviceManager; 87 | if (!isHidden || m_ShowHiddenDevices) { 88 | auto hItem = InsertTreeItem(m_Tree, (di.Description + (dn.IsEnabled() ? L"" : L" (Disabled)")).c_str(), image, di.Data.DevInst, it->second, TVI_SORT); 89 | if (m_DataSelected && m_Tree.GetItemData(hItem) == m_DataSelected) { 90 | m_Tree.SelectItem(hItem); 91 | m_DataSelected = 0; 92 | } 93 | if (isHidden) 94 | m_Tree.SetItemState(hItem, TVIS_CUT, TVIS_CUT); 95 | } 96 | } 97 | } 98 | 99 | if (!m_ShowEmptyClasses) { 100 | // 101 | // delete classes with no devices 102 | // 103 | for (auto& [_, hItem] : m_Guids) { 104 | if (m_Tree.GetChildItem(hItem) == nullptr) 105 | m_Tree.DeleteItem(hItem); 106 | } 107 | } 108 | m_Tree.Expand(hRoot, TVE_EXPAND); 109 | m_Tree.SetRedraw(TRUE); 110 | } 111 | 112 | LRESULT CDeviceClassesView::OnCreate(UINT, WPARAM, LPARAM, BOOL&) { 113 | m_hWndClient = m_Splitter.Create(m_hWnd, rcDefault, nullptr, WS_CLIPCHILDREN | WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS); 114 | m_Tree.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | 115 | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_HASLINES | TVS_SHOWSELALWAYS); 116 | m_Tree.SetExtendedStyle(TVS_EX_DOUBLEBUFFER, 0); 117 | 118 | m_List.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN 119 | | LVS_OWNERDATA | LVS_REPORT | LVS_SHOWSELALWAYS); 120 | m_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP); 121 | 122 | auto cm = GetColumnManager(m_List); 123 | cm->AddColumn(L"Property", LVCFMT_LEFT, 250, 0); 124 | cm->AddColumn(L"Value", LVCFMT_LEFT, 350, 1); 125 | cm->AddColumn(L"Details", LVCFMT_LEFT, 550, 2); 126 | cm->UpdateColumns(); 127 | 128 | m_Splitter.SetSplitterPosPct(25); 129 | m_Splitter.SetSplitterPanes(m_Tree, m_List); 130 | 131 | Refresh(); 132 | 133 | return 0; 134 | } 135 | 136 | void CDeviceClassesView::OnTreeSelChanged(HWND, HTREEITEM hOld, HTREEITEM hNew) { 137 | UpdateList(hNew); 138 | } 139 | 140 | void CDeviceClassesView::UpdateList(HTREEITEM hNew) { 141 | m_Items.clear(); 142 | auto inst = GetItemData(m_Tree, hNew); 143 | DeviceNode node(inst); 144 | bool device = inst < 0x8000; 145 | std::vector keys; 146 | GUID classGuid{ GUID_NULL }; 147 | if (device) { // device instance 148 | keys = node.GetPropertyKeys(); 149 | } 150 | else { 151 | // 152 | //device class 153 | // 154 | classGuid = m_Classes[inst - 0x8000]; 155 | keys = DeviceManager::GetDeviceClassPropertyKeys(classGuid); 156 | } 157 | 158 | m_Items.reserve(keys.size() + 1); 159 | if (device) { 160 | { 161 | Property p{}; 162 | p.ValueAsString = std::to_wstring(inst).c_str(); 163 | p.Name = L"Index"; 164 | m_Items.push_back(std::move(p)); 165 | } 166 | { 167 | Property p{}; 168 | p.ValueAsString = std::to_wstring(DeviceNode(inst).GetDepth()).c_str(); 169 | p.Name = L"Depth"; 170 | m_Items.push_back(std::move(p)); 171 | } 172 | } 173 | 174 | for (auto& key : keys) { 175 | Property prop; 176 | prop.Key = key; 177 | if (device) 178 | prop.Value = node.GetPropertyValue(key, prop.Type, &prop.ValueSize); 179 | else 180 | prop.Value = DeviceManager::GetClassPropertyValue(classGuid, key, prop.Type, &prop.ValueSize); 181 | 182 | prop.ValueAsString = Helpers::GetPropertyValueAsString(prop.Value.get(), prop.Type, prop.ValueSize); 183 | prop.Name = Helpers::GetPropertyName(key); 184 | m_Items.push_back(std::move(prop)); 185 | } 186 | 187 | auto si = GetSortInfo(m_List); 188 | if (si) 189 | DoSort(si); 190 | m_List.SetItemCount((int)keys.size()); 191 | UpdateUI(GetFrame()->GetUI()); 192 | } 193 | 194 | void CDeviceClassesView::OnPageActivated(bool active) { 195 | GetFrame()->GetUI().UIEnable(ID_VIEW_SHOWEMPTYCLASSES, active); 196 | } 197 | 198 | LRESULT CDeviceClassesView::OnShowEmptyClasses(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { 199 | m_ShowEmptyClasses = !m_ShowEmptyClasses; 200 | GetFrame()->GetUI().UISetCheck(ID_VIEW_SHOWEMPTYCLASSES, m_ShowEmptyClasses); 201 | Refresh(); 202 | return 0; 203 | } 204 | 205 | LRESULT CDeviceClassesView::OnSetFocus(UINT, WPARAM, LPARAM, BOOL&) { 206 | if (m_Focus == nullptr) 207 | m_Tree.SetFocus(); 208 | 209 | return 0; 210 | } 211 | 212 | LRESULT CDeviceClassesView::OnDeviceChange(UINT, WPARAM, LPARAM, BOOL&) { 213 | Refresh(); 214 | return 0; 215 | } 216 | 217 | LRESULT CDeviceClassesView::OnCopy(WORD, WORD, HWND, BOOL&) { 218 | if (m_Focus == m_Tree) { 219 | auto hItem = m_Tree.GetSelectedItem(); 220 | if (hItem) { 221 | CString text; 222 | m_Tree.GetItemText(hItem, text); 223 | ClipboardHelper::CopyText(m_hWnd, text); 224 | return 0; 225 | } 226 | } 227 | else if (m_Focus == m_List) { 228 | CString text; 229 | for (auto i = m_List.GetNextItem(-1, LVIS_SELECTED); i >= 0; i = m_List.GetNextItem(i, LVIS_SELECTED)) { 230 | text += ListViewHelper::GetRowAsString(m_List, i); 231 | text += L"\n"; 232 | } 233 | ClipboardHelper::CopyText(m_hWnd, text.Left(text.GetLength() - 1)); 234 | } 235 | return 0; 236 | } 237 | 238 | LRESULT CDeviceClassesView::OnItemChanged(int, LPNMHDR, BOOL&) { 239 | return 0; 240 | } 241 | 242 | LRESULT CDeviceClassesView::OnNotifySetFocus(int, LPNMHDR hdr, BOOL&) { 243 | m_Focus = hdr->hwndFrom; 244 | return 0; 245 | } 246 | 247 | LRESULT CDeviceClassesView::OnViewRefresh(WORD, WORD, HWND, BOOL&) { 248 | Refresh(); 249 | return 0; 250 | } 251 | 252 | LRESULT CDeviceClassesView::OnEnableDisableDevice(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { 253 | auto selected = m_Tree.GetSelectedItem(); 254 | DeviceNode dn((DEVINST)m_Tree.GetItemData(selected)); 255 | auto result = dn.IsEnabled() ? dn.Disable() : dn.Enable(); 256 | if (result) { 257 | m_Tree.SetItemText(selected, dn.IsEnabled() ? dn.GetName().c_str() : (dn.GetName() + L" (Disabled)").c_str()); 258 | UpdateList(selected); 259 | } 260 | return 0; 261 | } 262 | 263 | LRESULT CDeviceClassesView::OnDeviceProperties(WORD, WORD, HWND, BOOL&) { 264 | CString name; 265 | m_Tree.GetItemText(m_Tree.GetSelectedItem(), name); 266 | auto inst = (DEVINST)m_Tree.GetItemData(m_Tree.GetSelectedItem()); 267 | if (inst >= 0x8000) 268 | return 0; 269 | 270 | auto index = m_DevMgr->GetDeviceIndex(inst); 271 | Helpers::DisplayProperties(name, *m_DevMgr, m_Devices[index]); 272 | return 0; 273 | } 274 | 275 | LRESULT CDeviceClassesView::OnDeviceUninstall(WORD, WORD, HWND, BOOL&) { 276 | auto selected = m_Tree.GetSelectedItem(); 277 | auto inst = static_cast(m_Tree.GetItemData(selected)); 278 | auto& dev = m_DevMgr->GetDevice(m_DevMgr->GetDeviceIndex(inst)); 279 | if (::AtlMessageBox(m_hWnd, std::format(L"Uninstall {}?", dev.Description).c_str(), IDS_TITLE, MB_ICONWARNING | MB_OKCANCEL) == IDCANCEL) 280 | return 0; 281 | 282 | if (!::DiUninstallDevice(m_hWnd, m_DevMgr->InfoSet(), (PSP_DEVINFO_DATA)&dev.Data, 0, nullptr)) 283 | AtlMessageBox(m_hWnd, std::format(L"Failed to uninstall device {}.", dev.Description).c_str(), IDS_TITLE, MB_ICONERROR); 284 | 285 | return 0; 286 | } 287 | 288 | bool CDeviceClassesView::OnTreeRightClick(HWND, HTREEITEM hItem, POINT const& pt) { 289 | m_Tree.SelectItem(hItem); 290 | CMenu menu; 291 | menu.LoadMenu(IDR_CONTEXT); 292 | auto cmd = GetFrame()->TrackPopupMenu(menu.GetSubMenu(m_Tree.GetItemData(hItem) < 0x8000 ? 0 : 1), 293 | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y); 294 | LRESULT result; 295 | if (cmd) { 296 | ProcessWindowMessage(m_hWnd, WM_COMMAND, cmd, 0, result, 1); 297 | } 298 | return false; 299 | } 300 | 301 | bool CDeviceClassesView::OnRightClickList(HWND, int row, int col, CPoint const& pt) { 302 | CMenu menu; 303 | menu.LoadMenu(IDR_CONTEXT); 304 | return GetFrame()->TrackPopupMenu(menu.GetSubMenu(1), TPM_RIGHTBUTTON, pt.x, pt.y); 305 | } 306 | 307 | bool CDeviceClassesView::OnTreeDoubleClick(HWND, HTREEITEM hItem) { 308 | if (m_Tree.GetItemData(hItem) >= 0x8000) 309 | return false; 310 | 311 | LRESULT result; 312 | ProcessWindowMessage(m_hWnd, WM_COMMAND, ID_DEVICE_PROPERTIES, 0, result, 1); 313 | return true; 314 | } 315 | 316 | void CDeviceClassesView::UpdateUI(CUpdateUIBase& ui) { 317 | ui.UISetCheck(ID_VIEW_SHOWHIDDENDEVICES, m_ShowHiddenDevices); 318 | ui.UISetCheck(ID_VIEW_SHOWEMPTYCLASSES, m_ShowEmptyClasses); 319 | auto dev = GetItemData(m_Tree, m_Tree.GetSelectedItem()); 320 | ui.UIEnable(ID_DEVICE_PROPERTIES, dev < 0x8000 && m_Tree.GetSelectedItem() != m_Tree.GetRootItem()); 321 | 322 | int selected = m_List.GetSelectionMark(); 323 | if (SecurityHelper::IsRunningElevated()) { 324 | DeviceNode dn(dev); 325 | bool enabled = dn.IsEnabled(); 326 | ui.UIEnable(ID_DEVICE_ENABLE, !enabled); 327 | ui.UIEnable(ID_DEVICE_DISABLE, enabled); 328 | ui.UIEnable(ID_DEVICE_UNINSTALL, true); 329 | } 330 | else { 331 | ui.UIEnable(ID_DEVICE_ENABLE, false); 332 | ui.UIEnable(ID_DEVICE_DISABLE, false); 333 | ui.UIEnable(ID_DEVICE_UNINSTALL, false); 334 | } 335 | } 336 | 337 | bool CDeviceClassesView::OnDoubleClickList(HWND, int row, int col, POINT const& pt) const { 338 | if (row < 0) 339 | return false; 340 | 341 | auto const& item = m_Items[row]; 342 | return Helpers::DisplayProperty(item.Key, DeviceNode(GetItemData(m_Tree, m_Tree.GetSelectedItem())), item.Name); 343 | } 344 | -------------------------------------------------------------------------------- /DevExp/DeviceClassesView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ViewBase.h" 4 | #include "resource.h" 5 | #include 6 | #include "DeviceManager.h" 7 | #include 8 | #include 9 | 10 | class CDeviceClassesView : 11 | public CTreeViewHelper, 12 | public CViewBase, 13 | public CVirtualListView { 14 | public: 15 | using CViewBase::CViewBase; 16 | DECLARE_WND_CLASS(nullptr) 17 | 18 | void Refresh(); 19 | 20 | CString GetColumnText(HWND h, int row, int col); 21 | int GetRowImage(HWND h, int row, int col); 22 | void DoSort(SortInfo const* si); 23 | bool OnDoubleClickList(HWND, int row, int col, POINT const& pt) const; 24 | bool OnTreeDoubleClick(HWND, HTREEITEM hItem); 25 | 26 | protected: 27 | BEGIN_MSG_MAP(CDeviceClassesView) 28 | MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) 29 | NOTIFY_CODE_HANDLER(LVN_ITEMCHANGED, OnItemChanged) 30 | NOTIFY_CODE_HANDLER(NM_SETFOCUS, OnNotifySetFocus) 31 | MESSAGE_HANDLER(WM_DEVICECHANGE, OnDeviceChange) 32 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 33 | CHAIN_MSG_MAP(CVirtualListView) 34 | CHAIN_MSG_MAP(CTreeViewHelper) 35 | CHAIN_MSG_MAP(CViewBase) 36 | ALT_MSG_MAP(1) 37 | COMMAND_ID_HANDLER(ID_EDIT_COPY, OnCopy) 38 | COMMAND_ID_HANDLER(ID_VIEW_REFRESH, OnViewRefresh) 39 | COMMAND_ID_HANDLER(ID_VIEW_SHOWHIDDENDEVICES, OnShowHiddenDevices) 40 | COMMAND_ID_HANDLER(ID_VIEW_SHOWEMPTYCLASSES, OnShowEmptyClasses) 41 | COMMAND_ID_HANDLER(ID_DEVICE_PROPERTIES, OnDeviceProperties) 42 | COMMAND_ID_HANDLER(ID_DEVICE_ENABLE, OnEnableDisableDevice) 43 | COMMAND_ID_HANDLER(ID_DEVICE_DISABLE, OnEnableDisableDevice) 44 | COMMAND_ID_HANDLER(ID_DEVICE_UNINSTALL, OnDeviceUninstall) 45 | END_MSG_MAP() 46 | 47 | void OnTreeSelChanged(HWND, HTREEITEM hOld, HTREEITEM hNew); 48 | bool OnTreeRightClick(HWND, HTREEITEM hItem, POINT const& pt); 49 | bool OnRightClickList(HWND, int row, int col, CPoint const& pt); 50 | 51 | void OnPageActivated(bool active); 52 | void UpdateUI(CUpdateUIBase& ui); 53 | void UpdateList(HTREEITEM hNew); 54 | 55 | private: 56 | 57 | enum class ColumnType { 58 | Name, Value, Details 59 | }; 60 | 61 | struct Property { 62 | DEVPROPKEY Key; 63 | DEVPROPTYPE Type; 64 | CString Name; 65 | CString ValueAsString; 66 | std::unique_ptr Value; 67 | ULONG ValueSize; 68 | }; 69 | 70 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 71 | LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 72 | LRESULT OnDeviceChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 73 | LRESULT OnCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 74 | LRESULT OnItemChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/); 75 | LRESULT OnNotifySetFocus(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/); 76 | LRESULT OnViewRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 77 | LRESULT OnShowHiddenDevices(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 78 | LRESULT OnShowEmptyClasses(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 79 | LRESULT OnEnableDisableDevice(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 80 | LRESULT OnDeviceProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 81 | LRESULT OnDeviceUninstall(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 82 | 83 | CListViewCtrl m_List; 84 | CTreeViewCtrl m_Tree; 85 | CCustomSplitterWindow m_Splitter; 86 | std::vector m_Items; 87 | std::unique_ptr m_DevMgr; 88 | std::vector m_Devices; 89 | std::unordered_map m_Guids; 90 | std::vector m_Classes; 91 | HWND m_Focus{ nullptr }; 92 | ULONG_PTR m_DataSelected{ 0 }; 93 | bool m_ShowHiddenDevices{ false }; 94 | bool m_ShowEmptyClasses{ false }; 95 | }; 96 | -------------------------------------------------------------------------------- /DevExp/DeviceInterfacesView.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DeviceInterfacesView.h" 3 | #include "SortHelper.h" 4 | #include "Helpers.h" 5 | #include "ClipboardHelper.h" 6 | #include "ListViewhelper.h" 7 | #include "SecurityHelper.h" 8 | 9 | void CDeviceInterfacesView::Refresh() { 10 | m_Tree.SetRedraw(FALSE); 11 | 12 | CImageList images; 13 | images.Create(16, 16, ILC_COLOR32 | ILC_MASK, 32, 32); 14 | int computerIcon = images.AddIcon(AtlLoadIconImage(IDI_DEVICES, 0, 16, 16)); 15 | int ifaceIcon = images.AddIcon(AtlLoadIconImage(IDI_INTERFACE, 0, 16, 16)); 16 | m_Tree.SetImageList(images); 17 | 18 | m_Tree.DeleteAllItems(); 19 | m_DevMgr = DeviceManager::Create(); 20 | m_Devices = m_DevMgr->EnumDevices(m_ShowHiddenDevices); 21 | auto root = DeviceManager::GetRootDeviceNode(); 22 | WCHAR name[MAX_COMPUTERNAME_LENGTH + 1]; 23 | DWORD size = _countof(name); 24 | auto ok = ::GetComputerName(name, &size); 25 | auto hRoot = InsertTreeItem(m_Tree, ok ? name : L"This PC", computerIcon, root); 26 | 27 | m_Guids.clear(); 28 | m_Guids.reserve(64); 29 | m_Interfaces = DeviceManager::EnumDeviceInterfacesGuids(); 30 | int c = 0; 31 | for (auto& iface : m_Interfaces) { 32 | auto hInterface = InsertTreeItem(m_Tree, GetInterfaceName(iface), ifaceIcon, 0x8000 + c, hRoot, TVI_SORT); 33 | c++; 34 | auto mgr = DeviceManager::Create(nullptr, &iface, nullptr, InfoSetOptions::Present | InfoSetOptions::DeviceInterface); 35 | for (auto& di : mgr->EnumDevices(m_ShowHiddenDevices)) { 36 | auto hIcon = mgr->GetDeviceIcon(di); 37 | int image = -1; 38 | if (hIcon) { 39 | image = images.AddIcon(hIcon); 40 | ::DestroyIcon(hIcon); 41 | } 42 | auto isHidden = (DeviceNode(di.Data.DevInst).GetStatus() & DeviceNodeStatus::NoShowInDeviceManager) == DeviceNodeStatus::NoShowInDeviceManager; 43 | if (!isHidden || m_ShowHiddenDevices) { 44 | auto hItem = InsertTreeItem(m_Tree, di.Description.c_str(), image, di.Data.DevInst, hInterface, TVI_SORT); 45 | if (isHidden) 46 | m_Tree.SetItemState(hItem, TVIS_CUT, TVIS_CUT); 47 | } 48 | } 49 | if (!m_ShowEmptyClasses && m_Tree.GetChildItem(hInterface) == nullptr) 50 | m_Tree.DeleteItem(hInterface); 51 | } 52 | 53 | m_Tree.Expand(hRoot, TVE_EXPAND); 54 | m_Tree.SelectItem(hRoot); 55 | 56 | m_Tree.SetRedraw(TRUE); 57 | m_Tree.EnsureVisible(hRoot); 58 | } 59 | 60 | CString CDeviceInterfacesView::GetInterfaceName(GUID const& guid) { 61 | return Helpers::DeviceInterfaceToString(guid); 62 | } 63 | 64 | LRESULT CDeviceInterfacesView::OnNotifySetFocus(int, LPNMHDR hdr, BOOL&) { 65 | m_Focus = hdr->hwndFrom; 66 | return 0; 67 | } 68 | 69 | LRESULT CDeviceInterfacesView::OnCreate(UINT, WPARAM, LPARAM, BOOL&) { 70 | m_hWndClient = m_Splitter.Create(m_hWnd, rcDefault, nullptr, WS_CLIPCHILDREN | WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS); 71 | m_Tree.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | 72 | TVS_HASBUTTONS | TVS_HASLINES | TVS_SHOWSELALWAYS); 73 | m_Tree.SetExtendedStyle(TVS_EX_DOUBLEBUFFER, 0); 74 | 75 | m_List.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN 76 | | LVS_OWNERDATA | LVS_REPORT | LVS_SHOWSELALWAYS); 77 | m_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP); 78 | 79 | auto cm = GetColumnManager(m_List); 80 | cm->AddColumn(L"Property", LVCFMT_LEFT, 250, 0); 81 | cm->AddColumn(L"Value", LVCFMT_LEFT, 350, 1); 82 | cm->AddColumn(L"Details", LVCFMT_LEFT, 550, 2); 83 | cm->UpdateColumns(); 84 | 85 | m_Splitter.SetSplitterPosPct(25); 86 | m_Splitter.SetSplitterPanes(m_Tree, m_List); 87 | 88 | Refresh(); 89 | 90 | return 0; 91 | } 92 | 93 | CString CDeviceInterfacesView::GetColumnText(HWND, int row, int col) { 94 | auto& item = m_Items[row]; 95 | switch (static_cast(GetColumnManager(m_List)->GetColumnTag(col))) { 96 | case ColumnType::Name: return item.Name; 97 | case ColumnType::Value: return item.ValueAsString; 98 | case ColumnType::Details: return Helpers::GetPropertyDetails(item.Key, item.Value.get(), item.ValueSize); 99 | } 100 | ATLASSERT(false); 101 | return L""; 102 | } 103 | 104 | LRESULT CDeviceInterfacesView::OnSetFocus(UINT, WPARAM, LPARAM, BOOL&) { 105 | if(m_Focus == nullptr) 106 | m_Tree.SetFocus(); 107 | return 0; 108 | } 109 | 110 | void CDeviceInterfacesView::DoSort(const SortInfo* si) { 111 | auto compare = [&](auto const& n1, auto const& n2) { 112 | return SortHelper::Sort(n1.Name, n2.Name, si->SortAscending); 113 | }; 114 | 115 | std::sort(m_Items.begin(), m_Items.end(), compare); 116 | } 117 | 118 | LRESULT CDeviceInterfacesView::OnShowHiddenDevices(WORD, WORD, HWND, BOOL&) { 119 | m_ShowHiddenDevices = !m_ShowHiddenDevices; 120 | GetFrame()->GetUI().UISetCheck(ID_VIEW_SHOWHIDDENDEVICES, m_ShowHiddenDevices); 121 | 122 | Refresh(); 123 | return 0; 124 | } 125 | 126 | void CDeviceInterfacesView::OnTreeSelChanged(HWND, HTREEITEM hOld, HTREEITEM hNew) { 127 | m_Items.clear(); 128 | auto inst = GetItemData(m_Tree, hNew); 129 | DeviceNode node(inst); 130 | bool device = inst < 0x8000; 131 | std::vector keys; 132 | GUID classGuid{ GUID_NULL }; 133 | if (device) { // device instance 134 | keys = node.GetPropertyKeys(); 135 | } 136 | else { 137 | // 138 | // device interface 139 | // 140 | classGuid = m_Interfaces[inst - 0x8000]; 141 | keys = DeviceManager::GetDeviceInterfacePropertyKeys(classGuid); 142 | } 143 | 144 | m_Items.reserve(keys.size() + 1); 145 | if (device) { 146 | Property p{}; 147 | p.ValueAsString = std::to_wstring(inst).c_str(); 148 | p.Name = L"Index"; 149 | m_Items.push_back(std::move(p)); 150 | } 151 | 152 | for (auto& key : keys) { 153 | Property prop; 154 | prop.Key = key; 155 | if (device) 156 | prop.Value = node.GetPropertyValue(key, prop.Type, &prop.ValueSize); 157 | else 158 | prop.Value = DeviceManager::GetClassPropertyValue(classGuid, key, prop.Type, &prop.ValueSize, true); 159 | 160 | prop.ValueAsString = Helpers::GetPropertyValueAsString(prop.Value.get(), prop.Type, prop.ValueSize); 161 | prop.Name = Helpers::GetPropertyName(key); 162 | m_Items.push_back(std::move(prop)); 163 | } 164 | 165 | auto si = GetSortInfo(m_List); 166 | if (si) 167 | DoSort(si); 168 | m_List.SetItemCount((int)keys.size()); 169 | UpdateUI(GetFrame()->GetUI()); 170 | } 171 | 172 | bool CDeviceInterfacesView::OnTreeDoubleClick(HWND, HTREEITEM hItem) { 173 | if (m_Tree.GetItemData(hItem) >= 0x8000) 174 | return false; 175 | 176 | LRESULT result; 177 | ProcessWindowMessage(m_hWnd, WM_COMMAND, ID_DEVICE_PROPERTIES, 0, result, 1); 178 | return true; 179 | } 180 | 181 | void CDeviceInterfacesView::OnPageActivated(bool active) { 182 | GetFrame()->GetUI().UIEnable(ID_VIEW_SHOWEMPTYCLASSES, active); 183 | } 184 | 185 | LRESULT CDeviceInterfacesView::OnShowEmptyClasses(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { 186 | m_ShowEmptyClasses = !m_ShowEmptyClasses; 187 | GetFrame()->GetUI().UISetCheck(ID_VIEW_SHOWEMPTYCLASSES, m_ShowEmptyClasses); 188 | Refresh(); 189 | return 0; 190 | } 191 | 192 | void CDeviceInterfacesView::UpdateUI(CUpdateUIBase& ui) { 193 | ui.UISetCheck(ID_VIEW_SHOWHIDDENDEVICES, m_ShowHiddenDevices); 194 | ui.UISetCheck(ID_VIEW_SHOWEMPTYCLASSES, m_ShowEmptyClasses); 195 | auto dev = GetItemData(m_Tree, m_Tree.GetSelectedItem()); 196 | ui.UIEnable(ID_DEVICE_PROPERTIES, dev < 0x8000 && m_Tree.GetSelectedItem() != m_Tree.GetRootItem()); 197 | int selected = m_List.GetSelectionMark(); 198 | if (SecurityHelper::IsRunningElevated()) { 199 | DeviceNode dn(dev); 200 | bool enabled = dn.IsEnabled(); 201 | ui.UIEnable(ID_DEVICE_ENABLE, !enabled); 202 | ui.UIEnable(ID_DEVICE_DISABLE, enabled); 203 | ui.UIEnable(ID_DEVICE_DISABLE, enabled); 204 | ui.UIEnable(ID_DEVICE_UNINSTALL, true); 205 | } 206 | else { 207 | ui.UIEnable(ID_DEVICE_ENABLE, false); 208 | ui.UIEnable(ID_DEVICE_DISABLE, false); 209 | ui.UIEnable(ID_DEVICE_UNINSTALL, false); 210 | } 211 | } 212 | 213 | LRESULT CDeviceInterfacesView::OnCopy(WORD, WORD, HWND, BOOL&) { 214 | if (m_Focus == m_Tree) { 215 | auto hItem = m_Tree.GetSelectedItem(); 216 | if (hItem) { 217 | CString text; 218 | m_Tree.GetItemText(hItem, text); 219 | ClipboardHelper::CopyText(m_hWnd, text); 220 | return 0; 221 | } 222 | } 223 | else if (m_Focus == m_List) { 224 | CString text; 225 | for (auto i = m_List.GetNextItem(-1, LVIS_SELECTED); i >= 0; i = m_List.GetNextItem(i, LVIS_SELECTED)) { 226 | text += ListViewHelper::GetRowAsString(m_List, i); 227 | text += L"\n"; 228 | } 229 | ClipboardHelper::CopyText(m_hWnd, text.Left(text.GetLength() - 1)); 230 | } 231 | return 0; 232 | } 233 | 234 | LRESULT CDeviceInterfacesView::OnItemChanged(int, LPNMHDR, BOOL&) { 235 | return LRESULT(); 236 | } 237 | 238 | LRESULT CDeviceInterfacesView::OnViewRefresh(WORD, WORD, HWND, BOOL&) { 239 | Refresh(); 240 | return 0; 241 | } 242 | 243 | bool CDeviceInterfacesView::OnRightClickList(HWND, int row, int col, CPoint const& pt) { 244 | CMenu menu; 245 | menu.LoadMenu(IDR_CONTEXT); 246 | return GetFrame()->TrackPopupMenu(menu.GetSubMenu(1), TPM_RIGHTBUTTON, pt.x, pt.y); 247 | } 248 | 249 | bool CDeviceInterfacesView::OnDoubleClickList(HWND, int row, int col, POINT const& pt) const { 250 | if (row < 0) 251 | return false; 252 | 253 | auto const& item = m_Items[row]; 254 | return Helpers::DisplayProperty(item.Key, DeviceNode(GetItemData(m_Tree, m_Tree.GetSelectedItem())), item.Name); 255 | } 256 | 257 | LRESULT CDeviceInterfacesView::OnDeviceProperties(WORD, WORD, HWND, BOOL&) { 258 | CString name; 259 | m_Tree.GetItemText(m_Tree.GetSelectedItem(), name); 260 | auto inst = (DEVINST)m_Tree.GetItemData(m_Tree.GetSelectedItem()); 261 | if (inst >= 0x8000) 262 | return 0; 263 | 264 | auto index = m_DevMgr->GetDeviceIndex(inst); 265 | ATLASSERT(index >= 0); 266 | 267 | Helpers::DisplayProperties(name, *m_DevMgr, m_Devices[index]); 268 | return 0; 269 | } 270 | 271 | bool CDeviceInterfacesView::OnTreeRightClick(HWND, HTREEITEM hItem, POINT const& pt) { 272 | m_Tree.SelectItem(hItem); 273 | if (m_Tree.GetItemData(hItem) >= 0x8000) 274 | return false; 275 | 276 | CMenu menu; 277 | menu.LoadMenu(IDR_CONTEXT); 278 | auto cmd = GetFrame()->TrackPopupMenu(menu.GetSubMenu(m_Tree.GetItemData(hItem) < 0x8000 ? 0 : 1), 279 | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y); 280 | LRESULT result; 281 | if (cmd) { 282 | ProcessWindowMessage(m_hWnd, WM_COMMAND, cmd, 0, result, 1); 283 | } 284 | return false; 285 | } 286 | -------------------------------------------------------------------------------- /DevExp/DeviceInterfacesView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ViewBase.h" 4 | #include "resource.h" 5 | #include "VirtualListView.h" 6 | #include "DeviceManager.h" 7 | #include "TreeViewHelper.h" 8 | #include "CustomSplitterWindow.h" 9 | 10 | class CDeviceInterfacesView : 11 | public CTreeViewHelper, 12 | public CViewBase, 13 | public CVirtualListView { 14 | public: 15 | using CViewBase::CViewBase; 16 | DECLARE_WND_CLASS(nullptr) 17 | 18 | CString GetColumnText(HWND h, int row, int col); 19 | //int GetRowImage(HWND h, int row, int col); 20 | void DoSort(const SortInfo* si); 21 | bool OnRightClickList(HWND, int row, int col, CPoint const& pt); 22 | bool OnDoubleClickList(HWND, int row, int col, POINT const& pt) const; 23 | bool OnTreeDoubleClick(HWND, HTREEITEM hItem); 24 | bool OnTreeRightClick(HWND, HTREEITEM hItem, POINT const& pt); 25 | 26 | protected: 27 | BEGIN_MSG_MAP(CDeviceInterfacesView) 28 | MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) 29 | NOTIFY_CODE_HANDLER(LVN_ITEMCHANGED, OnItemChanged) 30 | NOTIFY_CODE_HANDLER(NM_SETFOCUS, OnNotifySetFocus) 31 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 32 | CHAIN_MSG_MAP(CVirtualListView) 33 | CHAIN_MSG_MAP(CTreeViewHelper) 34 | CHAIN_MSG_MAP(CViewBase) 35 | ALT_MSG_MAP(1) 36 | COMMAND_ID_HANDLER(ID_DEVICE_PROPERTIES, OnDeviceProperties) 37 | COMMAND_ID_HANDLER(ID_EDIT_COPY, OnCopy) 38 | COMMAND_ID_HANDLER(ID_VIEW_REFRESH, OnViewRefresh) 39 | COMMAND_ID_HANDLER(ID_VIEW_SHOWHIDDENDEVICES, OnShowHiddenDevices) 40 | COMMAND_ID_HANDLER(ID_VIEW_SHOWEMPTYCLASSES, OnShowEmptyClasses) 41 | END_MSG_MAP() 42 | 43 | void OnTreeSelChanged(HWND, HTREEITEM hOld, HTREEITEM hNew); 44 | void OnPageActivated(bool active); 45 | void UpdateUI(CUpdateUIBase& ui); 46 | 47 | private: 48 | enum class ColumnType { 49 | Name, Value, Details 50 | }; 51 | 52 | struct Property { 53 | DEVPROPKEY Key; 54 | DEVPROPTYPE Type; 55 | CString Name; 56 | CString ValueAsString; 57 | std::unique_ptr Value; 58 | ULONG ValueSize; 59 | }; 60 | 61 | void Refresh(); 62 | static CString GetInterfaceName(GUID const& info); 63 | 64 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 65 | LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 66 | LRESULT OnCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 67 | LRESULT OnItemChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/); 68 | LRESULT OnViewRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 69 | LRESULT OnShowHiddenDevices(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 70 | LRESULT OnShowEmptyClasses(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 71 | LRESULT OnNotifySetFocus(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/); 72 | LRESULT OnDeviceProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 73 | 74 | CListViewCtrl m_List; 75 | CTreeViewCtrl m_Tree; 76 | CCustomSplitterWindow m_Splitter; 77 | std::vector m_Items; 78 | std::unique_ptr m_DevMgr; 79 | std::vector m_Devices; 80 | std::unordered_map m_Guids; 81 | std::vector m_Interfaces; 82 | HWND m_Focus{ nullptr }; 83 | bool m_ShowHiddenDevices{ false }; 84 | bool m_ShowEmptyClasses{ false }; 85 | }; 86 | -------------------------------------------------------------------------------- /DevExp/DriversPropertyPage.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DriversPropertyPage.h" 3 | #include "Helpers.h" 4 | 5 | CDriversPropertyPage::CDriversPropertyPage(std::vector const& drivers) 6 | : CPropertyPageImpl(L"Drivers"), m_Items(drivers) { 7 | } 8 | 9 | CString CDriversPropertyPage::GetColumnText(HWND, int row, int col) const { 10 | auto& item = m_Items[row]; 11 | switch (col) { 12 | case 0: return Helpers::FormatDate(item.DriverDate).c_str(); 13 | case 1: return item.Description.c_str(); 14 | } 15 | return CString(); 16 | } 17 | 18 | int CDriversPropertyPage::GetRowImage(HWND, int row, int) const { 19 | return 0; 20 | } 21 | 22 | void CDriversPropertyPage::OnStateChanged(HWND, int from, int to, UINT oldState, UINT newState) { 23 | if (newState & LVIS_SELECTED) { 24 | auto& item = m_Items[from]; 25 | SetDlgItemText(IDC_MFG, item.ManufactorName.c_str()); 26 | } 27 | } 28 | 29 | LRESULT CDriversPropertyPage::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { 30 | m_List.Attach(GetDlgItem(IDC_LIST)); 31 | m_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP); 32 | m_List.SetItemCount((int)m_Items.size()); 33 | 34 | auto cm = GetColumnManager(m_List); 35 | cm->AddColumn(L"Date", LVCFMT_LEFT, 100); 36 | cm->AddColumn(L"File Path", LVCFMT_LEFT | LVCFMT_FILL, 300); 37 | cm->UpdateColumns(); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /DevExp/DriversPropertyPage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "resource.h" 4 | #include 5 | #include "DeviceManager.h" 6 | 7 | class CDriversPropertyPage : 8 | public CPropertyPageImpl, 9 | public CVirtualListView< CDriversPropertyPage> { 10 | public: 11 | enum { IDD = IDD_PROP_DRIVERS }; 12 | 13 | explicit CDriversPropertyPage(std::vector const& drivers); 14 | 15 | CString GetColumnText(HWND, int row, int col) const; 16 | int GetRowImage(HWND, int row, int) const; 17 | void OnStateChanged(HWND, int from, int to, UINT oldState, UINT newState); 18 | 19 | BEGIN_MSG_MAP(CDriversPropertyPage) 20 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) 21 | CHAIN_MSG_MAP(CVirtualListView) 22 | END_MSG_MAP() 23 | 24 | // Handler prototypes (uncomment arguments if needed): 25 | // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 26 | // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 27 | // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) 28 | 29 | LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 30 | 31 | private: 32 | CListViewCtrl m_List; 33 | std::vector const& m_Items; 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /DevExp/DriversView.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DriversView.h" 3 | #include 4 | #include "Helpers.h" 5 | #include 6 | #include 7 | 8 | void CDriversView::UpdateUI(CUpdateUIBase& ui) { 9 | } 10 | 11 | void CDriversView::UpdateUI() { 12 | int selected = m_List.GetSelectedIndex(); 13 | auto& item = m_Drivers[selected < 0 ? 0 : selected]; 14 | UIEnable(ID_DRIVER_START, selected >= 0 && item.State == DriverState::Stopped); 15 | UIEnable(ID_DRIVER_STOP, selected >= 0 && item.State == DriverState::Running); 16 | } 17 | 18 | LRESULT CDriversView::OnStartStopDriver(WORD, WORD id, HWND, BOOL&) { 19 | int selected = m_List.GetSelectedIndex(); 20 | ATLASSERT(selected >= 0); 21 | auto& item = m_Drivers[selected]; 22 | struct Data { 23 | HWND hWnd; 24 | std::wstring Name; 25 | bool Start; 26 | }; 27 | auto data = new Data{ m_hWnd, item.Name, id == ID_DRIVER_START }; 28 | ::TrySubmitThreadpoolCallback([](auto, auto param) { 29 | auto d = (Data*)param; 30 | auto ok = d->Start ? DriverManager::Start(d->Name) : DriverManager::Stop(d->Name); 31 | ::SendMessage(d->hWnd, WM_UPDATEDRIVER, ok ? 0 : ::GetLastError(), reinterpret_cast(d->Name.c_str())); 32 | delete d; 33 | }, data, nullptr); 34 | 35 | return 0; 36 | } 37 | 38 | LRESULT CDriversView::OnUpdateDriver(UINT, WPARAM wp, LPARAM lp, BOOL&) { 39 | if (wp) { 40 | AtlMessageBox(m_hWnd, L"Error encountered.", IDS_TITLE, MB_ICONERROR); 41 | } 42 | else { 43 | Refresh(); 44 | UpdateUI(); 45 | } 46 | return 0; 47 | } 48 | 49 | LRESULT CDriversView::OnCreate(UINT, WPARAM, LPARAM, BOOL&) { 50 | ToolBarButtonInfo buttons[] = { 51 | { ID_DRIVER_START, IDI_GO, 0, L"Start" }, 52 | { ID_DRIVER_STOP, IDI_STOP, 0, L"Stop" }, 53 | }; 54 | CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE); 55 | auto tb = ToolbarHelper::CreateAndInitToolBar(m_hWnd, buttons, _countof(buttons), 16); 56 | AddSimpleReBarBand(tb); 57 | UIAddToolBar(tb); 58 | CReBarCtrl rb(m_hWndToolBar); 59 | rb.LockBands(true); 60 | 61 | struct { 62 | UINT id, icon; 63 | } cmds[] = { 64 | { ID_DRIVER_START, IDI_GO }, 65 | { ID_DRIVER_STOP, IDI_STOP }, 66 | }; 67 | for (auto& cmd : cmds) { 68 | AddCommand(cmd.id, AtlLoadIconImage(cmd.icon, 0, 16, 16)); 69 | } 70 | UIAddMenu(IDR_CONTEXT); 71 | 72 | m_hWndClient = m_List.Create(m_hWnd, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN 73 | | LVS_OWNERDATA | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL); 74 | m_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP | LVS_EX_SUBITEMIMAGES); 75 | CImageList images; 76 | images.Create(16, 16, ILC_COLOR32 | ILC_MASK, 64, 32); 77 | UINT icons[] = { IDI_DRIVER, IDI_DRIVER_KMDF, IDI_DRIVER_UMDF, IDI_GO, IDI_STOP }; 78 | for (auto icon : icons) 79 | images.AddIcon(AtlLoadIconImage(icon, 0, 16, 16)); 80 | 81 | m_List.SetImageList(images, LVSIL_SMALL); 82 | 83 | auto cm = GetColumnManager(m_List); 84 | cm->AddColumn(L"Name", LVCFMT_LEFT, 150, ColumnType::Name); 85 | cm->AddColumn(L"Display Name", LVCFMT_LEFT, 250, ColumnType::DisplayName); 86 | cm->AddColumn(L"Type", LVCFMT_LEFT, 100, ColumnType::Type); 87 | cm->AddColumn(L"State", LVCFMT_LEFT, 80, ColumnType::State); 88 | cm->AddColumn(L"Start", LVCFMT_LEFT, 80, ColumnType::StartType); 89 | cm->AddColumn(L"Error Control", LVCFMT_LEFT, 90, ColumnType::ErrorControl); 90 | cm->AddColumn(L"Image Path", LVCFMT_LEFT, 350, ColumnType::ImagePath); 91 | cm->AddColumn(L"WDF Ver", LVCFMT_RIGHT, 70, ColumnType::WDFVersion); 92 | 93 | auto pLoop = _Module.GetMessageLoop(); 94 | pLoop->AddIdleHandler(this); 95 | 96 | Refresh(); 97 | 98 | return 0; 99 | } 100 | 101 | LRESULT CDriversView::OnDestroy(UINT, WPARAM, LPARAM, BOOL&) { 102 | _Module.GetMessageLoop()->RemoveIdleHandler(this); 103 | return 0; 104 | } 105 | 106 | LRESULT CDriversView::OnSetFocus(UINT, WPARAM, LPARAM, BOOL&) { 107 | m_List.SetFocus(); 108 | UpdateUI(); 109 | 110 | return 0; 111 | } 112 | 113 | LRESULT CDriversView::OnCopy(WORD, WORD, HWND, BOOL&) { 114 | CString text; 115 | for (auto i = m_List.GetNextItem(-1, LVIS_SELECTED); i >= 0; i = m_List.GetNextItem(i, LVIS_SELECTED)) { 116 | text += ListViewHelper::GetRowAsString(m_List, i); 117 | text += L"\n"; 118 | } 119 | ClipboardHelper::CopyText(m_hWnd, text.Left(text.GetLength() - 1)); 120 | return 0; 121 | } 122 | 123 | LRESULT CDriversView::OnViewRefresh(WORD, WORD, HWND, BOOL&) { 124 | Refresh(); 125 | return 0; 126 | } 127 | 128 | void CDriversView::OnStateChanged(HWND, int from, int to, UINT oldState, UINT newState) { 129 | if(newState & LVIS_SELECTED) 130 | UpdateUI(); 131 | } 132 | 133 | bool CDriversView::OnRightClickList(HWND, int row, int col, POINT const& pt) { 134 | CMenu menu; 135 | menu.LoadMenu(IDR_CONTEXT); 136 | return ShowContextMenu(menu.GetSubMenu(2), 0, pt.x, pt.y); 137 | } 138 | 139 | void CDriversView::Refresh() { 140 | bool empty = m_Drivers.empty(); 141 | m_Drivers.Set(DriverManager::EnumKernelDrivers()); 142 | if (!empty) 143 | Sort(m_List); 144 | m_List.SetItemCountEx((int)m_Drivers.size(), LVSICF_NOSCROLL); 145 | } 146 | 147 | BOOL CDriversView::OnIdle() { 148 | UIUpdateToolBar(); 149 | return FALSE; 150 | } 151 | 152 | CString CDriversView::GetColumnText(HWND, int row, int col) { 153 | auto& item = m_Drivers[row]; 154 | 155 | switch (GetColumnManager(m_List)->GetColumnTag(col)) { 156 | case ColumnType::Name: return item.Name.c_str(); 157 | case ColumnType::DisplayName: return item.DisplayName.c_str(); 158 | case ColumnType::ImagePath: return item.ImagePath.c_str(); 159 | case ColumnType::State: return Helpers::DriverStateToString(item.State); 160 | case ColumnType::Type: return Helpers::DriverTypeToString(item.Type).c_str(); 161 | case ColumnType::StartType: return Helpers::DriverStartTypeToString(item.StartType); 162 | case ColumnType::WDFVersion: return item.MajorVersion == 0 ? L"" : std::format(L"{}.{:02}", item.MajorVersion, item.MinorVersion).c_str(); 163 | case ColumnType::ErrorControl: return Helpers::DriverErrorControlToString(item.ErrorControl); 164 | } 165 | return CString(); 166 | } 167 | 168 | int CDriversView::GetRowImage(HWND h, int row, int col) { 169 | auto& item = m_Drivers[row]; 170 | if (col == 0) { 171 | if ((item.Type & DeviceDriverType::KMDF) == DeviceDriverType::KMDF) 172 | return 1; 173 | if ((item.Type & DeviceDriverType::UMDF) == DeviceDriverType::UMDF) 174 | return 2; 175 | return 0; 176 | } 177 | if (GetColumnManager(h)->GetColumnTag(col) == ColumnType::State) 178 | return item.State == DriverState::Running ? 3 : 4; 179 | return -1; 180 | } 181 | 182 | void CDriversView::DoSort(const SortInfo* si) { 183 | auto asc = si->SortAscending; 184 | auto col = GetColumnManager(si->hWnd)->GetColumnTag(si->SortColumn); 185 | auto compare = [&](auto const& d1, auto const& d2) { 186 | switch (col) { 187 | case ColumnType::Name: return SortHelper::Sort(d1.Name, d2.Name, asc); 188 | case ColumnType::DisplayName: return SortHelper::Sort(d1.DisplayName, d2.DisplayName, asc); 189 | case ColumnType::StartType: return SortHelper::Sort(d1.StartType, d2.StartType, asc); 190 | case ColumnType::ImagePath: return SortHelper::Sort(d1.ImagePath, d2.ImagePath, asc); 191 | case ColumnType::State: return SortHelper::Sort(d1.State, d2.State, asc); 192 | case ColumnType::ErrorControl: return SortHelper::Sort(d1.ErrorControl, d2.ErrorControl, asc); 193 | case ColumnType::WDFVersion: return SortHelper::Sort(d1.MajorVersion * 100 + d1.MinorVersion, d2.MajorVersion * 100 + d2.MinorVersion, asc); 194 | } 195 | return false; 196 | }; 197 | m_Drivers.Sort(compare); 198 | } 199 | 200 | int CDriversView::GetSaveColumnRange(HWND, int&) const { 201 | return 1; 202 | } 203 | -------------------------------------------------------------------------------- /DevExp/DriversView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "VirtualListView.h" 4 | #include "DeviceManager.h" 5 | #include "ViewBase.h" 6 | #include "resource.h" 7 | #include "SortedFilteredVector.h" 8 | #include "DriverManager.h" 9 | #include 10 | 11 | class DeviceNode; 12 | 13 | class CDriversView : 14 | public CViewBase, 15 | public CAutoUpdateUI, 16 | public CIdleHandler, 17 | public COwnerDrawnMenu, 18 | public CVirtualListView { 19 | public: 20 | using CViewBase::CViewBase; 21 | 22 | DECLARE_WND_CLASS(nullptr) 23 | 24 | void Refresh(); 25 | BOOL OnIdle() override; 26 | 27 | protected: 28 | static const UINT WM_UPDATEDRIVER = WM_USER + 100; 29 | 30 | BEGIN_MSG_MAP(CDriversView) 31 | MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) 32 | COMMAND_ID_HANDLER(ID_DRIVER_START, OnStartStopDriver) 33 | COMMAND_ID_HANDLER(ID_DRIVER_STOP, OnStartStopDriver) 34 | MESSAGE_HANDLER(WM_UPDATEDRIVER, OnUpdateDriver) 35 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 36 | MESSAGE_HANDLER(WM_DESTROY, OnDestroy) 37 | CHAIN_MSG_MAP(CVirtualListView) 38 | CHAIN_MSG_MAP(CAutoUpdateUI) 39 | CHAIN_MSG_MAP(COwnerDrawnMenu) 40 | CHAIN_MSG_MAP(CViewBase) 41 | ALT_MSG_MAP(1) 42 | COMMAND_ID_HANDLER(ID_EDIT_COPY, OnCopy) 43 | COMMAND_ID_HANDLER(ID_VIEW_REFRESH, OnViewRefresh) 44 | END_MSG_MAP() 45 | 46 | CString GetColumnText(HWND, int row, int col); 47 | int GetRowImage(HWND, int row, int col); 48 | void DoSort(const SortInfo* si); 49 | int GetSaveColumnRange(HWND, int&) const; 50 | void OnStateChanged(HWND, int from, int to, UINT oldState, UINT newState); 51 | 52 | bool OnRightClickList(HWND, int row, int col, POINT const& pt); 53 | //bool OnDoubleClickList(HWND, int row, int col, POINT const&); 54 | 55 | // Handler prototypes (uncomment arguments if needed): 56 | // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 57 | // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 58 | // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) 59 | 60 | enum class ColumnType { 61 | Name, DisplayName, Type, ImagePath, State, WDFVersion, StartType, ErrorControl 62 | }; 63 | 64 | // 65 | // CViewBase overridables 66 | // 67 | //void OnPageActivated(bool activate); 68 | void UpdateUI(CUpdateUIBase& ui); 69 | 70 | private: 71 | void UpdateUI(); 72 | 73 | LRESULT OnStartStopDriver(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 74 | LRESULT OnUpdateDriver(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 75 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 76 | LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 77 | LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 78 | LRESULT OnCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 79 | LRESULT OnViewRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 80 | 81 | CListViewCtrl m_List; 82 | SortedFilteredVector m_Drivers; 83 | }; 84 | -------------------------------------------------------------------------------- /DevExp/DxgiView.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DxgiView.h" 3 | #include "Helpers.h" 4 | 5 | #pragma comment(lib, "dxgi") 6 | 7 | static constexpr DWORD TreeNodeMode = 0x1000; 8 | static constexpr DWORD TreeNodeFormat = 0x2000; 9 | 10 | template 11 | T* QueryAdapterInfo(D3DKMT_HANDLE hAdpater, KMTQUERYADAPTERINFOTYPE type, T& data) { 12 | D3DKMT_QUERYADAPTERINFO queryInfo; 13 | queryInfo.hAdapter = hAdpater; 14 | queryInfo.Type = type; 15 | queryInfo.pPrivateDriverData = &data; 16 | queryInfo.PrivateDriverDataSize = sizeof(T); 17 | auto status = ::D3DKMTQueryAdapterInfo(&queryInfo); 18 | return status == STATUS_SUCCESS ? &data : nullptr; 19 | } 20 | 21 | 22 | LRESULT CDxgiView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { 23 | m_hWndClient = m_Splitter.Create(m_hWnd, rcDefault, nullptr, WS_CLIPCHILDREN | WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS); 24 | m_Tree.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | 25 | TVS_HASBUTTONS | TVS_HASLINES | TVS_SHOWSELALWAYS); 26 | m_Tree.SetExtendedStyle(TVS_EX_DOUBLEBUFFER, 0); 27 | 28 | CImageList images; 29 | images.Create(16, 16, ILC_COLOR32 | ILC_MASK, 8, 8); 30 | m_Tree.SetImageList(images); 31 | 32 | UINT ids[] = { IDI_DIRECTX, IDI_ADAPTER, IDI_DEVICE, IDI_RECT, IDI_RESOLUTION }; 33 | for(auto id : ids) 34 | images.AddIcon(AtlLoadIconImage(id, 0, 16, 16)); 35 | 36 | m_List.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN 37 | | LVS_OWNERDATA | LVS_REPORT | LVS_SHOWSELALWAYS); 38 | m_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP); 39 | 40 | auto cm = GetColumnManager(m_List); 41 | cm->AddColumn(L"Property", LVCFMT_LEFT, 220, 0); 42 | cm->AddColumn(L"Value", LVCFMT_LEFT, 300, 1); 43 | cm->AddColumn(L"Details", LVCFMT_LEFT, 690, 2); 44 | cm->UpdateColumns(); 45 | 46 | m_Splitter.SetSplitterPosPct(25); 47 | m_Splitter.SetSplitterPanes(m_Tree, m_List); 48 | 49 | if (!BuildTree()) { 50 | AtlMessageBox(nullptr, L"Failed to create DXGI factory", IDS_TITLE, MB_ICONERROR); 51 | return -1; 52 | } 53 | 54 | return 0; 55 | } 56 | 57 | bool CDxgiView::BuildTree() { 58 | m_Tree.SetRedraw(FALSE); 59 | m_Tree.DeleteAllItems(); 60 | m_TreeNodes.clear(); 61 | auto hRoot = m_Tree.InsertItem(L"DXGI", 0, 0, TVI_ROOT, TVI_LAST); 62 | auto hr = ::CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast(&m_Factory)); 63 | if (FAILED(hr)) 64 | return false; 65 | 66 | D3DKMT_ENUMADAPTERS adapters{}; 67 | auto status = D3DKMTEnumAdapters(&adapters); 68 | 69 | for (UINT i = 0;; i++) { 70 | CComPtr adapter; 71 | hr = m_Factory->EnumAdapters1(i, &adapter); 72 | if (FAILED(hr)) 73 | break; 74 | 75 | DXGI_ADAPTER_DESC1 desc; 76 | adapter->GetDesc1(&desc); 77 | auto hItem = m_Tree.InsertItem(desc.Description, 1, 1, hRoot, TVI_SORT); 78 | TreeItem item; 79 | item.spUnknown = adapter; 80 | item.hAdapter = adapters.Adapters[i].hAdapter; 81 | 82 | m_TreeNodes.insert({ hItem, item }); 83 | 84 | for (UINT i = 0;; i++) { 85 | CComPtr output; 86 | hr = adapter->EnumOutputs(i, &output); 87 | if (FAILED(hr)) 88 | break; 89 | 90 | DXGI_OUTPUT_DESC desc; 91 | output->GetDesc(&desc); 92 | auto hOutput = m_Tree.InsertItem(desc.DeviceName, 2, 2, hItem, TVI_SORT); 93 | item.spUnknown = output; 94 | m_TreeNodes.insert({ hOutput, item}); 95 | 96 | for (UINT f = 1; f <= 200; f++) { 97 | UINT count = 0; 98 | output->GetDisplayModeList((DXGI_FORMAT)f, 0, &count, nullptr); 99 | if (count) { 100 | auto hModes = m_Tree.InsertItem(Helpers::DxgiFormatToString((DXGI_FORMAT)f).c_str(), 3, 3, hOutput, TVI_SORT); 101 | m_Tree.SetItemData(hModes, f + TreeNodeFormat); 102 | auto modes = std::make_unique(count); 103 | output->GetDisplayModeList((DXGI_FORMAT)f, 0, &count, modes.get()); 104 | for (UINT i = 0; i < count; i++) { 105 | auto& mode = modes[i]; 106 | auto hMode = m_Tree.InsertItem(std::format(L"{}x{} {:.0f} Hz", mode.Width, mode.Height, 107 | mode.RefreshRate.Numerator / (float)mode.RefreshRate.Denominator).c_str(), 108 | 4, 4, hModes, TVI_LAST); 109 | m_Tree.SetItemData(hMode, i + TreeNodeMode); 110 | } 111 | } 112 | } 113 | } 114 | 115 | } 116 | 117 | m_Tree.Expand(hRoot, TVE_EXPAND); 118 | m_Tree.SetRedraw(); 119 | 120 | return true; 121 | } 122 | 123 | CString CDxgiView::GetColumnText(HWND, int row, int col) { 124 | auto& item = m_Items[row]; 125 | switch (col) { 126 | case 0: return item.Name; 127 | case 1: return item.ValueAsString; 128 | case 2: return item.Details; 129 | } 130 | return L""; 131 | } 132 | 133 | void CDxgiView::DoSort(SortInfo const*) { 134 | } 135 | 136 | bool CDxgiView::OnDoubleClickList(HWND, int row, int col, POINT const& pt) const { 137 | return false; 138 | } 139 | 140 | void CDxgiView::OnTreeSelChanged(HWND, HTREEITEM hOld, HTREEITEM hNew) { 141 | UpdateList(hNew); 142 | } 143 | 144 | void CDxgiView::UpdateUI(CUpdateUIBase& ui) { 145 | } 146 | 147 | void CDxgiView::OnPageActivated(bool active) { 148 | } 149 | 150 | void CDxgiView::UpdateList(HTREEITEM hItem) { 151 | m_Items.clear(); 152 | if (auto it = m_TreeNodes.find(hItem); it != m_TreeNodes.end()) { 153 | auto& item = it->second; 154 | if (CComQIPtr adapter(item.spUnknown); adapter) { 155 | DXGI_ADAPTER_DESC1 desc1; 156 | adapter->GetDesc1(&desc1); 157 | m_Items.emplace_back(L"Description", CString(desc1.Description)); 158 | m_Items.emplace_back(L"Vendor ID", std::format(L"0x{:X}", desc1.VendorId).c_str()); 159 | m_Items.emplace_back(L"Device ID", std::format(L"0x{:X}", desc1.DeviceId).c_str()); 160 | m_Items.emplace_back(L"Subsystem ID", std::format(L"0x{:X}", desc1.SubSysId).c_str()); 161 | m_Items.emplace_back(L"Revision", std::format(L"0x{:X}", desc1.Revision).c_str()); 162 | m_Items.emplace_back(L"LUID", std::format(L"0x{:X}:{:08X}", desc1.AdapterLuid.HighPart, desc1.AdapterLuid.LowPart).c_str()); 163 | m_Items.emplace_back(L"Flags", std::format(L"0x{:X}", desc1.Flags).c_str(), Helpers::AdapterFlagsToString(desc1.Flags)); 164 | 165 | if (item.hAdapter) { 166 | D3DKMT_ADAPTERADDRESS address; 167 | if(QueryAdapterInfo(item.hAdapter, KMTQAITYPE_ADAPTERADDRESS, address)) { 168 | m_Items.emplace_back(L"Adapter Address", std::format(L"Bus: 0x{:X} Device: 0x{:X} Function: 0x{:X}", 169 | address.BusNumber, address.DeviceNumber, address.FunctionNumber).c_str()); 170 | } 171 | D3DKMT_SEGMENTSIZEINFO segmentInfo; 172 | if (QueryAdapterInfo(item.hAdapter, KMTQAITYPE_GETSEGMENTSIZE, segmentInfo)) { 173 | m_Items.emplace_back(L"Video Memory", std::format(L"{} MB", segmentInfo.DedicatedVideoMemorySize >> 20).c_str()); 174 | m_Items.emplace_back(L"System Memory", std::format(L"{} MB", segmentInfo.DedicatedSystemMemorySize >> 20).c_str()); 175 | m_Items.emplace_back(L"Shared System Memory", std::format(L"{} MB", segmentInfo.SharedSystemMemorySize >> 20).c_str()); 176 | } 177 | D3DKMT_DRIVERVERSION driverVer; 178 | if (QueryAdapterInfo(item.hAdapter, KMTQAITYPE_DRIVERVERSION, driverVer)) { 179 | m_Items.emplace_back(L"Driver Version", std::format(L"{} ", (UINT)driverVer).c_str()); 180 | } 181 | D3DKMT_UMD_DRIVER_VERSION umdVersion; 182 | if (QueryAdapterInfo(item.hAdapter, KMTQAITYPE_UMD_DRIVER_VERSION, umdVersion)) { 183 | m_Items.emplace_back(L"User Mode Driver Version", std::format(L"{}.{}.{}.{}", 184 | HIWORD(umdVersion.DriverVersion.HighPart), LOWORD(umdVersion.DriverVersion.HighPart), 185 | HIWORD(umdVersion.DriverVersion.LowPart), LOWORD(umdVersion.DriverVersion.LowPart)).c_str()); 186 | } 187 | D3DKMT_ADAPTERREGISTRYINFO registryInfo; 188 | if (QueryAdapterInfo(item.hAdapter, KMTQAITYPE_ADAPTERREGISTRYINFO, registryInfo)) { 189 | m_Items.emplace_back(L"BIOS String", registryInfo.BiosString); 190 | m_Items.emplace_back(L"DAC Type", registryInfo.DacType); 191 | m_Items.emplace_back(L"Chip Type", registryInfo.ChipType); 192 | } 193 | D3DKMT_WDDM_1_2_CAPS caps; 194 | if (QueryAdapterInfo(item.hAdapter, KMTQAITYPE_WDDM_1_2_CAPS, caps)) { 195 | m_Items.emplace_back(L"WDDM 1.2 Caps", std::format(L"0x{:04X}", caps.Value).c_str(), Helpers::Wddm12CapsToString(caps).c_str()); 196 | } 197 | D3DKMT_WDDM_1_3_CAPS caps3; 198 | if (QueryAdapterInfo(item.hAdapter, KMTQAITYPE_WDDM_1_3_CAPS, caps3)) { 199 | m_Items.emplace_back(L"WDDM 1.3 Caps", std::format(L"0x{:04X}", caps3.Value).c_str(), Helpers::Wddm13CapsToString(caps3).c_str()); 200 | } 201 | 202 | for (UINT src = 0;; src++) { 203 | D3DKMT_CURRENTDISPLAYMODE displayMode; 204 | displayMode.VidPnSourceId = src; 205 | if (QueryAdapterInfo(item.hAdapter, KMTQAITYPE_CURRENTDISPLAYMODE, displayMode)) { 206 | m_Items.emplace_back(std::format(L"Source {} Resolution", src).c_str(), std::format(L"{} X {}", displayMode.DisplayMode.Width, displayMode.DisplayMode.Height).c_str()); 207 | m_Items.emplace_back(std::format(L"Source {} Format", src).c_str(), Helpers::DdiFormatToString(displayMode.DisplayMode.Format).c_str()); 208 | m_Items.emplace_back(std::format(L"Source {} Refresh Rate", src).c_str(), std::format(L"{} Hz", displayMode.DisplayMode.IntegerRefreshRate).c_str()); 209 | D3DKMT_GETDEVICESTATE state{}; 210 | state.hDevice = item.hAdapter; 211 | state.PresentState.VidPnSourceId = src; 212 | state.StateType = D3DKMT_DEVICESTATE_PRESENT; 213 | if (STATUS_SUCCESS == D3DKMTGetDeviceState(&state)) { 214 | m_Items.emplace_back(std::format(L"Source {} Present Count", src).c_str(), std::format(L"{}", state.PresentState.PresentStats.PresentCount).c_str()); 215 | } 216 | } 217 | else 218 | break; 219 | } 220 | /* 221 | D3DKMT_GETPRESENTHISTORY history; 222 | D3DKMT_PRESENTHISTORYTOKEN tokens[8]; 223 | history.hAdapter = item.hAdapter; 224 | history.pTokens = tokens; 225 | history.ProvidedSize = sizeof(tokens); 226 | auto status = D3DKMTGetPresentHistory(&history); 227 | if (status == STATUS_SUCCESS) { 228 | } 229 | */ 230 | } 231 | } 232 | else if (CComQIPtr output(item.spUnknown); output) { 233 | DXGI_OUTPUT_DESC desc; 234 | output->GetDesc(&desc); 235 | m_Items.emplace_back(L"Device Name", CString(desc.DeviceName)); 236 | m_Items.emplace_back(L"Desktop Coordinates", std::format(L"({},{}) - ({},{})", 237 | desc.DesktopCoordinates.left, desc.DesktopCoordinates.top, desc.DesktopCoordinates.right, desc.DesktopCoordinates.bottom).c_str(), 238 | std::format(L"{} x {}", desc.DesktopCoordinates.right - desc.DesktopCoordinates.left, desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top).c_str()); 239 | m_Items.emplace_back(L"Attached to Desktop", desc.AttachedToDesktop ? L"Yes" : L"No"); 240 | m_Items.emplace_back(L"Monitor Handle", std::format(L"{}", (PVOID)desc.Monitor).c_str()); 241 | m_Items.emplace_back(L"Rotation", Helpers::RotationToString(desc.Rotation), L"Degrees"); 242 | 243 | } 244 | } 245 | else { 246 | auto data = m_Tree.GetItemData(hItem); 247 | if (data >= TreeNodeFormat) { 248 | // display format 249 | auto hParent = m_Tree.GetParentItem(hItem); 250 | if (auto it = m_TreeNodes.find(hParent); it != m_TreeNodes.end()) { 251 | CComQIPtr output(it->second.spUnknown); 252 | ATLASSERT(output); 253 | if (output) { 254 | UINT count = 0; 255 | output->GetDisplayModeList1((DXGI_FORMAT)(data - TreeNodeFormat), 0, &count, nullptr); 256 | m_Items.emplace_back(L"Display Modes", std::format(L"{}", count).c_str()); 257 | } 258 | } 259 | } 260 | else if (data >= TreeNodeMode) { 261 | // TODO: display mode properties 262 | } 263 | } 264 | m_List.SetItemCount((int)m_Items.size()); 265 | } 266 | 267 | -------------------------------------------------------------------------------- /DevExp/DxgiView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // View.h : interface of the CView class 4 | // 5 | ///////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | #include "VirtualListView.h" 10 | #include "TreeViewHelper.h" 11 | #include "DeviceManager.h" 12 | #include "ViewBase.h" 13 | #include "resource.h" 14 | #include 15 | #include 16 | #include 17 | 18 | class CDxgiView : 19 | public CViewBase, 20 | public CVirtualListView, 21 | public CCustomDraw, 22 | public CTreeViewHelper { 23 | public: 24 | using CViewBase::CViewBase; 25 | 26 | DECLARE_WND_CLASS(nullptr) 27 | 28 | // 29 | // list view callbacks 30 | // 31 | CString GetColumnText(HWND, int row, int col); 32 | bool IsSortable(HWND, int col) const { 33 | return col == 0; 34 | } 35 | void DoSort(SortInfo const*); 36 | bool OnDoubleClickList(HWND, int row, int col, POINT const& pt) const; 37 | 38 | // 39 | // tree view callbacks 40 | // 41 | void OnTreeSelChanged(HWND, HTREEITEM hOld, HTREEITEM hNew); 42 | //bool OnTreeRightClick(HWND, HTREEITEM hItem, POINT const& pt); 43 | //bool OnTreeDoubleClick(HWND, HTREEITEM hItem); 44 | 45 | // BOOL PreTranslateMessage(MSG* pMsg); 46 | 47 | // 48 | // CViewBase overridables 49 | // 50 | void UpdateUI(CUpdateUIBase& ui); 51 | void OnPageActivated(bool active); 52 | void UpdateList(HTREEITEM hItem); 53 | 54 | BEGIN_MSG_MAP(CDxgiView) 55 | //MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) 56 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 57 | //NOTIFY_CODE_HANDLER(NM_SETFOCUS, OnNotifySetFocus) 58 | CHAIN_MSG_MAP(CVirtualListView) 59 | CHAIN_MSG_MAP(CCustomDraw) 60 | CHAIN_MSG_MAP(CTreeViewHelper) 61 | CHAIN_MSG_MAP(CViewBase) 62 | ALT_MSG_MAP(1) 63 | //COMMAND_ID_HANDLER(ID_EDIT_COPY, OnCopy) 64 | //COMMAND_ID_HANDLER(ID_VIEW_REFRESH, OnViewRefresh) 65 | //COMMAND_ID_HANDLER(ID_DEVICE_ENABLE, OnEnableDisableDevice) 66 | //COMMAND_ID_HANDLER(ID_DEVICE_DISABLE, OnEnableDisableDevice) 67 | //COMMAND_ID_HANDLER(ID_VIEW_SHOWHIDDENDEVICES, OnShowHiddenDevices) 68 | //COMMAND_ID_HANDLER(ID_DEVICE_PROPERTIES, OnViewProperties) 69 | END_MSG_MAP() 70 | 71 | // Handler prototypes (uncomment arguments if needed): 72 | // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 73 | // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 74 | // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) 75 | 76 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 77 | LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 78 | LRESULT OnCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 79 | LRESULT OnShowHiddenDevices(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 80 | LRESULT OnNotifySetFocus(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/); 81 | LRESULT OnViewRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 82 | LRESULT OnEnableDisableDevice(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 83 | LRESULT OnViewProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 84 | 85 | private: 86 | struct Property { 87 | CString Name; 88 | CString ValueAsString; 89 | CString Details; 90 | }; 91 | 92 | struct TreeItem { 93 | CComPtr spUnknown; 94 | D3DKMT_HANDLE hAdapter{}; 95 | }; 96 | 97 | bool BuildTree(); 98 | 99 | CListViewCtrl m_List; 100 | CTreeViewCtrl m_Tree; 101 | CCustomSplitterWindow m_Splitter; 102 | std::vector m_Items; 103 | std::unordered_map m_TreeNodes; 104 | HWND m_Focus{ nullptr }; 105 | CComPtr m_Factory; 106 | }; 107 | 108 | -------------------------------------------------------------------------------- /DevExp/GeneralPropertyPage.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "GeneralPropertyPage.h" 3 | #include "DeviceManager.h" 4 | #include "Helpers.h" 5 | 6 | CGeneralPropertyPage::CGeneralPropertyPage(DeviceManager const& dm, DeviceInfo const& di) 7 | : CPropertyPageImpl(L"General"), m_dm(dm), m_di(di) { 8 | } 9 | 10 | LRESULT CGeneralPropertyPage::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { 11 | auto hIcon = m_dm.GetDeviceIcon(m_di, true); 12 | ATLASSERT(hIcon); 13 | ((CStatic)GetDlgItem(IDC_IMAGE)).SetIcon(hIcon); 14 | 15 | SetDlgItemText(IDC_NAME, m_di.Description.c_str()); 16 | 17 | DeviceNode node(m_di.Data.DevInst); 18 | 19 | SetDlgItemText(IDC_DEVICETYPE, m_dm.GetDeviceClassDescription(m_di.Data.ClassGuid).c_str()); 20 | SetDlgItemText(IDC_MFG, m_dm.GetDeviceRegistryPropertyString(m_di, DeviceRegistryPropertyType::Mfg).c_str()); 21 | auto location = m_dm.GetDeviceRegistryPropertyString(m_di, DeviceRegistryPropertyType::Location); 22 | if (location.empty()) { 23 | auto parent = node.GetProperty(DEVPKEY_Device_Parent); 24 | auto dev = m_dm.FindDevice([&](auto& device) { 25 | return _wcsicmp(DeviceNode(device.Data.DevInst).GetProperty(DEVPKEY_Device_InstanceId).c_str(), parent.c_str()) == 0; 26 | }); 27 | if(dev) 28 | location = dev->Description; 29 | } 30 | SetDlgItemText(IDC_LOCATION, location.c_str()); 31 | 32 | DeviceNodeProblem problem; 33 | node.GetStatus(&problem); 34 | if (problem != DeviceNodeProblem::None) { 35 | SetDlgItemText(IDC_STATUS, std::format(L"Error: {}", (int)problem).c_str()); 36 | } 37 | else { 38 | SetDlgItemText(IDC_STATUS, L"The device is working properly."); 39 | } 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /DevExp/GeneralPropertyPage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "DialogHelper.h" 4 | #include "resource.h" 5 | 6 | struct DeviceInfo; 7 | class DeviceManager; 8 | 9 | class CGeneralPropertyPage : 10 | public CPropertyPageImpl, 11 | public CDialogHelper { 12 | public: 13 | enum { IDD = IDD_PROP_GENERAL }; 14 | 15 | CGeneralPropertyPage(DeviceManager const& dm, DeviceInfo const& di); 16 | 17 | BEGIN_MSG_MAP(CAboutDlg) 18 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) 19 | END_MSG_MAP() 20 | 21 | // Handler prototypes (uncomment arguments if needed): 22 | // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 23 | // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 24 | // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) 25 | 26 | LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 27 | 28 | private: 29 | DeviceInfo const& m_di; 30 | DeviceManager const& m_dm; 31 | }; 32 | 33 | -------------------------------------------------------------------------------- /DevExp/Helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "DeviceNode.h" 4 | 5 | struct DeviceInfo; 6 | class DeviceManager; 7 | enum class DeviceDriverType; 8 | enum class DriverStartType; 9 | enum class DriverState; 10 | enum class DriverErrorControl; 11 | enum DXGI_FORMAT; 12 | typedef enum _D3DDDIFORMAT D3DDDIFORMAT; 13 | typedef struct _D3DKMT_WDDM_1_2_CAPS D3DKMT_WDDM_1_2_CAPS; 14 | typedef struct _D3DKMT_WDDM_1_3_CAPS D3DKMT_WDDM_1_3_CAPS; 15 | 16 | struct Helpers final { 17 | static CString GetPropertyName(DEVPROPKEY const& key); 18 | static CString GuidToString(GUID const& guid); 19 | static CString GetPropertyValueAsString(DEVPROPKEY const& key, DeviceNode const& node, PCWSTR sep = L"; "); 20 | static CString GetPropertyValueAsString(PBYTE value, DEVPROPTYPE type, ULONG size, PCWSTR sep = L"; "); 21 | static CString FormatBytes(const PBYTE buffer, ULONG size); 22 | static CString GetPropertyDetails(DEVPROPKEY const& key, PBYTE value, ULONG size); 23 | static PCWSTR InstallStateToString(ULONG state); 24 | static PCWSTR RemovalPolicyToString(ULONG policy); 25 | static CString DevNodeStatusToString(DeviceNodeStatus status, PCWSTR sep = L", "); 26 | static PCWSTR PciDeviceTypeToString(ULONG type); 27 | static PCWSTR DevicePowerStateToString(DEVICE_POWER_STATE state); 28 | static CString DeviceInterfaceToString(GUID const& guid); 29 | static bool DisplayProperty(DEVPROPKEY const& key, DeviceNode const& node, PCWSTR name); 30 | static std::wstring PowerCapabilitiesToString(DWORD caps); 31 | static void DisplayProperties(PCWSTR title, DeviceManager const& dm, DeviceInfo const& di); 32 | static PCWSTR ResourceTypeToString(ResourceType type); 33 | static std::wstring FormatDate(FILETIME const& ft); 34 | static PCWSTR DriverStateToString(DriverState state); 35 | static PCWSTR DriverErrorControlToString(DriverErrorControl ec); 36 | static std::wstring DriverTypeToString(DeviceDriverType type); 37 | static PCWSTR DriverStartTypeToString(DriverStartType type); 38 | static std::wstring DxgiFormatToString(DXGI_FORMAT format); 39 | static std::wstring DdiFormatToString(D3DDDIFORMAT format); 40 | static CString AdapterFlagsToString(UINT flags); 41 | static PCWSTR RotationToString(UINT rotation); 42 | static std::wstring Wddm12CapsToString(D3DKMT_WDDM_1_2_CAPS const& caps); 43 | static std::wstring Wddm13CapsToString(D3DKMT_WDDM_1_3_CAPS const& caps); 44 | }; 45 | -------------------------------------------------------------------------------- /DevExp/Interfaces.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | const UINT WM_PAGE_ACTIVATED = WM_APP + 111; 4 | const UINT WM_NEED_REFRESH = WM_PAGE_ACTIVATED + 1; 5 | 6 | struct IMainFrame abstract { 7 | virtual HWND GetHwnd() const = 0; 8 | virtual BOOL TrackPopupMenu(HMENU hMenu, DWORD flags, int x, int y, HWND hWnd = nullptr) = 0; 9 | virtual CUpdateUIBase& GetUI() = 0; 10 | }; 11 | -------------------------------------------------------------------------------- /DevExp/MainFrm.h: -------------------------------------------------------------------------------- 1 | // MainFrm.h : interface of the CMainFrame class 2 | // 3 | ///////////////////////////////////////////////////////////////////////////// 4 | 5 | #pragma once 6 | 7 | #include "Interfaces.h" 8 | #include 9 | #include "AppSettings.h" 10 | #include 11 | #include 12 | 13 | class CMainFrame : 14 | public CFrameWindowImpl, 15 | public COwnerDrawnMenu, 16 | public CAutoUpdateUI, 17 | public IMainFrame, 18 | public CMessageFilter, 19 | public CIdleHandler { 20 | public: 21 | DECLARE_FRAME_WND_CLASS(L"DevExpMainWndClass", IDR_MAINFRAME) 22 | 23 | BOOL PreTranslateMessage(MSG* pMsg) override; 24 | BOOL OnIdle() override; 25 | void PostMessageToAllTabs(UINT msg, WPARAM wp = 0, LPARAM lp = 0) const; 26 | 27 | protected: 28 | static const UINT WM_UPDATE_DARKMODE = WM_APP + 56; 29 | 30 | BEGIN_MSG_MAP(CMainFrame) 31 | MESSAGE_HANDLER(WM_DEVICECHANGE, OnDeviceChange) 32 | COMMAND_ID_HANDLER(ID_EXPLORE_DEVICESBYCLASS, OnExploreDeviceClasses) 33 | COMMAND_ID_HANDLER(ID_EXPLORE_DEVICEINTERFACES, OnExploreDeviceInterfaces) 34 | COMMAND_ID_HANDLER(ID_EXPLORE_DEVICETREE, OnExploreDeviceTree) 35 | COMMAND_ID_HANDLER(ID_EXPLORE_DEVICELIST, OnExploreDeviceList) 36 | COMMAND_ID_HANDLER(ID_EXPLORE_DRIVERS, OnExploreDrivers) 37 | COMMAND_ID_HANDLER(ID_EXPLORE_DXGI, OnExploreDxgi) 38 | COMMAND_ID_HANDLER(ID_WINDOW_CLOSE, OnWindowClose) 39 | COMMAND_ID_HANDLER(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll) 40 | COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit) 41 | COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar) 42 | COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar) 43 | COMMAND_ID_HANDLER(ID_OPTIONS_ALWAYSONTOP, OnAlwaysOnTop) 44 | COMMAND_ID_HANDLER(ID_TOOLS_INSTALLDRIVER, OnInstallDriver) 45 | COMMAND_ID_HANDLER(ID_TOOLS_FORCEINSTALLDRIVER, OnForceInstallDriver) 46 | COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout) 47 | COMMAND_ID_HANDLER(ID_FILE_RUNASADMINISTRATOR, OnRunAsAdmin) 48 | COMMAND_ID_HANDLER(ID_DEVICE_SCANFORHARDWARECHANGES, OnRescanHardware) 49 | NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnPageActivated) 50 | COMMAND_ID_HANDLER(ID_OPTIONS_DARKMODE, OnToggleDarkMode) 51 | MESSAGE_HANDLER(WM_UPDATE_DARKMODE, OnUpdateDarkMode) 52 | COMMAND_RANGE_HANDLER(ID_WINDOW_TABFIRST, ID_WINDOW_TABLAST, OnWindowActivate) 53 | if (uMsg == WM_COMMAND && ::IsWindow(m_view.m_hWnd)) { 54 | auto page = m_view.GetActivePage(); 55 | if (page >= 0 && ((CMessageMap*)m_view.GetPageData(page))->ProcessWindowMessage(hWnd, WM_COMMAND, wParam, lParam, lResult, 1)) 56 | return TRUE; 57 | } 58 | MESSAGE_HANDLER(WM_SHOWWINDOW, OnShowWindow) 59 | MESSAGE_HANDLER(WM_CREATE, OnCreate) 60 | MESSAGE_HANDLER(WM_DESTROY, OnDestroy) 61 | CHAIN_MSG_MAP(CAutoUpdateUI) 62 | CHAIN_MSG_MAP(COwnerDrawnMenu) 63 | CHAIN_MSG_MAP(CFrameWindowImpl) 64 | END_MSG_MAP() 65 | 66 | // Handler prototypes (uncomment arguments if needed): 67 | // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 68 | // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 69 | // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) 70 | 71 | private: 72 | void SetDarkMode(bool dark); 73 | void InitToolBar(CToolBarCtrl& tb, int size); 74 | void InitMenu(); 75 | void UpdateUI(); 76 | void SetAlwaysOnTop(bool onTop); 77 | void InitDarkTheme() const; 78 | bool DoInstallDriver(bool force); 79 | 80 | // IMainFrame 81 | HWND GetHwnd() const override; 82 | BOOL TrackPopupMenu(HMENU hMenu, DWORD flags, int x, int y, HWND hWnd = nullptr) override; 83 | CUpdateUIBase& GetUI() override; 84 | 85 | LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 86 | LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled); 87 | LRESULT OnDeviceChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 88 | LRESULT OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 89 | LRESULT OnViewToolBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 90 | LRESULT OnViewStatusBar(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 91 | LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) const; 92 | LRESULT OnWindowClose(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 93 | LRESULT OnWindowCloseAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 94 | LRESULT OnWindowActivate(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 95 | LRESULT OnPageActivated(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/); 96 | LRESULT OnRescanHardware(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 97 | LRESULT OnRunAsAdmin(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 98 | LRESULT OnExploreDeviceClasses(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 99 | LRESULT OnExploreDrivers(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 100 | LRESULT OnExploreDeviceInterfaces(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 101 | LRESULT OnExploreDeviceTree(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 102 | LRESULT OnExploreDeviceList(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 103 | LRESULT OnExploreDxgi(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 104 | LRESULT OnAlwaysOnTop(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 105 | LRESULT OnShowWindow(UINT, WPARAM, LPARAM, BOOL&); 106 | LRESULT OnToggleDarkMode(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 107 | LRESULT OnInstallDriver(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 108 | LRESULT OnForceInstallDriver(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 109 | LRESULT OnUpdateDarkMode(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 110 | 111 | CCustomTabView m_view; 112 | inline static AppSettings s_Settings; 113 | Theme m_DarkTheme; 114 | int m_ActivePage{ -1 }; 115 | inline static Theme s_DarkTheme; 116 | }; 117 | -------------------------------------------------------------------------------- /DevExp/MultiStringListDlg.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "MultiStringListDlg.h" 3 | 4 | void CMultiStringListDlg::SetData(std::vector data) { 5 | m_Data = std::move(data); 6 | } 7 | 8 | LRESULT CMultiStringListDlg::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { 9 | InitDynamicLayout(); 10 | SetDialogIcon(IDR_MAINFRAME); 11 | 12 | SetWindowText(m_Title); 13 | m_List.Attach(GetDlgItem(IDC_LIST)); 14 | CFont font; 15 | font.CreatePointFont(105, L"Consolas"); 16 | m_List.SetFont(font.Detach()); 17 | 18 | std::wstring text; 19 | for (auto& s : m_Data) { 20 | text += s + L"\r\n"; 21 | } 22 | m_List.SetWindowText(text.c_str()); 23 | m_List.SetSelNone(TRUE); 24 | 25 | return 0; 26 | } 27 | 28 | LRESULT CMultiStringListDlg::OnCloseCmd(WORD, WORD wID, HWND, BOOL&) { 29 | EndDialog(wID); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /DevExp/MultiStringListDlg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "resource.h" 4 | #include 5 | 6 | class CMultiStringListDlg : 7 | public CDialogImpl, 8 | public CDialogHelper, 9 | public CDynamicDialogLayout { 10 | public: 11 | enum { IDD = IDD_STRINGLIST }; 12 | 13 | CMultiStringListDlg(PCWSTR title) : m_Title(title) {} 14 | 15 | void SetData(std::vector data); 16 | 17 | BEGIN_MSG_MAP(CMultiStringListDlg) 18 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) 19 | COMMAND_ID_HANDLER(IDOK, OnCloseCmd) 20 | COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd) 21 | CHAIN_MSG_MAP(CDynamicDialogLayout) 22 | END_MSG_MAP() 23 | 24 | private: 25 | // Handler prototypes (uncomment arguments if needed): 26 | // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 27 | // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 28 | // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) 29 | 30 | LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 31 | LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 32 | 33 | CString m_Title; 34 | CEdit m_List; 35 | std::vector m_Data; 36 | }; 37 | -------------------------------------------------------------------------------- /DevExp/ResourcesPropertyPage.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "ResourcesPropertyPage.h" 3 | #include "DeviceManager.h" 4 | #include 5 | #include "Helpers.h" 6 | 7 | CResourcesPropertyPage::CResourcesPropertyPage(std::vector const& resources) 8 | : CPropertyPageImpl(L"Resources"), m_Items(resources) { 9 | } 10 | 11 | CString CResourcesPropertyPage::GetColumnText(HWND, int row, int col) const { 12 | auto& item = m_Items[row]; 13 | 14 | switch (col) { 15 | case 0: return Helpers::ResourceTypeToString(item.Type); 16 | case 1: return ResourceSettingToString(item).c_str(); 17 | } 18 | return CString(); 19 | } 20 | 21 | int CResourcesPropertyPage::GetRowImage(HWND, int row, int) const { 22 | switch (m_Items[row].Type) { 23 | case ResourceType::Memory: 24 | case ResourceType::LargeMemory: 25 | return 0; 26 | case ResourceType::Interrupt: 27 | return 1; 28 | case ResourceType::IO: 29 | return 2; 30 | } 31 | return 3; 32 | } 33 | 34 | std::wstring CResourcesPropertyPage::ResourceSettingToString(DeviceResource const& res) { 35 | switch (res.Type) { 36 | case ResourceType::Memory: 37 | case ResourceType::LargeMemory: 38 | { 39 | auto& header = res.Memory().MEM_Header; 40 | return std::format(L"0x{:016X} - 0x{:016X} (0x{:X})", 41 | header.MD_Alloc_Base, header.MD_Alloc_End, header.MD_Alloc_End - header.MD_Alloc_Base + 1); 42 | } 43 | 44 | case ResourceType::Interrupt: 45 | { 46 | auto& irq = res.Interrupt().IRQ_Header.IRQD_Alloc_Num; 47 | return std::format(L"IRQ: 0x{:X} ({})", irq, (LONG)irq).c_str(); 48 | } 49 | 50 | case ResourceType::IO: 51 | auto& io = res.IO().IO_Header; 52 | return std::format(L"0x{:04X} - 0x{:04X} (0x{:X})", 53 | io.IOD_Alloc_Base, io.IOD_Alloc_End, io.IOD_Alloc_End - io.IOD_Alloc_Base + 1); 54 | } 55 | return L""; 56 | } 57 | 58 | LRESULT CResourcesPropertyPage::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { 59 | m_List.Attach(GetDlgItem(IDC_LIST)); 60 | m_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP); 61 | m_List.SetItemCount((int)m_Items.size()); 62 | 63 | CImageList images; 64 | images.Create(16, 16, ILC_COLOR32 | ILC_MASK, 4, 4); 65 | UINT icons[] = { IDI_MEMORY, IDI_INTERRUPT, IDI_PORT }; 66 | for (auto icon : icons) 67 | images.AddIcon(AtlLoadIconImage(icon)); 68 | m_List.SetImageList(images, LVSIL_SMALL); 69 | 70 | auto cm = GetColumnManager(m_List); 71 | cm->AddColumn(L"Resource Type", LVCFMT_LEFT, 100); 72 | cm->AddColumn(L"Setting", LVCFMT_LEFT, 300); 73 | cm->UpdateColumns(); 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /DevExp/ResourcesPropertyPage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "DialogHelper.h" 4 | #include "resource.h" 5 | #include 6 | 7 | struct DeviceResource; 8 | 9 | class CResourcesPropertyPage : 10 | public CPropertyPageImpl, 11 | public CVirtualListView< CResourcesPropertyPage>, 12 | public CDialogHelper { 13 | public: 14 | enum { IDD = IDD_PROP_RES }; 15 | 16 | explicit CResourcesPropertyPage(std::vector const& resources); 17 | 18 | CString GetColumnText(HWND, int row, int col) const; 19 | int GetRowImage(HWND, int row, int) const; 20 | 21 | BEGIN_MSG_MAP(CResourcesPropertyPage) 22 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) 23 | CHAIN_MSG_MAP(CVirtualListView) 24 | END_MSG_MAP() 25 | 26 | static std::wstring ResourceSettingToString(DeviceResource const& res); 27 | 28 | // Handler prototypes (uncomment arguments if needed): 29 | // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 30 | // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 31 | // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) 32 | 33 | LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 34 | 35 | private: 36 | CListViewCtrl m_List; 37 | std::vector const& m_Items; 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /DevExp/SecurityHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "SecurityHelper.h" 3 | 4 | bool SecurityHelper::IsRunningElevated() { 5 | static bool runningElevated = false; 6 | static bool runningElevatedCheck = false; 7 | if (runningElevatedCheck) 8 | return runningElevated; 9 | 10 | runningElevatedCheck = true; 11 | wil::unique_handle hToken; 12 | if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, hToken.addressof())) 13 | return false; 14 | 15 | TOKEN_ELEVATION te; 16 | DWORD len; 17 | if (::GetTokenInformation(hToken.get(), TokenElevation, &te, sizeof(te), &len)) { 18 | runningElevated = te.TokenIsElevated ? true : false; 19 | } 20 | return runningElevated; 21 | } 22 | 23 | bool SecurityHelper::RunElevated() { 24 | WCHAR path[MAX_PATH]; 25 | ::GetModuleFileName(nullptr, path, _countof(path)); 26 | return (INT_PTR)::ShellExecute(nullptr, L"runas", path, nullptr, nullptr, SW_SHOWDEFAULT) > 31; 27 | } 28 | 29 | bool SecurityHelper::EnablePrivilege(PCWSTR privName, bool enable) { 30 | wil::unique_handle hToken; 31 | if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hToken.addressof())) 32 | return false; 33 | 34 | bool result = false; 35 | TOKEN_PRIVILEGES tp; 36 | tp.PrivilegeCount = 1; 37 | tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0; 38 | if (::LookupPrivilegeValue(nullptr, privName, 39 | &tp.Privileges[0].Luid)) { 40 | if (::AdjustTokenPrivileges(hToken.get(), FALSE, &tp, sizeof(tp), 41 | nullptr, nullptr)) 42 | result = ::GetLastError() == ERROR_SUCCESS; 43 | } 44 | return result; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /DevExp/SecurityHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct SecurityHelper abstract final { 4 | static bool IsRunningElevated(); 5 | static bool RunElevated(); 6 | static bool EnablePrivilege(PCWSTR privName, bool enable); 7 | }; 8 | -------------------------------------------------------------------------------- /DevExp/ViewBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Interfaces.h" 4 | 5 | template 6 | struct CViewBase 7 | : public CFrameWindowImpl { 8 | using BaseFrame = CFrameWindowImpl; 9 | 10 | CViewBase(IMainFrame* frame) : m_pFrame(frame) {} 11 | 12 | protected: 13 | BEGIN_MSG_MAP(CViewBase) 14 | MESSAGE_HANDLER(WM_PAGE_ACTIVATED, OnPageActivated) 15 | MESSAGE_HANDLER(WM_NEED_REFRESH, OnNeedRefresh) 16 | CHAIN_MSG_MAP(BaseFrame) 17 | END_MSG_MAP() 18 | 19 | void OnFinalMessage(HWND) override { 20 | delete this; 21 | } 22 | 23 | IMainFrame* GetFrame() { 24 | return m_pFrame; 25 | } 26 | 27 | bool IsRefreshNeeded() const { 28 | auto need = m_NeedRefresh; 29 | m_NeedRefresh = false; 30 | return need; 31 | } 32 | 33 | LRESULT OnPageActivated(UINT, WPARAM wp, LPARAM, BOOL&) { 34 | m_IsActive = (bool)wp; 35 | static_cast(this)->OnPageActivated(wp ? true : false); 36 | if (wp) 37 | static_cast(this)->UpdateUI(m_pFrame->GetUI()); 38 | return 0; 39 | } 40 | 41 | LRESULT OnNeedRefresh(UINT, WPARAM wp, LPARAM, BOOL&) { 42 | auto pT = static_cast(this); 43 | if (m_IsActive) { 44 | LRESULT result; 45 | pT->ProcessWindowMessage(pT->m_hWnd, WM_COMMAND, ID_VIEW_REFRESH, 0, result, 1); 46 | } 47 | else 48 | m_NeedRefresh = true; 49 | return 0; 50 | } 51 | 52 | // 53 | // overridables 54 | // 55 | void OnPageActivated(bool activate) {} 56 | void UpdateUI(CUpdateUIBase& ui) {} 57 | 58 | private: 59 | IMainFrame* m_pFrame; 60 | mutable bool m_NeedRefresh{ false }; 61 | bool m_IsActive{ false }; 62 | }; 63 | -------------------------------------------------------------------------------- /DevExp/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DevExp/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | -------------------------------------------------------------------------------- /DevExp/pch.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #define WINVER 0x0A00 9 | #define _WIN32_WINNT 0x0603 10 | #define _WIN32_IE 0x0700 11 | #define _RICHEDIT_VER 0x0500 12 | #define NOMINMAX 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | extern CAppModule _Module; 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include 53 | #include 54 | #include 55 | 56 | #if defined _M_IX86 57 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 58 | #elif defined _M_IA64 59 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") 60 | #elif defined _M_X64 61 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 62 | #else 63 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 64 | #endif 65 | -------------------------------------------------------------------------------- /DevExp/res/Adapter.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/Adapter.ico -------------------------------------------------------------------------------- /DevExp/res/Binary.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/Binary.ico -------------------------------------------------------------------------------- /DevExp/res/Check.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/Check.ico -------------------------------------------------------------------------------- /DevExp/res/DevExp.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/DevExp.ico -------------------------------------------------------------------------------- /DevExp/res/Go.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/Go.ico -------------------------------------------------------------------------------- /DevExp/res/Install.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/Install.ico -------------------------------------------------------------------------------- /DevExp/res/LPT-plug.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/LPT-plug.ico -------------------------------------------------------------------------------- /DevExp/res/Properties.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/Properties.ico -------------------------------------------------------------------------------- /DevExp/res/Stop.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/Stop.ico -------------------------------------------------------------------------------- /DevExp/res/Text.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/Text.ico -------------------------------------------------------------------------------- /DevExp/res/close-all.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/close-all.ico -------------------------------------------------------------------------------- /DevExp/res/close.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/close.ico -------------------------------------------------------------------------------- /DevExp/res/copy.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/copy.ico -------------------------------------------------------------------------------- /DevExp/res/delete.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/delete.ico -------------------------------------------------------------------------------- /DevExp/res/device.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/device.ico -------------------------------------------------------------------------------- /DevExp/res/devices.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/devices.ico -------------------------------------------------------------------------------- /DevExp/res/directx.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/directx.ico -------------------------------------------------------------------------------- /DevExp/res/disable.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/disable.ico -------------------------------------------------------------------------------- /DevExp/res/driver-kmdf.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/driver-kmdf.ico -------------------------------------------------------------------------------- /DevExp/res/driver-umdf.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/driver-umdf.ico -------------------------------------------------------------------------------- /DevExp/res/driver.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/driver.ico -------------------------------------------------------------------------------- /DevExp/res/enable.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/enable.ico -------------------------------------------------------------------------------- /DevExp/res/enum.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/enum.ico -------------------------------------------------------------------------------- /DevExp/res/find.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/find.ico -------------------------------------------------------------------------------- /DevExp/res/flag.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/flag.ico -------------------------------------------------------------------------------- /DevExp/res/gear_refresh.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/gear_refresh.ico -------------------------------------------------------------------------------- /DevExp/res/globe.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/globe.ico -------------------------------------------------------------------------------- /DevExp/res/info.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/info.ico -------------------------------------------------------------------------------- /DevExp/res/interface.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/interface.ico -------------------------------------------------------------------------------- /DevExp/res/interrupt.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/interrupt.ico -------------------------------------------------------------------------------- /DevExp/res/link.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/link.ico -------------------------------------------------------------------------------- /DevExp/res/list.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/list.ico -------------------------------------------------------------------------------- /DevExp/res/memory.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/memory.ico -------------------------------------------------------------------------------- /DevExp/res/number-4.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/number-4.ico -------------------------------------------------------------------------------- /DevExp/res/piece.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/piece.ico -------------------------------------------------------------------------------- /DevExp/res/power.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/power.ico -------------------------------------------------------------------------------- /DevExp/res/radio.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/radio.ico -------------------------------------------------------------------------------- /DevExp/res/rectangle.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/rectangle.ico -------------------------------------------------------------------------------- /DevExp/res/refresh.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/refresh.ico -------------------------------------------------------------------------------- /DevExp/res/resolution.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/resolution.ico -------------------------------------------------------------------------------- /DevExp/res/resource.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/resource.ico -------------------------------------------------------------------------------- /DevExp/res/show-hidden.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/show-hidden.ico -------------------------------------------------------------------------------- /DevExp/res/tree.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/tree.ico -------------------------------------------------------------------------------- /DevExp/res/uninstall.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DeviceExplorer/e46c03c62b2802c66824bfb290d040ebc96ef9cf/DevExp/res/uninstall.ico -------------------------------------------------------------------------------- /DevExp/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by DevExp.rc 4 | // 5 | #define IDD_ABOUTBOX 100 6 | #define IDD_PROP_GENERAL 107 7 | #define IDR_MAINFRAME 128 8 | #define IDS_TITLE 129 9 | #define IDI_COPY 201 10 | #define IDI_CANCEL 202 11 | #define IDI_FIND 203 12 | #define IDI_PROPS 204 13 | #define IDI_REFRESH 205 14 | #define IDI_DEVICES 206 15 | #define IDR_CONTEXT 207 16 | #define IDI_LIST 208 17 | #define IDI_MEMORY 209 18 | #define IDI_TREE 210 19 | #define IDI_RESCAN 211 20 | #define IDI_DISABLE_DEVICE 212 21 | #define IDI_ENABLE_DEVICE 213 22 | #define IDI_INTERFACE 214 23 | #define IDD_STRINGLIST 215 24 | #define IDD_PROP_RES 216 25 | #define IDD_PROP_DRIVERS 217 26 | #define IDI_DRIVER 218 27 | #define IDI_DRIVER_KMDF 219 28 | #define IDI_GLOBE 220 29 | #define IDI_FLAG 222 30 | #define IDI_POWER 223 31 | #define IDI_ICON3 224 32 | #define IDI_TEXT 224 33 | #define IDI_BINARY 225 34 | #define IDI_INTERRUPT 226 35 | #define IDI_PORT 227 36 | #define IDI_DRIVER_UMDF 229 37 | #define IDI_GO 230 38 | #define IDI_STOP 231 39 | #define IDI_CHECK 232 40 | #define IDI_RADIO 233 41 | #define IDI_CLOSE 234 42 | #define IDI_CLOSEALL 235 43 | #define IDI_INSTALL 236 44 | #define IDI_ADAPTER 237 45 | #define IDI_DEVICE 238 46 | #define IDI_RECT 239 47 | #define IDI_DIRECTX 240 48 | #define IDI_ICON1 241 49 | #define IDI_RESOLUTION 241 50 | #define IDC_LIST 1002 51 | #define IDC_NAME 1003 52 | #define IDC_IMAGE 1005 53 | #define IDC_DEVICETYPE 1006 54 | #define IDC_MFG 1007 55 | #define IDC_LOCATION 1008 56 | #define IDC_LOCATION2 1009 57 | #define IDC_STATUS 1009 58 | #define ID_WINDOW_CLOSE 32772 59 | #define ID_WINDOW_CLOSE_ALL 32773 60 | #define ID_FILE_RUNASADMINISTRATOR 32775 61 | #define ID_OPTIONS_ALWAYSONTOP 32776 62 | #define ID_OPTIONS_FONT 32777 63 | #define ID_DEVICE_ENABLE 32778 64 | #define ID_DEVICE_UNINSTALL 32779 65 | #define ID_DEVICE_PROPERTIES 32780 66 | #define ID_VIEW_SHOWHIDDENDEVICES 32781 67 | #define ID_DEVICE_SCANFORHARDWARECHANGES 32782 68 | #define ID_DEVICE_DISABLE 32783 69 | #define ID_VIEW_SHOWEMPTYCLASSES 32784 70 | #define ID_VIEW_REFRESH32785 32785 71 | #define ID_TAB_NEWWINDOW 32786 72 | #define ID_OPTIONS_DARKMODE 32787 73 | #define ID_DEVICE_DRIVERS 32788 74 | #define ID_TAB_CLOSEALL 32791 75 | #define ID_EXPLORE_DEVICESBYCLASS 32792 76 | #define ID_EXPLORE_DEVICETREE 32793 77 | #define ID_EXPLORE_DRIVERS 32794 78 | #define ID_EXPLORE_DEVICEINTERFACES 32795 79 | #define ID_EXPLORE_DEVICELIST 32796 80 | #define ID_DRIVER_START 32797 81 | #define ID_DRIVER_STOP 32798 82 | #define ID_DRIVER_UNINSTALL 32799 83 | #define ID_TOOLS_INSTALLDRIVER 32800 84 | #define ID_Menu 32801 85 | #define ID_TOOLS_FORCEINSTALLDRIVER 32802 86 | #define ID_EXPLORE_DXGI 32803 87 | 88 | // Next default values for new objects 89 | // 90 | #ifdef APSTUDIO_INVOKED 91 | #ifndef APSTUDIO_READONLY_SYMBOLS 92 | #define _APS_NEXT_RESOURCE_VALUE 242 93 | #define _APS_NEXT_COMMAND_VALUE 32804 94 | #define _APS_NEXT_CONTROL_VALUE 1010 95 | #define _APS_NEXT_SYMED_VALUE 101 96 | #endif 97 | #endif 98 | -------------------------------------------------------------------------------- /DevExpC/DevExpC.cpp: -------------------------------------------------------------------------------- 1 | // DevExpC.cpp : This file contains the 'main' function. Program execution begins and ends there. 2 | // 3 | 4 | #include "pch.h" 5 | #include "DeviceManager.h" 6 | #define INITGUID 7 | #include 8 | #include "DriverManager.h" 9 | 10 | 11 | std::wstring GuidToString(GUID const& guid) { 12 | WCHAR name[64]; 13 | return SUCCEEDED(::StringFromGUID2(guid, name, _countof(name))) ? name : L""; 14 | } 15 | 16 | void DumpHardwareProfiles() { 17 | for (auto& profile : DeviceManager::EnumHardwareProfiles()) { 18 | printf("Profile %u: %ws\n", profile.Index, profile.FriendlyName.c_str()); 19 | } 20 | } 21 | 22 | void TestEnum() { 23 | GUID guid; 24 | printf("Classes\n"); 25 | for (DWORD i = 0;; i++) { 26 | if (CR_NO_SUCH_VALUE == ::CM_Enumerate_Classes(i, &guid, CM_ENUMERATE_CLASSES_INSTALLER)) 27 | break; 28 | printf("%ws\n", GuidToString(guid).c_str()); 29 | } 30 | 31 | printf("Interfaces\n"); 32 | for (DWORD i = 0;; i++) { 33 | if (CR_NO_SUCH_VALUE == ::CM_Enumerate_Classes(i, &guid, CM_ENUMERATE_CLASSES_INTERFACE)) 34 | break; 35 | printf("%ws\n", GuidToString(guid).c_str()); 36 | } 37 | printf("Enumerators\n"); 38 | WCHAR name[MAX_DEVICE_ID_LEN + 1]; 39 | for (DWORD i = 0;; i++) { 40 | DWORD size = _countof(name); 41 | if (CR_NO_SUCH_VALUE == ::CM_Enumerate_Enumerators(i, name, &size, 0)) 42 | break; 43 | printf("%ws\n", name); 44 | 45 | ::CM_Get_Device_ID_List_Size(&size, name, CM_GETIDLIST_FILTER_ENUMERATOR | CM_GETIDLIST_FILTER_PRESENT); 46 | auto buffer = std::make_unique(size); 47 | ::CM_Get_Device_ID_List(name, buffer.get(), size, CM_GETIDLIST_FILTER_ENUMERATOR | CM_GETIDLIST_FILTER_PRESENT); 48 | auto p = buffer.get(); 49 | while (*p) { 50 | DEVINST inst = 0; 51 | auto error = ::CM_Locate_DevInst(&inst, p, 0); 52 | printf("\t%ws (%d)\n", p, error == CR_SUCCESS ? inst : -1); 53 | p += wcslen(p) + 1; 54 | } 55 | } 56 | } 57 | 58 | void DisplayProperties(DEVINST inst) { 59 | auto buffer = std::make_unique(2048); 60 | DEVPROPKEY keys[80]; 61 | ULONG count = _countof(keys); 62 | ::CM_Get_DevNode_Property_Keys(inst, keys, &count, 0); 63 | LOG_CONF log = 0; 64 | ::CM_Get_First_Log_Conf(&log, inst, BASIC_LOG_CONF); 65 | if (log) { 66 | RES_DES rd; 67 | RESOURCEID r; 68 | while(CR_SUCCESS == CM_Get_Next_Res_Des(&rd, log, ResType_All, &r, 0)) { 69 | BYTE buffer[1000]; 70 | CM_Get_Res_Des_Data(rd, buffer, 1000, 0); 71 | auto io = (IRQ_RESOURCE*)buffer; 72 | } 73 | CM_Free_Log_Conf(log, 0); 74 | } 75 | 76 | DEVPROPTYPE type; 77 | for (DWORD i = 0; i < count; i++) { 78 | ULONG size = 2048; 79 | ::CM_Get_DevNode_Property(inst, keys + i, &type, buffer.get(), &size, 0); 80 | if (type == DEVPROP_TYPE_STRING && keys[i] == DEVPKEY_NAME) { 81 | printf("\t(%ws)\n", (PCWSTR)buffer.get()); 82 | } 83 | else if (type == DEVPROP_TYPE_STRING_INDIRECT) { 84 | int zz = 9; 85 | } 86 | } 87 | } 88 | 89 | void EnumSiblingDevNodes(DEVINST inst, int indent = 0); 90 | 91 | void EnumChildDevNodes(DEVINST inst, int indent = 1) { 92 | WCHAR name[256]; 93 | DEVINST child = 0; 94 | ::CM_Get_Child(&child, inst, 0); 95 | while (child) { 96 | ::CM_Get_Device_ID(child, name, _countof(name), 0); 97 | printf("%s%ws\n", std::string(indent, ' ').c_str(), name); 98 | DisplayProperties(child); 99 | EnumSiblingDevNodes(child, indent); 100 | EnumChildDevNodes(child, indent + 1); 101 | DEVINST temp = 0; 102 | ::CM_Get_Child(&temp, child, 0); 103 | child = temp; 104 | } 105 | } 106 | 107 | void EnumSiblingDevNodes(DEVINST inst, int indent) { 108 | WCHAR name[256]; 109 | DEVINST child = 0; 110 | ::CM_Get_Sibling(&child, inst, 0); 111 | while (child) { 112 | ::CM_Get_Device_ID(child, name, _countof(name), 0); 113 | printf("%s%ws\n", std::string(indent, ' ').c_str(), name); 114 | DisplayProperties(child); 115 | DEVINST sib = 0; 116 | ::CM_Get_Sibling(&sib, child, 0); 117 | EnumChildDevNodes(child, indent + 1); 118 | child = sib; 119 | //EnumSiblingDevNodes(child, indent); 120 | } 121 | } 122 | 123 | void EnumDevNodes() { 124 | //::CM_Locate_DevInst( 125 | DEVINST inst; 126 | WCHAR name[256]; 127 | DEVPROPKEY keys[30]; 128 | ULONG count = _countof(keys); 129 | auto buffer = std::make_unique(2048); 130 | 131 | if (CR_SUCCESS == ::CM_Locate_DevNode(&inst, nullptr, CM_LOCATE_DEVNODE_NORMAL)) { 132 | ::CM_Get_Device_ID(inst, name, _countof(name), 0); 133 | printf("%ws\n", name); 134 | DisplayProperties(inst); 135 | ::CM_Get_DevNode_Property_Keys(inst, keys, &count, 0); 136 | DEVPROPTYPE type; 137 | for (DWORD i = 0; i < count; i++) { 138 | ULONG size = 2048; 139 | ::CM_Get_DevNode_Property(inst, keys + i, &type, buffer.get(), &size, 0); 140 | //printf("Type: %u\n", type); 141 | } 142 | 143 | EnumChildDevNodes(inst); 144 | EnumSiblingDevNodes(inst); 145 | 146 | 147 | } 148 | } 149 | 150 | int main() { 151 | auto drivers = DriverManager::EnumKernelDrivers(); 152 | 153 | auto dm = DeviceManager::Create();; 154 | for (auto& di : dm->EnumDevices()) { 155 | auto res = DeviceNode(di.Data.DevInst).GetResources(); 156 | if(!res.empty()) 157 | printf("Inst: %u Resources: %u\n", di.Data.DevInst, (uint32_t)res.size()); 158 | } 159 | 160 | SetupDiCallClassInstaller(DIF_SELECTDEVICE, dm->InfoSet(), nullptr); 161 | 162 | for (auto g : DeviceManager::BuildClassInfoList(0)) { 163 | printf("%ws (%ws)\n", GuidToString(g).c_str(), DeviceManager::GetSetupClassDescription(g).c_str()); 164 | } 165 | 166 | //DumpDeviceInterfaces(); 167 | //DumpHardwareProfiles(); 168 | //DumpDeviceClasses(); 169 | //EnumDevNodes(); 170 | 171 | //TestEnum(); 172 | 173 | 174 | return 0; 175 | } 176 | 177 | -------------------------------------------------------------------------------- /DevExpC/DevExpC.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /DevExpC/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /DevExpC/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: source file corresponding to the pre-compiled header 2 | 3 | #include "pch.h" 4 | 5 | // When you are using pre-compiled headers, this source file is necessary for compilation to succeed. 6 | -------------------------------------------------------------------------------- /DevExpC/pch.h: -------------------------------------------------------------------------------- 1 | // pch.h: This is a precompiled header file. 2 | // Files listed below are compiled only once, improving build performance for future builds. 3 | // This also affects IntelliSense performance, including code completion and many code browsing features. 4 | // However, files listed here are ALL re-compiled if any one of them is updated between builds. 5 | // Do not add files here that you will be updating frequently as this negates the performance advantage. 6 | 7 | #ifndef PCH_H 8 | #define PCH_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #endif //PCH_H 22 | -------------------------------------------------------------------------------- /DevExpCore/DevExpCore.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /DevExpCore/DeviceManager.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DeviceManager.h" 3 | #include 4 | #include 5 | 6 | #pragma comment(lib, "setupapi") 7 | #pragma comment(lib, "cfgmgr32") 8 | 9 | SP_CLASSIMAGELIST_DATA g_ClassImageList; 10 | 11 | std::unique_ptr DeviceManager::Create(const wchar_t* computerName, const GUID* classGuid, const wchar_t* enumerator, InfoSetOptions options) { 12 | auto dm = new DeviceManager(computerName, classGuid, enumerator, options); 13 | if (dm->m_hInfoSet) 14 | return std::unique_ptr(dm); 15 | delete dm; 16 | return nullptr; 17 | } 18 | 19 | std::wstring DeviceManager::GetDeviceClassDescription(GUID const& guid, const wchar_t* computerName) { 20 | wchar_t desc[256]; 21 | if (::SetupDiGetClassDescriptionEx(&guid, desc, _countof(desc), nullptr, computerName, nullptr)) { 22 | return desc; 23 | } 24 | return L""; 25 | } 26 | 27 | HIMAGELIST DeviceManager::GetClassImageList() { 28 | if (g_ClassImageList.ImageList == nullptr) { 29 | g_ClassImageList.cbSize = sizeof(g_ClassImageList); 30 | ::SetupDiGetClassImageList(&g_ClassImageList); 31 | } 32 | return g_ClassImageList.ImageList; 33 | } 34 | 35 | int DeviceManager::GetClassImageIndex(GUID const& guid) { 36 | int index = -1; 37 | ::SetupDiGetClassImageIndex(&g_ClassImageList, &guid, &index); 38 | return index; 39 | } 40 | 41 | std::vector DeviceManager::EnumHardwareProfiles(PCWSTR computerName) { 42 | std::vector hwprofiles; 43 | DWORD size; 44 | if (!::SetupDiGetHwProfileListEx(nullptr, 0, &size, nullptr, computerName, nullptr) && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 45 | auto profiles = std::make_unique(size); 46 | if (::SetupDiGetHwProfileListEx(profiles.get(), size, &size, nullptr, computerName, nullptr)) { 47 | WCHAR name[256]; 48 | hwprofiles.reserve(size); 49 | for (DWORD i = 0; i < size; i++) { 50 | HardwareProfile profile; 51 | profile.Index = i; 52 | if (::SetupDiGetHwProfileFriendlyNameEx(i, name, _countof(name), nullptr, computerName, nullptr)) 53 | profile.FriendlyName = name; 54 | hwprofiles.push_back(std::move(profile)); 55 | } 56 | } 57 | } 58 | return hwprofiles; 59 | } 60 | 61 | std::vector DeviceManager::GetDeviceClassPropertyKeys(GUID const& guid) { 62 | return GetDeviceClassPropertyKeysCommon(guid, true); 63 | } 64 | 65 | std::vector DeviceManager::GetDeviceInterfacePropertyKeys(GUID const& guid) { 66 | return GetDeviceClassPropertyKeysCommon(guid, false); 67 | } 68 | 69 | DeviceNode DeviceManager::GetRootDeviceNode() { 70 | DEVINST inst; 71 | return CR_SUCCESS == ::CM_Locate_DevNode(&inst, nullptr, CM_LOCATE_DEVNODE_NORMAL) ? inst : 0; 72 | } 73 | 74 | std::wstring DeviceManager::GetDeviceRegistryPropertyString(const DeviceInfo& di, DeviceRegistryPropertyType type) const { 75 | WCHAR value[512]; 76 | DWORD regType; 77 | if (::SetupDiGetDeviceRegistryProperty(m_hInfoSet.get(), (PSP_DEVINFO_DATA)&di.Data, static_cast(type), ®Type, 78 | (BYTE*)value, sizeof(value), nullptr)) { 79 | assert(regType == REG_SZ); 80 | return value; 81 | } 82 | return L""; 83 | } 84 | 85 | std::vector DeviceManager::GetDeviceRegistryPropertyMultiString(const DeviceInfo& di, DeviceRegistryPropertyType type) const { 86 | std::vector result; 87 | WCHAR buffer[1 << 11]; 88 | DWORD regType; 89 | auto ok = ::SetupDiGetDeviceRegistryProperty(m_hInfoSet.get(), (PSP_DEVINFO_DATA)&di.Data, static_cast(type), ®Type, (BYTE*)buffer, sizeof(buffer), nullptr); 90 | if (!ok) 91 | return result; 92 | 93 | assert(regType == REG_MULTI_SZ); 94 | for (auto p = buffer; *p;) { 95 | result.push_back(p); 96 | p += ::wcslen(p) + 1; 97 | } 98 | return result; 99 | } 100 | 101 | HICON DeviceManager::GetDeviceIcon(const DeviceInfo& di, bool big) const { 102 | HICON hIcon = nullptr; 103 | auto size = big ? 32 : 16; 104 | ::SetupDiLoadDeviceIcon(m_hInfoSet.get(), (PSP_DEVINFO_DATA)&di.Data, size, size, 0, &hIcon); 105 | return hIcon; 106 | } 107 | 108 | std::vector DeviceManager::EnumDrivers(DeviceInfo const& di, bool compat) const { 109 | auto devinfo = const_cast(&di.Data); 110 | if (!::SetupDiBuildDriverInfoList(m_hInfoSet.get(), devinfo, SPDIT_CLASSDRIVER)) 111 | return {}; 112 | 113 | SP_DRVINFO_DATA dd{ sizeof(dd) }; 114 | auto buffer = std::make_unique(1 << 12); 115 | auto ddd = reinterpret_cast(buffer.get()); 116 | ddd->cbSize = sizeof(*ddd); 117 | std::vector drivers; 118 | drivers.reserve(16); 119 | for (DWORD i = 0; ; i++) { 120 | if (!::SetupDiEnumDriverInfo(m_hInfoSet.get(), devinfo, SPDIT_CLASSDRIVER, i, &dd)) 121 | break; 122 | 123 | DeviceDriverInfo ddi; 124 | ddi.Description = dd.Description; 125 | ddi.DriverDate = dd.DriverDate; 126 | ddi.ManufactorName = dd.MfgName; 127 | ddi.ProviderName = dd.ProviderName; 128 | ddi.Type = dd.DriverType; 129 | ddi.DriverVersion = dd.DriverVersion; 130 | 131 | if (::SetupDiGetDriverInfoDetail(m_hInfoSet.get(), devinfo, &dd, ddd, 1 << 12, nullptr)) { 132 | ddi.DriverDesc = ddd->DrvDescription; 133 | ddi.InfFile = ddd->InfFileName; 134 | } 135 | drivers.push_back(std::move(ddi)); 136 | } 137 | ::SetupDiDestroyDriverInfoList(m_hInfoSet.get(), devinfo, SPDIT_CLASSDRIVER); 138 | return drivers; 139 | } 140 | 141 | std::unique_ptr DeviceManager::GetPropertyValue(DWORD inst, DEVPROPKEY const& key, DEVPROPTYPE& type, ULONG* len) const { 142 | ULONG size = 0; 143 | ::SetupDiGetDeviceProperty(m_hInfoSet.get(), (PSP_DEVINFO_DATA)&m_devices[m_devMap.at(inst)].Data , &key, &type, nullptr, 0, &size, 0); 144 | if (size == 0) 145 | return nullptr; 146 | 147 | auto value = std::make_unique(size); 148 | ::SetupDiGetDeviceProperty(m_hInfoSet.get(), (PSP_DEVINFO_DATA)&m_devices[m_devMap.at(inst)].Data, &key, &type, value.get(), size, &size, 0); 149 | if (len) 150 | *len = size; 151 | return value; 152 | } 153 | 154 | std::wstring DeviceManager::GetDeviceClassRegistryPropertyString(const GUID* guid, DeviceClassRegistryPropertyType type) { 155 | DWORD regType; 156 | std::wstring result; 157 | result.resize(256); 158 | if (::SetupDiGetClassRegistryProperty(guid, static_cast(type), ®Type, 159 | (BYTE*)result.data(), DWORD(result.size() * sizeof(WCHAR)), nullptr, nullptr, nullptr)) { 160 | assert(regType == REG_SZ); 161 | return result; 162 | } 163 | 164 | return L""; 165 | } 166 | 167 | std::vector DeviceManager::GetDeviceClassRegistryPropertyMultiString(const GUID* guid, DeviceClassRegistryPropertyType type) { 168 | std::vector result; 169 | WCHAR buffer[1 << 12]; 170 | DWORD regType; 171 | if (::SetupDiGetClassRegistryProperty(guid, static_cast(type), ®Type, (BYTE*)buffer, sizeof(buffer), nullptr, nullptr, nullptr)) { 172 | assert(regType == REG_MULTI_SZ); 173 | for (auto p = buffer; *p;) { 174 | result.push_back(p); 175 | p += ::wcslen(p) + 1; 176 | } 177 | } 178 | return result; 179 | } 180 | 181 | std::vector DeviceManager::EnumDeviceClasses() { 182 | GUID guid; 183 | std::vector classes; 184 | classes.reserve(64); 185 | WCHAR name[128]; 186 | for (DWORD i = 0;; i++) { 187 | if (CR_NO_SUCH_VALUE == ::CM_Enumerate_Classes(i, &guid, CM_ENUMERATE_CLASSES_INSTALLER)) 188 | break; 189 | 190 | ULONG len = _countof(name); 191 | ::CM_Get_Class_Name(&guid, name, &len, 0); 192 | DeviceClassInfo info; 193 | info.Guid = guid; 194 | info.Name = name; 195 | classes.push_back(std::move(info)); 196 | } 197 | return classes; 198 | } 199 | 200 | std::vector DeviceManager::EnumDeviceClassesGuids() { 201 | GUID guid; 202 | std::vector classes; 203 | classes.reserve(64); 204 | for (DWORD i = 0;; i++) { 205 | if (CR_NO_SUCH_VALUE == ::CM_Enumerate_Classes(i, &guid, CM_ENUMERATE_CLASSES_INSTALLER)) 206 | break; 207 | 208 | classes.push_back(guid); 209 | } 210 | return classes; 211 | } 212 | 213 | bool DeviceManager::EnumDeviceInterfaces(GUID const& guid, std::vector& vec) { 214 | SP_DEVICE_INTERFACE_DATA data = { sizeof(data) }; 215 | auto buffer = std::make_unique(2048); 216 | auto detail = reinterpret_cast(buffer.get()); 217 | SP_DEVINFO_DATA devData = { sizeof(devData) }; 218 | WCHAR name[256]; 219 | 220 | DWORD i = 0; 221 | for (;; i++) { 222 | if (!::SetupDiEnumDeviceInterfaces(m_hInfoSet.get(), nullptr, &guid, i, &data)) 223 | break; 224 | 225 | DeviceInterfaceInfo info; 226 | info.Guid = data.InterfaceClassGuid; 227 | detail->cbSize = sizeof(*detail); 228 | if (::SetupDiGetDeviceInterfaceDetail(m_hInfoSet.get(), &data, detail, 2048, nullptr, &devData) 229 | || ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 230 | auto hKey = ::SetupDiOpenDeviceInterfaceRegKey(m_hInfoSet.get(), &data, 0, KEY_READ); 231 | if (hKey != INVALID_HANDLE_VALUE) { 232 | CRegKey key(hKey); 233 | ULONG chars = _countof(name); 234 | if (ERROR_SUCCESS == key.QueryStringValue(L"FriendlyName", name, &chars)) 235 | info.FriendlyName = name; 236 | } 237 | DeviceInfo di; 238 | di.Data = devData; 239 | info.DeviceFriendlyName = GetDeviceRegistryPropertyString(di, DeviceRegistryPropertyType::FriendlyName); 240 | info.DeviceDescription = GetDeviceRegistryPropertyString(di, DeviceRegistryPropertyType::Description); 241 | info.SymbolicLink = detail->DevicePath; 242 | } 243 | vec.push_back(std::move(info)); 244 | } 245 | return i > 0; 246 | } 247 | 248 | std::vector DeviceManager::EnumDeviceInterfacesGuids() { 249 | GUID guid; 250 | std::vector guids; 251 | guids.reserve(64); 252 | for (DWORD i = 0;; i++) { 253 | if (CR_NO_SUCH_VALUE == ::CM_Enumerate_Classes(i, &guid, CM_ENUMERATE_CLASSES_INTERFACE)) 254 | break; 255 | guids.push_back(guid); 256 | } 257 | 258 | return guids; 259 | } 260 | 261 | DeviceManager::DeviceManager(const wchar_t* computerName, const GUID* classGuid, const wchar_t* enumerator, InfoSetOptions options) { 262 | m_hInfoSet.reset(::SetupDiGetClassDevsEx(classGuid, enumerator, nullptr, static_cast(options), nullptr, computerName, nullptr)); 263 | } 264 | 265 | std::vector DeviceManager::GetDeviceClassPropertyKeysCommon(GUID const& guid, bool deviceClass) { 266 | ULONG count = 0; 267 | ::CM_Get_Class_Property_Keys(&guid, nullptr, &count, deviceClass ? CM_CLASS_PROPERTY_INSTALLER : CM_CLASS_PROPERTY_INTERFACE); 268 | if (count == 0) 269 | return {}; 270 | 271 | std::vector keys; 272 | keys.resize(count); 273 | ::CM_Get_Class_Property_Keys(&guid, keys.data(), &count, deviceClass ? CM_CLASS_PROPERTY_INSTALLER : CM_CLASS_PROPERTY_INTERFACE); 274 | return keys; 275 | } 276 | 277 | int DeviceManager::GetDeviceIndex(DEVINST inst) const { 278 | if (auto it = m_devMap.find(inst); it != m_devMap.end()) 279 | return it->second; 280 | return -1; 281 | } 282 | 283 | std::unique_ptr DeviceManager::GetClassPropertyValue(GUID const& guid, DEVPROPKEY const& key, DEVPROPTYPE& type, ULONG* len, bool iface) { 284 | ULONG size = 0; 285 | ::CM_Get_Class_Property(&guid, &key, &type, nullptr, &size, iface ? CM_CLASS_PROPERTY_INTERFACE : CM_CLASS_PROPERTY_INSTALLER); 286 | if (size) { 287 | auto value = std::make_unique(size); 288 | ::CM_Get_Class_Property(&guid, &key, &type, value.get(), &size, iface ? CM_CLASS_PROPERTY_INTERFACE : CM_CLASS_PROPERTY_INSTALLER); 289 | if (len) 290 | *len = size; 291 | return value; 292 | } 293 | return nullptr; 294 | } 295 | 296 | std::vector DeviceManager::BuildClassInfoList(DWORD flags) { 297 | DWORD count = 0; 298 | ::SetupDiBuildClassInfoList(flags, nullptr, 0, &count); 299 | if (count > 0) { 300 | std::vector guids(count); 301 | ::SetupDiBuildClassInfoList(flags, guids.data(), count, &count); 302 | return guids; 303 | } 304 | return {}; 305 | } 306 | 307 | std::wstring DeviceManager::GetSetupClassDescription(GUID const& guid) { 308 | WCHAR desc[256]; 309 | ::SetupDiGetClassDescription(&guid, desc, _countof(desc), nullptr); 310 | return desc; 311 | } 312 | 313 | std::wstring DeviceManager::GetDeviceInterfaceName(GUID const& guid) { 314 | auto name = GetDeviceInterfaceProperty(guid, DEVPKEY_NAME); 315 | if(name.empty()) 316 | name = GetDeviceInterfaceProperty(guid, DEVPKEY_DeviceInterface_FriendlyName); 317 | if (name.empty()) 318 | name = GetDeviceInterfaceProperty(guid, DEVPKEY_DeviceClass_ClassName); 319 | if (name.empty()) 320 | name = GetDeviceClassDescription(guid); 321 | if (name.empty()) { 322 | WCHAR sguid[64]; 323 | ::StringFromGUID2(guid, sguid, _countof(sguid)); 324 | name = sguid; 325 | } 326 | return name; 327 | } 328 | 329 | DeviceInfo const& DeviceManager::GetDevice(int index) const { 330 | return m_devices[index]; 331 | } 332 | 333 | bool DeviceManager::GetPropertyPages(PROPSHEETHEADER& header, DeviceInfo const& di, uint32_t maxPages) const { 334 | return ::SetupDiGetClassDevPropertySheets(m_hInfoSet.get(), (PSP_DEVINFO_DATA)&di.Data, &header, maxPages, nullptr, DIGCDP_FLAG_ADVANCED); 335 | } 336 | -------------------------------------------------------------------------------- /DevExpCore/DeviceManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "DeviceNode.h" 6 | 7 | namespace wil { 8 | using unique_hinfoset = unique_any_handle_invalid; 9 | } 10 | 11 | template<> 12 | struct std::hash { 13 | size_t operator()(const GUID& key) const { 14 | return key.Data1 ^ ((key.Data3 << 16) | key.Data2); 15 | } 16 | }; 17 | 18 | struct DeviceInterfaceInfo { 19 | std::wstring FriendlyName; 20 | std::wstring SymbolicLink; 21 | std::wstring DeviceFriendlyName; 22 | std::wstring DeviceDescription; 23 | GUID Guid; 24 | }; 25 | 26 | struct DeviceClassInfo { 27 | GUID Guid; 28 | std::wstring Name; 29 | }; 30 | 31 | struct HardwareProfile { 32 | uint32_t Index; 33 | std::wstring FriendlyName; 34 | }; 35 | 36 | enum class DeviceClassRegistryPropertyType { 37 | Characteristics = SPCRP_CHARACTERISTICS, 38 | DeviceType = SPCRP_DEVTYPE, 39 | UpperFilters = SPCRP_UPPERFILTERS, 40 | LowerFilters = SPCRP_LOWERFILTERS, 41 | Exclusive = SPCRP_EXCLUSIVE, 42 | SecurityDescriptor = SPCRP_SECURITY, 43 | SecurityDescriptionString = SPCRP_SECURITY_SDS 44 | }; 45 | 46 | enum class DeviceRegistryPropertyType { 47 | Description = SPDRP_DEVICEDESC, 48 | HardwareId = SPDRP_HARDWAREID, 49 | CompatibleIds = SPDRP_COMPATIBLEIDS, 50 | Service = SPDRP_SERVICE, 51 | Class = SPDRP_CLASS, 52 | ClassGuid = SPDRP_CLASSGUID, 53 | Driver = SPDRP_DRIVER, 54 | ConfigFlags = SPDRP_CONFIGFLAGS, 55 | Mfg = SPDRP_MFG, 56 | FriendlyName = SPDRP_FRIENDLYNAME, 57 | UpperFilters = SPDRP_UPPERFILTERS, 58 | LowerFilters = SPDRP_LOWERFILTERS, 59 | Capabilities = SPDRP_CAPABILITIES, 60 | PdoName = SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, 61 | Enumerator = SPDRP_ENUMERATOR_NAME, 62 | Location = SPDRP_LOCATION_INFORMATION, 63 | UINumber = SPDRP_UI_NUMBER, 64 | BusTypeGuid = SPDRP_BUSTYPEGUID, 65 | Exclusive = SPDRP_EXCLUSIVE, 66 | DeviceType = SPDRP_DEVTYPE, 67 | BusNumber = SPDRP_BUSNUMBER, 68 | Address = SPDRP_ADDRESS, 69 | Characteristics = SPDRP_CHARACTERISTICS, 70 | LegacyBusType = SPDRP_LEGACYBUSTYPE, 71 | InstallState = SPDRP_INSTALL_STATE, 72 | PowerData = SPDRP_DEVICE_POWER_DATA, 73 | SecurityDescriptor = SPDRP_SECURITY, 74 | SecurityDescriptorString = SPDRP_SECURITY_SDS, 75 | LocationPaths = SPDRP_LOCATION_PATHS, 76 | UINumberDescFormat = SPDRP_UI_NUMBER_DESC_FORMAT, 77 | RemovalPolicy = SPDRP_REMOVAL_POLICY, 78 | RemovalPolicyHwDefault = SPDRP_REMOVAL_POLICY_HW_DEFAULT, 79 | RemovalPolicyOverride = SPDRP_REMOVAL_POLICY_OVERRIDE, 80 | BaseContainerId = SPDRP_BASE_CONTAINERID 81 | }; 82 | 83 | enum class InfoSetOptions { 84 | AllClasses = DIGCF_ALLCLASSES, 85 | Profile = DIGCF_PROFILE, 86 | Present = DIGCF_PRESENT, 87 | Default = DIGCF_DEFAULT, 88 | DeviceInterface = DIGCF_DEVICEINTERFACE 89 | }; 90 | DEFINE_ENUM_FLAG_OPERATORS(InfoSetOptions); 91 | 92 | struct DeviceInfo { 93 | std::wstring Description; 94 | SP_DEVINFO_DATA Data; 95 | }; 96 | 97 | struct DeviceDriverInfo { 98 | std::wstring Description; 99 | std::wstring ManufactorName; 100 | std::wstring ProviderName; 101 | FILETIME DriverDate; 102 | DWORDLONG DriverVersion; 103 | std::wstring DriverDesc; 104 | std::wstring InfFile; 105 | DWORD Type; 106 | }; 107 | 108 | class DeviceManager final { 109 | public: 110 | static std::unique_ptr Create(const wchar_t* computerName = nullptr, const GUID* classGuid = nullptr, const wchar_t* enumerator = nullptr, 111 | InfoSetOptions options = InfoSetOptions::Present | InfoSetOptions::AllClasses); 112 | 113 | template requires (std::is_base_of_v) 114 | std::vector EnumDevices(bool includeHidden = false); 115 | static std::wstring GetDeviceClassDescription(GUID const& guid, const wchar_t* computerName = nullptr); 116 | static HIMAGELIST GetClassImageList(); 117 | static int GetClassImageIndex(GUID const& guid); 118 | static std::vector GetClassPropertyKeys(GUID const& guid); 119 | static std::vector EnumHardwareProfiles(PCWSTR computerName = nullptr); 120 | static std::vector GetDeviceClassPropertyKeys(GUID const& guid); 121 | static std::vector GetDeviceInterfacePropertyKeys(GUID const& guid); 122 | static std::unique_ptr GetClassPropertyValue(GUID const& guid, DEVPROPKEY const& key, DEVPROPTYPE& type, ULONG* len, bool iface = false); 123 | static std::vector BuildClassInfoList(DWORD flags = DIBCI_NOINSTALLCLASS | DIBCI_NODISPLAYCLASS); 124 | static std::wstring GetSetupClassDescription(GUID const& guid); 125 | 126 | static DeviceNode GetRootDeviceNode(); 127 | 128 | bool GetPropertyPages(PROPSHEETHEADER& header, DeviceInfo const& di, uint32_t maxPages) const; 129 | 130 | HDEVINFO InfoSet() { 131 | return m_hInfoSet.get(); 132 | } 133 | 134 | // device 135 | std::wstring GetDeviceRegistryPropertyString(const DeviceInfo& di, DeviceRegistryPropertyType type) const; 136 | std::vector GetDeviceRegistryPropertyMultiString(const DeviceInfo& di, DeviceRegistryPropertyType type) const; 137 | template 138 | T GetDeviceRegistryProperty(const DeviceInfo& di, DeviceRegistryPropertyType type) const; 139 | HICON GetDeviceIcon(const DeviceInfo& di, bool big = false) const; 140 | DeviceInfo const& GetDevice(int index) const; 141 | std::vector EnumDrivers(DeviceInfo const& di, bool compat = false) const; 142 | //std::vector EnumDrivers(); 143 | 144 | std::unique_ptr GetPropertyValue(DWORD inst, DEVPROPKEY const& key, DEVPROPTYPE& type, ULONG* len = nullptr) const; 145 | 146 | // device class 147 | static std::wstring GetDeviceClassRegistryPropertyString(const GUID* guid, DeviceClassRegistryPropertyType type); 148 | static std::vector GetDeviceClassRegistryPropertyMultiString(const GUID* guid, DeviceClassRegistryPropertyType type); 149 | static std::vector EnumDeviceClasses(); 150 | static std::vector EnumDeviceClassesGuids(); 151 | 152 | template 153 | static T GetDeviceClassRegistryProperty(const GUID* guid, DeviceClassRegistryPropertyType type); 154 | 155 | bool EnumDeviceInterfaces(GUID const& guid, std::vector& vec); 156 | static std::vector EnumDeviceInterfaces(); 157 | static std::vector EnumDeviceInterfacesGuids(); 158 | static std::wstring GetDeviceInterfaceName(GUID const& guid); 159 | 160 | template 161 | DeviceInfo const* FindDevice(F&& f) const { 162 | for (auto const& dev : m_devices) 163 | if (f(dev)) 164 | return &dev; 165 | return nullptr; 166 | } 167 | 168 | template 169 | static T GetDeviceInterfaceProperty(GUID const& guid, DEVPROPKEY const& key) { 170 | T value{}; 171 | ULONG size = sizeof(T); 172 | WCHAR sguid[64]; 173 | ::StringFromGUID2(guid, sguid, _countof(sguid)); 174 | DEVPROPTYPE type; 175 | ::CM_Get_Device_Interface_Property(sguid, &key, &type, &value, &size, 0); 176 | return value; 177 | } 178 | 179 | template<> 180 | static std::wstring GetDeviceInterfaceProperty(GUID const& guid, DEVPROPKEY const& key) { 181 | DEVPROPTYPE type; 182 | ULONG size = 0; 183 | WCHAR sguid[64]; 184 | if (0 == ::StringFromGUID2(guid, sguid, _countof(sguid))) 185 | return L""; 186 | 187 | if (CR_BUFFER_SMALL != ::CM_Get_Device_Interface_Property(sguid, &key, &type, nullptr, &size, 0)) 188 | return L""; 189 | 190 | assert(type == DEVPROP_TYPE_STRING); 191 | if (type != DEVPROP_TYPE_STRING) 192 | return L""; 193 | std::wstring value; 194 | value.resize(size / sizeof(WCHAR)); 195 | ::CM_Get_Device_Interface_Property(sguid, &key, &type, (PBYTE)value.data(), &size, 0); 196 | return value; 197 | } 198 | 199 | int GetDeviceIndex(DEVINST inst) const; 200 | 201 | template 202 | T GetProperty(DWORD inst, DEVPROPKEY const& key) const { 203 | T value{}; 204 | ULONG size = sizeof(T); 205 | DEVPROPTYPE type; 206 | ::SetupDiGetDeviceProperty(m_hInfoSet.get(), (PSP_DEVINFO_DATA)&m_devices[m_devMap.at(inst)].Data, &key, &type, &value, size, &size, 0); 207 | return value; 208 | } 209 | 210 | template<> 211 | std::wstring GetProperty(DWORD inst, DEVPROPKEY const& key) const { 212 | DEVPROPTYPE type; 213 | auto buffer = GetPropertyValue(inst, key, type, nullptr); 214 | if (buffer == nullptr) 215 | return L""; 216 | 217 | assert(type == DEVPROP_TYPE_STRING); 218 | if (type != DEVPROP_TYPE_STRING) 219 | return L""; 220 | 221 | return (PCWSTR)buffer.get(); 222 | } 223 | 224 | private: 225 | DeviceManager(const wchar_t* computerName = nullptr, const GUID* classGuid = nullptr, const wchar_t* enumerator = nullptr, 226 | InfoSetOptions options = InfoSetOptions::Present | InfoSetOptions::AllClasses); 227 | 228 | static std::vector GetDeviceClassPropertyKeysCommon(GUID const& guid, bool deviceClass); 229 | 230 | private: 231 | wil::unique_hinfoset m_hInfoSet; 232 | std::vector m_devices; 233 | std::unordered_map m_devMap; 234 | }; 235 | 236 | template 237 | inline T DeviceManager::GetDeviceRegistryProperty(const DeviceInfo& di, DeviceRegistryPropertyType type) const { 238 | static_assert(std::is_trivially_copyable()); 239 | T result{}; 240 | 241 | ::SetupDiGetDeviceRegistryProperty(m_hInfoSet.get(), (PSP_DEVINFO_DATA)&di.Data, static_cast(type), nullptr, 242 | (BYTE*)&result, sizeof(T), nullptr); 243 | return result; 244 | } 245 | 246 | template 247 | inline T DeviceManager::GetDeviceClassRegistryProperty(const GUID* guid, DeviceClassRegistryPropertyType type) { 248 | static_assert(std::is_trivially_copyable()); 249 | T result{}; 250 | DWORD regType; 251 | if (::SetupDiGetClassRegistryProperty(guid, static_cast(type), ®Type, 252 | (BYTE*)&result, sizeof(T), nullptr, nullptr, nullptr)) { 253 | } 254 | return result; 255 | } 256 | 257 | template requires (std::is_base_of_v) 258 | std::vector DeviceManager::EnumDevices(bool includeHidden) { 259 | std::vector devices; 260 | SP_DEVINFO_DATA data = { sizeof(data) }; 261 | m_devMap.clear(); 262 | m_devices.clear(); 263 | auto root = GetRootDeviceNode(); 264 | 265 | for (DWORD i = 0; ; i++) { 266 | if (!::SetupDiEnumDeviceInfo(m_hInfoSet.get(), i, &data)) 267 | break; 268 | 269 | if (data.DevInst != (DEVINST)root && !includeHidden && (DeviceNode(data.DevInst).GetStatus() & DeviceNodeStatus::NoShowInDeviceManager) == DeviceNodeStatus::NoShowInDeviceManager) 270 | continue; 271 | 272 | T di; 273 | di.Description = DeviceNode(data.DevInst).GetName(); 274 | di.Data = data; 275 | m_devMap.insert({ data.DevInst, (int)devices.size() }); 276 | m_devices.push_back(di); 277 | devices.push_back(std::move(di)); 278 | } 279 | 280 | return devices; 281 | } 282 | -------------------------------------------------------------------------------- /DevExpCore/DeviceNode.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DeviceNode.h" 3 | #include 4 | 5 | std::wstring DeviceNode::GetName() const { 6 | return GetProperty(DEVPKEY_NAME); 7 | } 8 | 9 | std::vector DeviceNode::GetChildDevNodes(DeviceNode const& inst) { 10 | DEVINST child; 11 | std::vector devnodes; 12 | devnodes.reserve(8); 13 | DeviceNode start(inst); 14 | if (CR_SUCCESS == ::CM_Get_Child(&child, start, 0)) { 15 | devnodes.push_back(child); 16 | auto siblings = GetSiblingDevNodes(child); 17 | devnodes.insert(devnodes.end(), siblings.begin(), siblings.end()); 18 | } 19 | 20 | return devnodes; 21 | } 22 | 23 | std::vector DeviceNode::GetSiblingDevNodes(DeviceNode const& inst) { 24 | DEVINST sibling; 25 | std::vector devnodes; 26 | devnodes.reserve(8); 27 | DeviceNode start(inst); 28 | while (CR_SUCCESS == ::CM_Get_Sibling(&sibling, start, 0)) { 29 | devnodes.push_back(sibling); 30 | start = sibling; 31 | } 32 | 33 | return devnodes; 34 | } 35 | 36 | std::vector DeviceNode::GetChildren() const { 37 | return GetChildDevNodes(m_Inst); 38 | } 39 | 40 | std::vector DeviceNode::GetSiblings() const { 41 | return GetSiblingDevNodes(m_Inst); 42 | } 43 | 44 | std::vector DeviceNode::GetPropertyKeys() const { 45 | std::vector keys; 46 | ULONG count = 0; 47 | ::CM_Get_DevNode_Property_Keys(m_Inst, nullptr, &count, 0); 48 | if (count) { 49 | keys.resize(count); 50 | ::CM_Get_DevNode_Property_Keys(m_Inst, keys.data(), &count, 0); 51 | } 52 | return keys; 53 | } 54 | 55 | bool DeviceNode::Enable() { 56 | return ::CM_Enable_DevNode(m_Inst, 0) == CR_SUCCESS; 57 | } 58 | 59 | bool DeviceNode::Disable() { 60 | return ::CM_Disable_DevNode(m_Inst, 0) == CR_SUCCESS; 61 | } 62 | 63 | bool DeviceNode::Uninstall() { 64 | return ::CM_Uninstall_DevNode(m_Inst, 0) == CR_SUCCESS; 65 | } 66 | 67 | bool DeviceNode::Rescan() { 68 | return ::CM_Reenumerate_DevInst(m_Inst, CM_REENUMERATE_NORMAL) == CR_SUCCESS; 69 | } 70 | 71 | bool DeviceNode::IsEnabled() const { 72 | DeviceNodeProblem problem; 73 | return !((GetStatus(&problem) & DeviceNodeStatus::HasProblem) == DeviceNodeStatus::HasProblem && problem == DeviceNodeProblem::DISABLED); 74 | } 75 | 76 | DEVPROPTYPE DeviceNode::GetPropertyType(DEVPROPKEY const& key) const { 77 | DEVPROPTYPE type; 78 | ULONG size = 0; 79 | ::CM_Get_DevNode_Property(m_Inst, &key, &type, nullptr, &size, 0); 80 | return type; 81 | } 82 | 83 | DeviceNodeStatus DeviceNode::GetStatus(DeviceNodeProblem* pProblem) const { 84 | ULONG status, problem; 85 | if (CR_SUCCESS == ::CM_Get_DevNode_Status(&status, &problem, m_Inst, 0)) { 86 | if (pProblem) 87 | *pProblem = static_cast(problem); 88 | return static_cast(status); 89 | } 90 | return DeviceNodeStatus::None; 91 | } 92 | 93 | std::vector DeviceNode::GetResources(LogicalConfigurationType type) { 94 | LOG_CONF log = 0; 95 | std::vector resources; 96 | if (CR_SUCCESS != ::CM_Get_First_Log_Conf(&log, m_Inst, static_cast(type))) 97 | return resources; 98 | 99 | resources.reserve(16); 100 | do { 101 | RES_DES rd = 0; 102 | RESOURCEID r = ResType_All; 103 | while (CR_SUCCESS == ::CM_Get_Next_Res_Des(&rd, rd ? rd : log, ResType_All, &r, 0)) { 104 | ULONG size = 0; 105 | ::CM_Get_Res_Des_Data_Size(&size, rd, 0); 106 | auto buffer = std::make_unique(size); 107 | if (CR_SUCCESS == ::CM_Get_Res_Des_Data(rd, buffer.get(), size, 0)) { 108 | if (r == ResType_None || r == ResType_DevicePrivate) 109 | continue; 110 | DeviceResource res; 111 | res.Type = (ResourceType)r; 112 | res.m_buffer = std::move(buffer); 113 | res.m_size = size; 114 | resources.push_back(std::move(res)); 115 | } 116 | } 117 | } while (::CM_Get_Next_Log_Conf(&log, log, 0) == CR_SUCCESS); 118 | 119 | CM_Free_Log_Conf(log, 0); 120 | 121 | return resources; 122 | } 123 | 124 | std::unique_ptr DeviceNode::GetPropertyValue(DEVPROPKEY const& key, DEVPROPTYPE& type, ULONG* len) const { 125 | ULONG size = 0; 126 | ::CM_Get_DevNode_Property(m_Inst, &key, &type, nullptr, &size, 0); 127 | auto value = std::make_unique(size); 128 | ::CM_Get_DevNode_Property(m_Inst, &key, &type, value.get(), &size, 0); 129 | if (len) 130 | *len = size; 131 | return value; 132 | } 133 | 134 | DeviceNode DeviceNode::GetParent() const { 135 | DEVINST parent; 136 | return CR_SUCCESS == ::CM_Get_Parent(&parent, m_Inst, 0) ? parent : -1; 137 | } 138 | 139 | ULONG DeviceNode::GetDepth() const { 140 | ULONG depth = -1; 141 | ::CM_Get_Depth(&depth, m_Inst, 0); 142 | return depth; 143 | } 144 | -------------------------------------------------------------------------------- /DevExpCore/DeviceNode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class DeviceNodeStatus : uint32_t { 4 | None = 0, 5 | RootEnumerated = DN_ROOT_ENUMERATED, 6 | DriverLoaded = DN_DRIVER_LOADED, 7 | EnumLoaded = DN_ENUM_LOADED, 8 | Started = DN_STARTED, 9 | Manual = DN_MANUAL, 10 | NeedToEnum = DN_NEED_TO_ENUM, 11 | NotFirstTime = DN_NOT_FIRST_TIME, 12 | HardwareEnum = DN_HARDWARE_ENUM, 13 | Liar = DN_LIAR, 14 | HasMark = DN_HAS_MARK, 15 | HasProblem = DN_HAS_PROBLEM, 16 | Filtered = DN_FILTERED, 17 | Moved = DN_MOVED, 18 | Disableable = DN_DISABLEABLE, 19 | Removable = DN_REMOVABLE, 20 | PrivateProblem = DN_PRIVATE_PROBLEM, 21 | MfParent = DN_MF_PARENT, 22 | MfChild = DN_MF_CHILD, 23 | WillBeRmoved = DN_WILL_BE_REMOVED, 24 | NotFirstTimeEnum = DN_NOT_FIRST_TIMEE, 25 | StopFreeResources = DN_STOP_FREE_RES, 26 | RealCandidate = DN_REBAL_CANDIDATE, 27 | BadPartial = DN_BAD_PARTIAL, 28 | NtEnumerator = DN_NT_ENUMERATOR, 29 | NtDriver = DN_NT_DRIVER, 30 | NeedsLocking = DN_NEEDS_LOCKING, 31 | ArmWakeup = DN_ARM_WAKEUP, 32 | ApmEnumerator = DN_APM_ENUMERATOR, 33 | ApmDriver = DN_APM_DRIVER, 34 | SilentInstall = DN_SILENT_INSTALL, 35 | NoShowInDeviceManager = DN_NO_SHOW_IN_DM, 36 | BootLogProblem = DN_BOOT_LOG_PROB, 37 | }; 38 | DEFINE_ENUM_FLAG_OPERATORS(DeviceNodeStatus); 39 | 40 | enum class DeviceNodeProblem { 41 | None = 0, 42 | NotConfigured, 43 | DEVLOADER_FAILED, 44 | OUT_OF_MEMORY, 45 | ENTRY_IS_WRONG_TYPE, 46 | LACKED_ARBITRATOR, 47 | BOOT_CONFIG_CONFLICT, 48 | FAILED_FILTER, 49 | DEVLOADER_NOT_FOUND, 50 | INVALID_DATA, 51 | FAILED_START, 52 | LIAR, 53 | NORMAL_CONFLICT, 54 | NOT_VERIFIED, 55 | NEED_RESTART, 56 | REENUMERATION, 57 | PARTIAL_LOG_CONF, 58 | UNKNOWN_RESOURCE, 59 | REINSTALL, 60 | REGISTRY, 61 | VXDLDR, 62 | WILL_BE_REMOVED, 63 | DISABLED, 64 | DEVLOADER_NOT_READY, 65 | DEVICE_NOT_THERE, 66 | MOVED, 67 | TOO_EARLY, 68 | NO_VALID_LOG_CONF, 69 | FAILED_INSTALL, 70 | HARDWARE_DISABLED, 71 | CANT_SHARE_IRQ, 72 | FAILED_ADD, 73 | DISABLED_SERVICE, 74 | TRANSLATION_FAILED, 75 | NO_SOFTCONFIG, 76 | BIOS_TABLE, 77 | IRQ_TRANSLATION_FAILED, 78 | FAILED_DRIVER_ENTRY, 79 | DRIVER_FAILED_PRIOR_UNLOAD, 80 | DRIVER_FAILED_LOAD, 81 | DRIVER_SERVICE_KEY_INVALID, 82 | LEGACY_SERVICE_NO_DEVICES, 83 | DUPLICATE_DEVICE, 84 | FAILED_POST_START, 85 | HALTED, 86 | PHANTOM, 87 | SYSTEM_SHUTDOWN, 88 | HELD_FOR_EJECT, 89 | DRIVER_BLOCKED, 90 | REGISTRY_TOO_LARGE, 91 | SETPROPERTIES_FAILED, 92 | WAITING_ON_DEPENDENCY, 93 | UNSIGNED_DRIVER, 94 | USED_BY_DEBUGGER, 95 | DEVICE_RESET, 96 | CONSOLE_LOCKED, 97 | NEED_CLASS_CONFIG, 98 | GUEST_ASSIGNMENT_FAILED, 99 | }; 100 | 101 | enum class ResourceType { 102 | Memory = ResType_Mem, 103 | Interrupt = ResType_IRQ, 104 | IO = ResType_IO, 105 | LargeMemory = ResType_MemLarge, 106 | BusNumber = ResType_BusNumber, 107 | DMA = ResType_DMA, 108 | Private = ResType_DevicePrivate, 109 | PCCardConfig = ResType_PcCardConfig, 110 | MFCardConfig = ResType_MfCardConfig, 111 | ClassSpecific = ResType_ClassSpecific, 112 | 113 | }; 114 | DEFINE_ENUM_FLAG_OPERATORS(ResourceType); 115 | 116 | enum class LogicalConfigurationType { 117 | Basic = BASIC_LOG_CONF, 118 | Filtered = FILTERED_LOG_CONF, 119 | Allocated = ALLOC_LOG_CONF, 120 | Boot = BOOT_LOG_CONF, 121 | Forced = FORCED_LOG_CONF, 122 | Override = OVERRIDE_LOG_CONF, 123 | }; 124 | 125 | struct DeviceResource { 126 | ResourceType Type; 127 | IO_RESOURCE& IO() const { 128 | return *(IO_RESOURCE*)m_buffer.get(); 129 | } 130 | IRQ_RESOURCE& Interrupt() const { 131 | return *(IRQ_RESOURCE*)m_buffer.get(); 132 | } 133 | MEM_RESOURCE& Memory() const { 134 | return *(MEM_RESOURCE*)m_buffer.get(); 135 | } 136 | MEM_LARGE_RESOURCE& LargeMemory() const { 137 | return *(MEM_LARGE_RESOURCE*)m_buffer.get(); 138 | } 139 | BUSNUMBER_RESOURCE& BusNumber() const { 140 | return *(BUSNUMBER_RESOURCE*)m_buffer.get(); 141 | } 142 | BYTE* Buffer() const { 143 | return m_buffer.get(); 144 | } 145 | ULONG Size() const { 146 | return m_size; 147 | } 148 | private: 149 | friend class DeviceNode; 150 | std::unique_ptr m_buffer; 151 | ULONG m_size; 152 | }; 153 | 154 | class DeviceNode { 155 | public: 156 | DeviceNode(DEVINST inst) : m_Inst(inst) {} 157 | 158 | operator DEVINST() const { 159 | return m_Inst; 160 | } 161 | 162 | bool IsValid() const { 163 | return m_Inst != -1; 164 | } 165 | 166 | static std::vector GetChildDevNodes(DeviceNode const& inst); 167 | static std::vector GetSiblingDevNodes(DeviceNode const& inst); 168 | 169 | std::vector GetChildren() const; 170 | std::vector GetSiblings() const; 171 | DeviceNode GetParent() const; 172 | std::vector GetPropertyKeys() const; 173 | std::wstring GetName() const; 174 | 175 | DEVPROPTYPE GetPropertyType(DEVPROPKEY const& key) const; 176 | 177 | bool Enable(); 178 | bool Disable(); 179 | bool Uninstall(); 180 | bool Rescan(); 181 | bool IsEnabled() const; 182 | ULONG GetDepth() const; 183 | 184 | std::unique_ptr GetPropertyValue(DEVPROPKEY const& key, DEVPROPTYPE& type, ULONG* len = nullptr) const; 185 | 186 | template 187 | T GetProperty(DEVPROPKEY const& key) const { 188 | T value{}; 189 | ULONG size = sizeof(T); 190 | ::CM_Get_DevNode_Property(m_Inst, &key, nullptr, (PBYTE)&value, &size, 0); 191 | return value; 192 | } 193 | 194 | template<> 195 | std::wstring GetProperty(DEVPROPKEY const& key) const { 196 | DEVPROPTYPE type; 197 | ULONG size = 0; 198 | if (CR_BUFFER_SMALL != ::CM_Get_DevNode_Property(m_Inst, &key, &type, nullptr, &size, 0)) 199 | return L""; 200 | 201 | assert(type == DEVPROP_TYPE_STRING); 202 | if (type != DEVPROP_TYPE_STRING) 203 | return L""; 204 | auto value = std::make_unique(size); 205 | ::CM_Get_DevNode_Property(m_Inst, &key, &type, (PBYTE)value.get(), &size, 0); 206 | return value.get(); 207 | } 208 | 209 | template<> 210 | std::vector GetProperty(DEVPROPKEY const& key) const { 211 | DEVPROPTYPE type; 212 | ULONG size = 0; 213 | if(CR_BUFFER_SMALL != ::CM_Get_DevNode_Property(m_Inst, &key, &type, nullptr, &size, 0)) 214 | return {}; 215 | 216 | assert(type == DEVPROP_TYPE_STRING_LIST); 217 | if (type != DEVPROP_TYPE_STRING_LIST) 218 | return {}; 219 | std::vector value; 220 | auto buffer = std::make_unique(size / sizeof(WCHAR)); 221 | ::CM_Get_DevNode_Property(m_Inst, &key, &type, (PBYTE)buffer.get(), &size, 0); 222 | auto p = buffer.get(); 223 | while (*p) { 224 | value.push_back(p); 225 | p += wcslen(p) + 1; 226 | } 227 | return value; 228 | } 229 | 230 | DeviceNodeStatus GetStatus(DeviceNodeProblem* problem = nullptr) const; 231 | 232 | std::vector GetResources(LogicalConfigurationType type = LogicalConfigurationType::Allocated); 233 | 234 | private: 235 | DEVINST m_Inst; 236 | }; 237 | 238 | -------------------------------------------------------------------------------- /DevExpCore/DriverManager.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DriverManager.h" 3 | 4 | std::vector DriverManager::EnumKernelDrivers(bool runningOnly) { 5 | wil::unique_schandle hScm(::OpenSCManager(nullptr, nullptr, SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT)); 6 | if (!hScm) 7 | return {}; 8 | 9 | DWORD size = 0; 10 | DWORD count = 0; 11 | ::EnumServicesStatusEx(hScm.get(), SC_ENUM_PROCESS_INFO, SERVICE_DRIVER, SERVICE_ACTIVE | (runningOnly ? 0 : SERVICE_INACTIVE), 12 | nullptr, 0, &size, &count, nullptr, nullptr); 13 | if (size == 0) 14 | return {}; 15 | 16 | auto buffer = std::make_unique(size); 17 | if (!::EnumServicesStatusEx(hScm.get(), SC_ENUM_PROCESS_INFO, SERVICE_DRIVER, SERVICE_ACTIVE | (runningOnly ? 0 : SERVICE_INACTIVE), 18 | buffer.get(), size, &size, &count, nullptr, nullptr)) 19 | return {}; 20 | 21 | std::vector drivers; 22 | drivers.reserve(count); 23 | auto info = (ENUM_SERVICE_STATUS_PROCESS*)buffer.get(); 24 | auto svcBuffer = std::make_unique(1 << 12); 25 | auto config = (QUERY_SERVICE_CONFIG*)svcBuffer.get(); 26 | 27 | for (DWORD i = 0; i < count; i++) { 28 | DriverInfo di; 29 | auto& dinfo = info[i]; 30 | di.Name = dinfo.lpServiceName; 31 | di.DisplayName = dinfo.lpDisplayName; 32 | auto& status = dinfo.ServiceStatusProcess; 33 | di.Type = (DeviceDriverType)status.dwServiceType; 34 | di.State = (DriverState)status.dwCurrentState; 35 | wil::unique_schandle hService(::OpenService(hScm.get(), dinfo.lpServiceName, SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS)); 36 | if (hService && ::QueryServiceConfig(hService.get(), config, 1 << 12, &size)) { 37 | di.ErrorControl = (DriverErrorControl)config->dwErrorControl; 38 | di.ImagePath = config->lpBinaryPathName; 39 | di.StartType = (DriverStartType)config->dwStartType; 40 | } 41 | else { 42 | continue; 43 | } 44 | 45 | // 46 | // look up KMDF details (if any) 47 | // 48 | CRegKey key; 49 | key.Open(HKEY_LOCAL_MACHINE, (LR"(System\CurrentControlSet\Services\)" + di.Name + LR"(\Parameters\WDF)").c_str(), KEY_READ); 50 | if (key) { 51 | di.Type |= DeviceDriverType::KMDF; 52 | key.QueryDWORDValue(L"WdfMajorVersion", (DWORD&)di.MajorVersion); 53 | key.QueryDWORDValue(L"WdfMinorVersion", (DWORD&)di.MinorVersion); 54 | } 55 | drivers.push_back(std::move(di)); 56 | } 57 | 58 | return drivers; 59 | } 60 | 61 | bool DriverManager::Start(std::wstring_view name) { 62 | wil::unique_schandle hScm(::OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS)); 63 | if (!hScm) 64 | return false; 65 | 66 | wil::unique_schandle hService(::OpenService(hScm.get(), name.data(), SERVICE_START)); 67 | if (!hScm) 68 | return false; 69 | 70 | return ::StartService(hService.get(), 0, nullptr); 71 | } 72 | 73 | bool DriverManager::Stop(std::wstring_view name) { 74 | wil::unique_schandle hScm(::OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS)); 75 | if (!hScm) 76 | return false; 77 | 78 | wil::unique_schandle hService(::OpenService(hScm.get(), name.data(), SERVICE_STOP)); 79 | if (!hScm) 80 | return false; 81 | 82 | SERVICE_STATUS status; 83 | return ::ControlService(hService.get(), SERVICE_CONTROL_STOP, &status); 84 | } 85 | -------------------------------------------------------------------------------- /DevExpCore/DriverManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class DeviceDriverType { 4 | Kernel = 1, 5 | FileSystem = 2, 6 | TypeMask = 15, 7 | KMDF = 0x20, 8 | UMDF = 0x40, 9 | }; 10 | DEFINE_ENUM_FLAG_OPERATORS(DeviceDriverType); 11 | 12 | enum class DriverStartType { 13 | Boot, 14 | System, 15 | Auto, 16 | Demand, 17 | Disabled 18 | }; 19 | 20 | enum class DriverState { 21 | Stopped = 1, 22 | StartPending, 23 | StopPending, 24 | Running, 25 | ContinuePending, 26 | PausePending, 27 | Paused 28 | }; 29 | 30 | enum class DriverErrorControl { 31 | Ignore, 32 | Normal, 33 | Severe, 34 | Critical, 35 | }; 36 | 37 | struct DriverInfo { 38 | std::wstring Name; 39 | std::wstring DisplayName; 40 | std::wstring ImagePath; 41 | DeviceDriverType Type; 42 | DriverStartType StartType; 43 | DriverState State; 44 | DriverErrorControl ErrorControl; 45 | uint32_t MajorVersion{ 0 }, MinorVersion{ 0 }; 46 | }; 47 | 48 | class DriverManager { 49 | public: 50 | static std::vector EnumKernelDrivers(bool runningOnly = false); 51 | static std::vector EnumUserDrivers(bool runningOnly = false); 52 | static bool Start(std::wstring_view name); 53 | static bool Stop(std::wstring_view name); 54 | }; 55 | 56 | -------------------------------------------------------------------------------- /DevExpCore/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /DevExpCore/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: source file corresponding to the pre-compiled header 2 | 3 | #include "pch.h" 4 | 5 | // When you are using pre-compiled headers, this source file is necessary for compilation to succeed. 6 | -------------------------------------------------------------------------------- /DevExpCore/pch.h: -------------------------------------------------------------------------------- 1 | // pch.h: This is a precompiled header file. 2 | // Files listed below are compiled only once, improving build performance for future builds. 3 | // This also affects IntelliSense performance, including code completion and many code browsing features. 4 | // However, files listed here are ALL re-compiled if any one of them is updated between builds. 5 | // Do not add files here that you will be updating frequently as this negates the performance advantage. 6 | 7 | #ifndef PCH_H 8 | #define PCH_H 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #endif //PCH_H 25 | -------------------------------------------------------------------------------- /DeviceExplorer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.31911.260 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DevExpCore", "DevExpCore\DevExpCore.vcxproj", "{D49246FC-7ADF-4FE3-A264-48A18397354E}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DevExpC", "DevExpC\DevExpC.vcxproj", "{0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DevExp", "DevExp\DevExp.vcxproj", "{432E23FE-076E-497D-AB19-2DBCCB8028CD}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "instdrv", "instdrv\instdrv.vcxproj", "{B54B775A-C385-486F-9C53-DABB112BFD01}" 13 | EndProject 14 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WTLHelper", "WTLHelper\WTLHelper\WTLHelper.vcxproj", "{AE53419F-A769-4548-8E15-E311904DF7DF}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|ARM64 = Debug|ARM64 19 | Debug|x64 = Debug|x64 20 | Debug|x86 = Debug|x86 21 | Release|ARM64 = Release|ARM64 22 | Release|x64 = Release|x64 23 | Release|x86 = Release|x86 24 | ReleaseSigned|ARM64 = ReleaseSigned|ARM64 25 | ReleaseSigned|x64 = ReleaseSigned|x64 26 | ReleaseSigned|x86 = ReleaseSigned|x86 27 | EndGlobalSection 28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 29 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Debug|ARM64.ActiveCfg = Debug|x64 30 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Debug|ARM64.Build.0 = Debug|x64 31 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Debug|x64.ActiveCfg = Debug|x64 32 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Debug|x64.Build.0 = Debug|x64 33 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Debug|x86.ActiveCfg = Debug|Win32 34 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Debug|x86.Build.0 = Debug|Win32 35 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Release|ARM64.ActiveCfg = Release|x64 36 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Release|ARM64.Build.0 = Release|x64 37 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Release|x64.ActiveCfg = Release|x64 38 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Release|x64.Build.0 = Release|x64 39 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Release|x86.ActiveCfg = Release|Win32 40 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.Release|x86.Build.0 = Release|Win32 41 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.ReleaseSigned|ARM64.ActiveCfg = ReleaseSigned|x64 42 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.ReleaseSigned|ARM64.Build.0 = ReleaseSigned|x64 43 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.ReleaseSigned|x64.ActiveCfg = ReleaseSigned|x64 44 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.ReleaseSigned|x64.Build.0 = ReleaseSigned|x64 45 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.ReleaseSigned|x86.ActiveCfg = ReleaseSigned|Win32 46 | {D49246FC-7ADF-4FE3-A264-48A18397354E}.ReleaseSigned|x86.Build.0 = ReleaseSigned|Win32 47 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Debug|ARM64.ActiveCfg = Debug|x64 48 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Debug|ARM64.Build.0 = Debug|x64 49 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Debug|x64.ActiveCfg = Debug|x64 50 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Debug|x64.Build.0 = Debug|x64 51 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Debug|x86.ActiveCfg = Debug|Win32 52 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Debug|x86.Build.0 = Debug|Win32 53 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Release|ARM64.ActiveCfg = Release|x64 54 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Release|ARM64.Build.0 = Release|x64 55 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Release|x64.ActiveCfg = Release|x64 56 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Release|x64.Build.0 = Release|x64 57 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Release|x86.ActiveCfg = Release|Win32 58 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.Release|x86.Build.0 = Release|Win32 59 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.ReleaseSigned|ARM64.ActiveCfg = ReleaseSigned|x64 60 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.ReleaseSigned|ARM64.Build.0 = ReleaseSigned|x64 61 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.ReleaseSigned|x64.ActiveCfg = ReleaseSigned|x64 62 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.ReleaseSigned|x64.Build.0 = ReleaseSigned|x64 63 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.ReleaseSigned|x86.ActiveCfg = ReleaseSigned|Win32 64 | {0BBB6988-32AF-4B4A-B94F-32D6289E7D0C}.ReleaseSigned|x86.Build.0 = ReleaseSigned|Win32 65 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Debug|ARM64.ActiveCfg = Debug|x64 66 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Debug|ARM64.Build.0 = Debug|x64 67 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Debug|x64.ActiveCfg = Debug|x64 68 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Debug|x64.Build.0 = Debug|x64 69 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Debug|x86.ActiveCfg = Debug|Win32 70 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Debug|x86.Build.0 = Debug|Win32 71 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Release|ARM64.ActiveCfg = Release|x64 72 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Release|ARM64.Build.0 = Release|x64 73 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Release|x64.ActiveCfg = Release|x64 74 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Release|x64.Build.0 = Release|x64 75 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Release|x86.ActiveCfg = Release|Win32 76 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.Release|x86.Build.0 = Release|Win32 77 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.ReleaseSigned|ARM64.ActiveCfg = ReleaseSigned|x64 78 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.ReleaseSigned|ARM64.Build.0 = ReleaseSigned|x64 79 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.ReleaseSigned|x64.ActiveCfg = ReleaseSigned|x64 80 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.ReleaseSigned|x64.Build.0 = ReleaseSigned|x64 81 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.ReleaseSigned|x86.ActiveCfg = ReleaseSigned|Win32 82 | {432E23FE-076E-497D-AB19-2DBCCB8028CD}.ReleaseSigned|x86.Build.0 = ReleaseSigned|Win32 83 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Debug|ARM64.ActiveCfg = Debug|x64 84 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Debug|ARM64.Build.0 = Debug|x64 85 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Debug|x64.ActiveCfg = Debug|x64 86 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Debug|x64.Build.0 = Debug|x64 87 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Debug|x86.ActiveCfg = Debug|Win32 88 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Debug|x86.Build.0 = Debug|Win32 89 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Release|ARM64.ActiveCfg = Release|x64 90 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Release|ARM64.Build.0 = Release|x64 91 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Release|x64.ActiveCfg = Release|x64 92 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Release|x64.Build.0 = Release|x64 93 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Release|x86.ActiveCfg = Release|Win32 94 | {B54B775A-C385-486F-9C53-DABB112BFD01}.Release|x86.Build.0 = Release|Win32 95 | {B54B775A-C385-486F-9C53-DABB112BFD01}.ReleaseSigned|ARM64.ActiveCfg = ReleaseSigned|x64 96 | {B54B775A-C385-486F-9C53-DABB112BFD01}.ReleaseSigned|ARM64.Build.0 = ReleaseSigned|x64 97 | {B54B775A-C385-486F-9C53-DABB112BFD01}.ReleaseSigned|x64.ActiveCfg = ReleaseSigned|x64 98 | {B54B775A-C385-486F-9C53-DABB112BFD01}.ReleaseSigned|x64.Build.0 = ReleaseSigned|x64 99 | {B54B775A-C385-486F-9C53-DABB112BFD01}.ReleaseSigned|x86.ActiveCfg = ReleaseSigned|Win32 100 | {B54B775A-C385-486F-9C53-DABB112BFD01}.ReleaseSigned|x86.Build.0 = ReleaseSigned|Win32 101 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|ARM64.ActiveCfg = Debug|ARM64 102 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|ARM64.Build.0 = Debug|ARM64 103 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x64.ActiveCfg = Debug|x64 104 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x64.Build.0 = Debug|x64 105 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x86.ActiveCfg = Debug|Win32 106 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Debug|x86.Build.0 = Debug|Win32 107 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Release|ARM64.ActiveCfg = Release|ARM64 108 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Release|ARM64.Build.0 = Release|ARM64 109 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x64.ActiveCfg = Release|x64 110 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x64.Build.0 = Release|x64 111 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x86.ActiveCfg = Release|Win32 112 | {AE53419F-A769-4548-8E15-E311904DF7DF}.Release|x86.Build.0 = Release|Win32 113 | {AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|ARM64.ActiveCfg = ReleaseSigned|ARM64 114 | {AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|ARM64.Build.0 = ReleaseSigned|ARM64 115 | {AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|x64.ActiveCfg = ReleaseSigned|x64 116 | {AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|x64.Build.0 = ReleaseSigned|x64 117 | {AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|x86.ActiveCfg = ReleaseSigned|Win32 118 | {AE53419F-A769-4548-8E15-E311904DF7DF}.ReleaseSigned|x86.Build.0 = ReleaseSigned|Win32 119 | EndGlobalSection 120 | GlobalSection(SolutionProperties) = preSolution 121 | HideSolutionNode = FALSE 122 | EndGlobalSection 123 | GlobalSection(ExtensibilityGlobals) = postSolution 124 | SolutionGuid = {47AAC736-67D4-4753-A9BE-072C2EA6DF46} 125 | EndGlobalSection 126 | EndGlobal 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Device Explorer 2 | Enhanced version of the built-in Device Manager tool. 3 | (Work in progress) 4 | -------------------------------------------------------------------------------- /instdrv/instdrv.cpp: -------------------------------------------------------------------------------- 1 | // instdrv.cpp : This file contains the 'main' function. Program execution begins and ends there. 2 | // 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #pragma comment(lib, "setupapi") 11 | #pragma comment(lib, "newdev") 12 | 13 | int Error(char const* msg, DWORD err = ::GetLastError()) { 14 | WCHAR text[256]; 15 | ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, 0, text, _countof(text), nullptr); 16 | printf("%s. %ws\n", msg, text); 17 | return err; 18 | } 19 | 20 | int wmain(int argc, const wchar_t* argv[]) { 21 | if (argc < 2) { 22 | printf("Usage: instdrv [hardware_id]\n"); 23 | return 0; 24 | } 25 | 26 | auto hinf = ::SetupOpenInfFile(argv[1], nullptr, INF_STYLE_WIN4, nullptr); 27 | if (!hinf) 28 | return Error("Failed to open file"); 29 | 30 | INFCONTEXT ctx; 31 | if (!::SetupFindFirstLine(hinf, L"manufacturer", nullptr, &ctx)) 32 | return Error("Failed to locate manufacturer section"); 33 | 34 | WCHAR mfg[256]; 35 | if (!::SetupGetStringField(&ctx, 1, mfg, _countof(mfg), nullptr)) 36 | return Error("Error parsing INF"); 37 | 38 | GUID clsGuid; 39 | WCHAR className[MAX_CLASS_NAME_LEN]; 40 | SetupDiGetINFClass(argv[1], &clsGuid, className, _countof(className), nullptr); 41 | 42 | HDEVINFO hDevInfo = ::SetupDiCreateDeviceInfoList(&clsGuid, nullptr); 43 | if (!hDevInfo) 44 | return Error("Failed to create device info list"); 45 | 46 | SP_DEVINFO_DATA di{ sizeof(di) }; 47 | if(!::SetupDiCreateDeviceInfo(hDevInfo, className, &clsGuid, nullptr, nullptr, DICD_GENERATE_ID, &di)) 48 | return Error("Failed to create device"); 49 | 50 | WCHAR hwid[256]{}; 51 | if (argc < 3) { 52 | // find hardware ID 53 | WCHAR arch[16]; 54 | if (::SetupGetStringField(&ctx, 2, arch, _countof(arch), nullptr)) { 55 | wcscat_s(mfg, L"."); 56 | wcscat_s(mfg, arch); 57 | } 58 | if (::SetupFindFirstLine(hinf, mfg, nullptr, &ctx)) 59 | ::SetupGetStringField(&ctx, 2, hwid, _countof(hwid), nullptr); 60 | } 61 | 62 | auto name = argc > 2 ? argv[2] : hwid; 63 | if (!::SetupDiSetDeviceRegistryProperty(hDevInfo, &di, SPDRP_HARDWAREID, (const BYTE*)name, DWORD((wcslen(name) + 1) * sizeof(WCHAR)))) 64 | return Error("Failed to set hardware ID"); 65 | 66 | if (!::SetupDiCallClassInstaller(DIF_REGISTERDEVICE, hDevInfo, &di)) 67 | return Error("Failed to register device"); 68 | 69 | BOOL reboot; 70 | if (!::UpdateDriverForPlugAndPlayDevices(nullptr, name, argv[1], INSTALLFLAG_FORCE, &reboot)) 71 | return Error("Failed to update driver"); 72 | 73 | ::SetupDiDestroyDeviceInfoList(hDevInfo); 74 | printf("Installation successful!\n"); 75 | 76 | ::SetupCloseInfFile(hinf); 77 | 78 | return 0; 79 | } 80 | 81 | -------------------------------------------------------------------------------- /instdrv/instdrv.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | ReleaseSigned 10 | Win32 11 | 12 | 13 | ReleaseSigned 14 | x64 15 | 16 | 17 | Release 18 | Win32 19 | 20 | 21 | Debug 22 | x64 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | 16.0 31 | Win32Proj 32 | {b54b775a-c385-486f-9c53-dabb112bfd01} 33 | instdrv 34 | 10.0 35 | 36 | 37 | 38 | Application 39 | true 40 | v143 41 | Unicode 42 | 43 | 44 | Application 45 | false 46 | v143 47 | true 48 | Unicode 49 | 50 | 51 | Application 52 | false 53 | v143 54 | true 55 | Unicode 56 | 57 | 58 | Application 59 | true 60 | v143 61 | Unicode 62 | 63 | 64 | Application 65 | false 66 | v143 67 | true 68 | Unicode 69 | 70 | 71 | Application 72 | false 73 | v143 74 | true 75 | Unicode 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | MultiThreaded 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | 129 | 130 | signtool sign /i DigiCert /fd sha256 $(TargetPath) 131 | 132 | 133 | 134 | 135 | Level3 136 | true 137 | true 138 | true 139 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 140 | true 141 | MultiThreaded 142 | 143 | 144 | Console 145 | true 146 | true 147 | true 148 | 149 | 150 | signtool sign /i DigiCert /fd sha256 $(TargetPath) 151 | 152 | 153 | 154 | 155 | Level3 156 | true 157 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 158 | true 159 | 160 | 161 | Console 162 | true 163 | 164 | 165 | 166 | 167 | Level3 168 | true 169 | true 170 | true 171 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 172 | true 173 | MultiThreaded 174 | 175 | 176 | Console 177 | true 178 | true 179 | true 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | Level3 189 | true 190 | true 191 | true 192 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 193 | true 194 | MultiThreaded 195 | 196 | 197 | Console 198 | true 199 | true 200 | true 201 | 202 | 203 | signtool sign /a /n Scorpio /t http://timestamp.digicert.com /fd sha256 $(TargetPath) 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /instdrv/instdrv.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | --------------------------------------------------------------------------------