-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathfrmMain.twin
More file actions
1309 lines (1162 loc) · 53.2 KB
/
frmMain.twin
File metadata and controls
1309 lines (1162 loc) · 53.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
[Description("DevExplorer Main Form")]
[FormDesignerId("9D5C3949-7539-4FCC-9D96-136E21889D63")]
[PredeclaredId]
Class Form1
'Device Explorer v1.3
'(c) 2023-2026 Jon Johnson
'v1.3
'- Code fixes for new twinBASIC syntax rules; update WDL package and change to linked.
'- Fix Computer picture black background bug
'- Existing binary build had broken right click
'- Add refreshes for device removals
'v1.2
' - Weird issue with icons being off by one... I commented out lines that adjusted these; but in
' previous versions they were required to get the correct icon. Still is, for Other Devices.
' Please let me know if you see the wrong icon on any category or device!
'
' - Fix for icons disappearing when an item was selected.
'
' - Fix for problem running in IDE multiple times without compiler restart.
'
'
'v1.1 - Update for newer versions of tB.
'Note: All APIs come from WinDevLib.
'Code is currently highly repetive and inefficient, will refine after everything works.
Private hModule As LongPtr 'We'll point this at the compiled exe if we're running in the IDE and it exists.
Private cxyIcon As Long, cxyIconBtn As Long
Private m_ScaleX As Single, m_ScaleY As Single
Private himlMain As LongPtr
Private Type DMItem
bDevice As Boolean
bDisable As Boolean
bPresent As Boolean
AsscGUID As UUID
DispName As String
Desc As String
InstId As String
hItem As LongPtr
hItemPar As LongPtr
nIcon As Long
dvi As Long
DevCap As SetupDevCap
ProblemCode As Long
ProblemText As String
End Type
Private DMSet() As DMItem
Private nItems As Long
Private nDevices As Long
Private arClasses() As UUID
Private Const szHelpTitle = "Device Explorer"
Private Const szHelpHeader = "Device Explorer v1.3"
Private Const szHelpMessage = "This project is a basic, light weight, and portable device manager for the local computer: list devices, show their property pages, and enable, disable, " & _
"remove, or eject them. Note that not all devices support all actions, and running as administrator is required in most cases." & vbcrLf & _
"Project by Jon Johnson based on numerous C/C++ projects, and an " & _
"<a href=""https://www.vbforums.com/showthread.php?859333-TABLED-EnumDisplayDevices-vs-SetupDiEnumDeviceInfo&p=5265171&viewfull=1#post5265171"">example of basic device enumeration</a>" & _
" on VBForums.com by Elroy. " & vbcrlf & vbcrlf & _
"For the readme, filing bug reports, original source, feature requests, and anything else, visit the project's GitHub repository:" & vbcrlf & _
"<a href=""https://github.com/fafalone/DeviceExplorer"">https://github.com/fafalone/DeviceExplorer</a>"
Private Const szHelpFooter = "Copyright ©2023-2024 Jon Johnson. Licensed under the MIT license. See code or repository for more information."
Private Const szHelpIconRes = "101"
Private idxSelected As Long
Private Const IDI_ICONUNK = "102"
Private Const IDI_OVRWARN = "201"
Private Const IDI_OVRINFO = "202"
Private Const IDI_OVRDOWN = "203"
Private Const IDI_DISABLE = "301"
Private Const IDI_REMOVE = "302"
Private Const IDI_UNINST = "303"
Private Const IDI_EJECT = "304"
Private Const IDI_UPDATE = "305"
Private Const IDI_REFRESH = "306"
Private Const IDI_PLAIN = "307"
Private Sub OnInitialize() Handles Form.Initialize
ReDim arClasses(0)
ReDim DMSet(0)
nItems = 0
nDevices = 0
'Attempt to load resources from last .exe
hModule = GetModuleHandleW()
Dim InIde As Boolean: Debug.Assert MakeTrue(InIde)
If InIde Then
If (App.LastBuildPath = "") Or (PathFileExists(App.LastBuildPath) = 0) Then
MsgBox "You must compile this app before running it in the IDE as it depends on resources.", vbCritical Or vbOKOnly, App.Title
End
'hModule = App.hInstance
Else
hModule = LoadLibraryEx(App.LastBuildPath, 0, LOAD_LIBRARY_AS_DATAFILE Or LOAD_LIBRARY_AS_IMAGE_RESOURCE)
End If
End If
End Sub
Private Function MakeTrue(ByRef x As Boolean) As Boolean
x = True: MakeTrue = True
End Function
Private Sub OnLoad() Handles Form.Load
Dim hDC As LongPtr = GetDC(0&)
m_ScaleX = GetDeviceCaps(hDC, LOGPIXELSX) / 96
m_ScaleY = GetDeviceCaps(hDC, LOGPIXELSY) / 96
Select Case m_ScaleX
Case Is <= 1: cxyIcon = 24
Case Is <= 1.25: cxyIcon = 32
Case Is <= 1.5: cxyIcon = 48
Case Else: cxyIcon = 64
End Select
ReleaseDC 0&, hDC
Dim sNameBuf As String = Space$(MAX_COMPUTERNAME_LENGTH)
Dim nLen As Long = MAX_COMPUTERNAME_LENGTH
If GetComputerName(sNameBuf, nLen) Then
sNameBuf = Left$(sNameBuf, nLen)
Label1.Caption = "Computer: " & sNameBuf
End If
Dim bWow64 As BOOL, bEl As Boolean
Dim sPrompt As String, sMsg As String
bEl = IsProcessElevated()
If bEl Then
Dim btPrev As Byte
Dim status As NTSTATUS = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 1, 0, btPrev)
If NT_SUCCESS(status) Then
Debug.Print "Enabled Load driver privilege"
Else
Debug.Print "Failed to enabled load driver privilege, 0x" & Hex$(status) & GetNtErrorString(status)
End If
Else
sPrompt = "WARNING: Not running as administrator." & vbCrLf
End If
IsWow64Process(GetCurrentProcess(), bWow64)
If bWow64 Then
sPrompt = sPrompt & "WARNING: Running as 32bit process on 64bit OS." & vbCrLf
End If
If sPrompt <> "" Then
#If DBG_NO_CHECKS = 0 Then
MsgBox sPrompt & vbCrLf & _
"You can view the device list and properties, but you must run the 64bit version of this app with elevation to " & _
"enable/disable/remove devices on 64bit Windows.", vbCritical Or vbOKOnly, App.Title
#Else
Debug.Print sPrompt
#End If
End If
himlMain = ImageList_Create(cxyIcon, cxyIcon, ILC_COLOR32 Or ILC_HIGHQUALITYSCALE Or ILC_MASK, 1, 1)
'Set up overlay icons like the warning icon for devices with problems. (Not sure where the 2nd is used yet)
Dim hOvr1 As LongPtr = LoadImage(hModule, ByVal StrPtr(IDI_OVRWARN), IMAGE_ICON, cxyIcon, cxyIcon, LR_DEFAULTCOLOR Or LR_SHARED)
Dim hOvr2 As LongPtr = LoadImage(hModule, ByVal StrPtr(IDI_OVRINFO), IMAGE_ICON, cxyIcon, cxyIcon, LR_DEFAULTCOLOR Or LR_SHARED)
Dim hOvr3 As LongPtr = LoadImage(hModule, ByVal StrPtr(IDI_OVRDOWN), IMAGE_ICON, cxyIcon, cxyIcon, LR_DEFAULTCOLOR Or LR_SHARED)
Dim o1 As Long = ImageList_AddIcon(himlMain, hOvr1)
Dim o2 As Long = ImageList_AddIcon(himlMain, hOvr2)
Dim o3 As Long = ImageList_AddIcon(himlMain, hOvr3)
ImageList_SetOverlayImage(himlMain, o1, 1)
ImageList_SetOverlayImage(himlMain, o2, 2)
ImageList_SetOverlayImage(himlMain, o3, 3)
DestroyIcon hOvr1
DestroyIcon hOvr2
DestroyIcon hOvr3
SendMessage TreeView1.hWnd, TVM_SETIMAGELIST, 0, ByVal himlMain
SetWindowTheme TreeView1.hWnd, StrPtr("explorer"), 0
InitButtonIcons
pvEnumClasses
pvPopulateDevices
pvPruneUnused()
End Sub
Private Sub OnExit() Handles mnuExit.Click
Unload Me
End Sub
[Description("Loads button icons from the resource file (which is was a compiled exe must exist to take them from when running in the IDE). ")]
Private Sub InitButtonIcons()
Select Case m_ScaleX
Case Is <= 1: cxyIconBtn = 24
Case Is <= 1.25: cxyIconBtn = 32
Case Is <= 1.5: cxyIconBtn = 48
Case Else: cxyIconBtn = 64
End Select
Dim hBtn As LongPtr = LoadImage(hModule, ByVal StrPtr(IDI_REFRESH), IMAGE_ICON, cxyIconBtn, cxyIconBtn, LR_DEFAULTCOLOR Or LR_SHARED)
If hBtn Then ButtonIconAssign cmdEnum.hWnd, hBtn, cxyIconBtn, cxyIconBtn, BUTTON_IMAGELIST_ALIGN_RIGHT, 0&, 2&, 2&, 0&
DestroyIcon hBtn: hBtn = 0
hBtn = LoadImage(hModule, ByVal StrPtr(IDI_DISABLE), IMAGE_ICON, cxyIconBtn, cxyIconBtn, LR_DEFAULTCOLOR Or LR_SHARED)
If hBtn Then ButtonIconAssign cmdDisable.hWnd, hBtn, cxyIconBtn, cxyIconBtn, BUTTON_IMAGELIST_ALIGN_RIGHT, 0&, 2&, 2&, 0&
DestroyIcon hBtn: hBtn = 0
hBtn = LoadImage(hModule, ByVal StrPtr(IDI_EJECT), IMAGE_ICON, cxyIconBtn, cxyIconBtn, LR_DEFAULTCOLOR Or LR_SHARED)
If hBtn Then ButtonIconAssign cmdEject.hWnd, hBtn, cxyIconBtn, cxyIconBtn, BUTTON_IMAGELIST_ALIGN_RIGHT, 0&, 2&, 2&, 0&
DestroyIcon hBtn: hBtn = 0
hBtn = LoadImage(hModule, ByVal StrPtr(IDI_UNINST), IMAGE_ICON, cxyIconBtn, cxyIconBtn, LR_DEFAULTCOLOR Or LR_SHARED)
If hBtn Then ButtonIconAssign cmdUninstall.hWnd, hBtn, cxyIconBtn, cxyIconBtn, BUTTON_IMAGELIST_ALIGN_RIGHT, 0&, 2&, 2&, 0&
DestroyIcon hBtn: hBtn = 0
hBtn = LoadImage(hModule, ByVal StrPtr(IDI_UPDATE), IMAGE_ICON, cxyIconBtn, cxyIconBtn, LR_DEFAULTCOLOR Or LR_SHARED)
If hBtn Then ButtonIconAssign cmdUpdate.hWnd, hBtn, cxyIconBtn, cxyIconBtn, BUTTON_IMAGELIST_ALIGN_RIGHT, 0&, 2&, 2&, 0&
DestroyIcon hBtn: hBtn = 0
hBtn = LoadImage(hModule, ByVal StrPtr(IDI_REMOVE), IMAGE_ICON, cxyIconBtn, cxyIconBtn, LR_DEFAULTCOLOR Or LR_SHARED)
If hBtn Then ButtonIconAssign cmdRem.hWnd, hBtn, cxyIconBtn, cxyIconBtn, BUTTON_IMAGELIST_ALIGN_RIGHT, 0&, 2&, 2&, 0&
DestroyIcon hBtn: hBtn = 0
hBtn = LoadImage(hModule, ByVal StrPtr(IDI_PLAIN), IMAGE_ICON, cxyIconBtn, cxyIconBtn, LR_DEFAULTCOLOR Or LR_SHARED)
If hBtn Then ButtonIconAssign cmdEnable.hWnd, hBtn, cxyIconBtn, cxyIconBtn, BUTTON_IMAGELIST_ALIGN_RIGHT, 0&, 2&, 2&, 0&
DestroyIcon hBtn: hBtn = 0
End Sub
[Description("Assigns an HICON image to a CommandButton control with the given size and margins.")]
Private Sub ButtonIconAssign(hWnd As LongPtr, hIcon As LongPtr, cx As Long, CY As Long, align As BUTTON_IMAGELIST_ALIGN, margLeft As Long, margRight As Long, margTop As Long, margBottom As Long)
'BM_SETIMAGE doesn't allow specifying margins. So you need to put a space before the text or it's way too close to the image; but then one space
'might be too much or too little. If we use this method instead, the margins will be perfectly set by pixel.
On Error GoTo e0
Dim bi4 As BUTTON_IMAGELIST
bi4.himl = ImageList_Create(cx, CY, ILC_COLOR32 Or ILC_MASK, 1, 1)
If bi4.himl Then
bi4.margin.Left = margLeft
bi4.margin.Right = margRight
bi4.margin.Top = margTop
bi4.margin.Bottom = margBottom
ImageList_ReplaceIcon bi4.himl, -1, hIcon
Call SendMessage(hWnd, BCM_SETIMAGELIST, 0&, bi4)
End If
On Error GoTo 0
Exit Sub
e0:
Debug.Print "ButtonIconAssign.Error->" & Err.Description & " (" & Err.Number & ")"
End Sub
Private Sub OnUnload(Cancel As Integer) Handles Form.Unload
ImageList_Destroy himlMain
If hModule <> App.hInstance Then FreeLibrary hModule
End Sub
[Description("Enumerates all hardware classes and adds them to the DMSet array and as root nodes in the TreeView.")]
Private Sub pvEnumClasses()
On Error GoTo e0
Dim ret As BOOL
Dim cbReq As Long
Dim i As Long
Dim sBufN As String, sBufD As String
Dim cchReq As Long
Dim hIcon As LongPtr
ret = SetupDiBuildClassInfoList(0, ByVal vbNullPtr, 0, cbReq)
If cbReq > 0 Then
ReDim arClasses(cbReq - 1)
ret = SetupDiBuildClassInfoList(0, arClasses(0), UBound(arClasses) + 1, cbReq)
If ret Then
For i = 0 To UBound(arClasses) - 1
sBufN = String$(MAX_CLASS_NAME_LEN, 0)
ret = SetupDiClassNameFromGuid(arClasses(i), sBufN, Len(sBufN), cchReq)
If cchReq Then sBufN = Left$(sBufN, cchReq - 1)
cchReq = 0
ret = SetupDiGetClassDescription(arClasses(i), vbNullString, 0, cchReq)
If cchReq > 0 Then
sBufD = String$(cchReq, 0)
ret = SetupDiGetClassDescription(arClasses(i), sBufD, Len(sBufD), cchReq)
End If
ret = SetupDiLoadClassIcon(arClasses(i), hIcon)
ReDim Preserve DMSet(nItems)
DMSet(i).DispName = sBufN
DMSet(i).Desc = sBufD
DMSet(i).AsscGUID = arClasses(i)
If hIcon Then
DMSet(i).nIcon = ImageList_AddIcon(himlMain, hIcon)
' DMSet(i).nIcon += 1
DestroyIcon hIcon
End If
nItems += 1
'Debug.Print "Added class " & dbg_GUIDToString(arClasses(i)) & ": Name=" & sBufN & ", Description=" & sBufD
Next
End If
End If
If nItems Then
Dim oNode As Node
For i = 0 To UBound(DMSet)
Set oNode = TreeView1.Nodes.Add(, , , DMSet(i).Desc)
DMSet(i).hItem = oNode.Handle
oNode.Key = CVar(CStr(i))
oNode.Sorted = True
Dim tvi As TVITEMW
tvi.Mask = TVIF_HANDLE Or TVIF_IMAGE Or TVIF_SELECTEDIMAGE
tvi.hItem = oNode.Handle
tvi.iImage = DMSet(i).nIcon
tvi.iSelectedImage = DMSet(i).nIcon
SendMessage TreeView1.hWnd, TVM_SETITEMW, 0, tvi
Next
End If
Exit Sub
e0:
Debug.Print CurrentComponentName & "." & CurrentProcedureName & "->Error: " & Err.Number & " (" & Err.Number & "); LastDllError=0x" & Hex$(Err.LastDllError)
End Sub
[Description("Goes through the class list from pvEnumClasses and adds all installed devices for each category. Then, looks for devices with no associated class (which includes the 'Unknown' class), and adds them as 'Other devices'.")]
Private Sub pvPopulateDevices()
On Error GoTo e0
Dim hSet As LongPtr
Dim i As Long, j As Long
Dim hIcon As LongPtr
Dim tDevInfo As SP_DEVINFO_DATA
Dim sBufN As String
Dim sBufID As String
Dim cbReq As Long
Dim cchReq As Long
Dim ret As BOOL
Dim regType As REGTYPES
Dim dwCap As SetupDevCap
Dim dwStatus As CfgMgDevNodeStatus
Dim nProbCode As CfgMgrProblems
Dim nPT As DEVPROPTYPE
Dim bProblem As Boolean
Dim sBufP As String
Dim cchProb As Long
Dim fPresent As BOOL
Dim dwState As TVITEM_State, dwMask As TVITEM_State
For i = 0 To UBound(DMSet)
If DMSet(i).bDevice Then Continue For
'Is a class
hSet = SetupDiGetClassDevs(DMSet(i).AsscGUID, vbNullString, Me.hWnd, IIf(Check3.Value = vbChecked, 0&, DIGCF_PRESENT))
If hSet = INVALID_HANDLE_VALUE Then Continue For
tDevInfo.cbSize = LenB(tDevInfo)
j = 0
Do While SetupDiEnumDeviceInfo(hSet, j, tDevInfo)
cchReq = 0: cbReq = 0
sBufN = "": sBufID = "": sBufP = ""
dwCap = 0: bProblem = False
dwStatus = 0: nProbCode = 0
fPresent = 0
dwMask = 0: dwState = 0
ret = SetupDiGetDeviceInstanceId(hSet, tDevInfo, vbNullString, 0, cchReq)
If cchReq Then
sBufID = String$(cchReq, 0)
ret = SetupDiGetDeviceInstanceId(hSet, tDevInfo, sBufID, Len(sBufID), cchReq)
If InStr(sBufID, Chr$(0)) > 1 Then
sBufID = Left$(sBufID, InStr(sBufID, Chr$(0)) - 1)
End If
End If
ret = SetupDiGetDeviceRegistryProperty(hSet, tDevInfo, SPDRP_CAPABILITIES, regType, dwCap, LenB(dwCap), cbReq)
cbReq = 0
sBufN = String$(80, 0)
ret = SetupDiGetDeviceRegistryPropertyW(hSet, tDevInfo, SPDRP_FRIENDLYNAME, regType, ByVal StrPtr(sBufN), LenB(sBufN), cbReq)
If Err.LastDllError = ERROR_INVALID_DATA Then 'No friendly name
cbReq = 0
ret = SetupDiGetDeviceRegistryPropertyW(hSet, tDevInfo, SPDRP_DEVICEDESC, regType, ByVal 0, 0, cbReq)
If cbReq Then
sBufN = String$(cbReq / 2, 0)
ret = SetupDiGetDeviceRegistryPropertyW(hSet, tDevInfo, SPDRP_DEVICEDESC, regType, ByVal StrPtr(sBufN), LenB(sBufN), cbReq)
End If
If Left$(sBufN, 1) = vbNullChar Then
sBufN = sBufID
Debug.Print "Name fallback; no FN, no DD " & sBufID
End If
Else
If InStr(sBufN, Chr$(0)) > 1 Then
sBufN = Left$(sBufN, InStr(sBufN, Chr$(0)) - 1)
Else
sBufN = sBufID
End If
End If
If CM_Get_DevNode_Status(dwStatus, nProbCode, tDevInfo.DevInst, 0) = CR_SUCCESS Then
If (dwStatus And DN_HAS_PROBLEM) = DN_HAS_PROBLEM Then
bProblem = True
cbReq = 0
sBufP = String$(1024, 0)
cchProb = DeviceProblemTextW(0, tDevInfo.DevInst, nProbCode, StrPtr(sBufP), Len(sBufP))
If cchProb Then
sBufP = Left$(sBufP, cchProb)
Else
sBufP = "Unknown problem, code " & nProbCode
End If
End If
End If
If Check3.Value = vbChecked Then
ret = SetupDiGetDeviceProperty(hSet, tDevInfo, DEVPKEY_Device_IsPresent, nPropType, fPresent, LenB(Of BOOL), cbReq, 0)
Else
fPresent = CTRUE
End If
ret = SetupDiLoadDeviceIcon(hSet, tDevInfo, cxyIcon, cxyIcon, 0, hIcon)
'Debug.Print "AddDevice " & sBufN & "=>" & sBufID
ReDim Preserve DMSet(nItems)
With DMSet(nItems)
.AsscGUID = tDevInfo.ClassGuid
.bDevice = True
.dvi = tDevInfo.DevInst
If sBufN = "" Then
.DispName = .InstId
Else
.DispName = sBufN
End If
.DevCap = dwCap
.InstId = sBufID
If hIcon Then
.nIcon = ImageList_AddIcon(himlMain, hIcon)
' .nIcon += 1
DestroyIcon hIcon
hIcon = 0
End If
Dim oNodePar As Node
Set oNodePar = pvNodeFromHandle(DMSet(i).hItem)
Dim oNode As Node
Set oNode = TreeView1.Nodes.Add(oNodePar, tvwChild, CVar(CStr(nItems)), DMSet(nItems).DispName)
.hItem = oNode.Handle
.hItemPar = oNodePar.Handle
Dim tvi As TVITEMW
tvi.Mask = TVIF_HANDLE Or TVIF_IMAGE Or TVIF_SELECTEDIMAGE
tvi.hItem = oNode.Handle
tvi.iImage = DMSet(nItems).nIcon
tvi.iSelectedImage = DMSet(nItems).nIcon
SendMessage TreeView1.hWnd, TVM_SETITEMW, 0, tvi
If bProblem Then
.ProblemCode = nProbCode
.ProblemText = sBufP
If nProbCode = CM_PROB_DISABLED Then
dwState = INDEXTOOVERLAYMASK(3)
Else
dwState = INDEXTOOVERLAYMASK(1)
End If
dwMask = TVIS_OVERLAYMASK
End If
If fPresent = 0 Then
dwState = dwState Or TVIS_CUT
dwMask = dwMask Or TVIS_CUT
End If
If dwMask Then TreeView_SetItemState TreeView1.hWnd, oNode.Handle, dwState, dwMask
End With
nItems += 1
nDevices += 1
j += 1
tDevInfo.cbSize = LenB(tDevInfo)
Loop
Next
Debug.Print "Completed primary device enum, loading Other Devices"
'Enumerate 'Other devices' -- those without a setup class
Dim hSetUnk As LongPtr = SetupDiGetClassDevsW(ByVal vbNullPtr, 0, 0, IIf(Check3.Value = vbChecked, DIGCF_ALLCLASSES, DIGCF_ALLCLASSES Or DIGCF_PRESENT))
If hSetUnk Then
Dim spdid As SP_DEVINFO_DATA
Dim nPropType As DEVPROPTYPE
Dim tDevGuid As UUID
Dim oNodeOther As Node
spdid.cbSize = LenB(Of SP_DEVINFO_DATA)
j = 0
Do While SetupDiEnumDeviceInfo(hSetUnk, j, spdid)
j += 1
ret = SetupDiGetDeviceProperty(hSetUnk, spdid, DEVPKEY_Device_Class, nPropType, tDevGuid, LenB(Of UUID), cbReq, 0)
If (ret = 0) Or (nPropType <> DEVPROP_TYPE_GUID) Then
If Err.LastDllError = ERROR_NOT_FOUND Then
cchReq = 0: cbReq = 0
sBufN = "": sBufID = "": sBufP = ""
dwCap = 0: bProblem = False
dwStatus = 0: nProbCode = 0
fPresent = 0
dwState = 0: dwMask = 0
ret = SetupDiGetDeviceInstanceId(hSetUnk, spdid, vbNullString, 0, cchReq)
If cchReq Then
sBufID = String$(cchReq, 0)
ret = SetupDiGetDeviceInstanceId(hSetUnk, spdid, sBufID, Len(sBufID), cchReq)
If InStr(sBufID, Chr$(0)) > 1 Then
sBufID = Left$(sBufID, InStr(sBufID, Chr$(0)) - 1)
End If
End If
ret = SetupDiGetDeviceRegistryProperty(hSetUnk, spdid, SPDRP_CAPABILITIES, regType, dwCap, 4, cbReq)
cbReq = 0
sBufN = String$(80, 0)
ret = SetupDiGetDeviceRegistryPropertyW(hSetUnk, spdid, SPDRP_FRIENDLYNAME, regType, ByVal StrPtr(sBufN), LenB(sBufN), cbReq)
If Err.LastDllError = ERROR_INVALID_DATA Then 'No friendly name
cbReq = 0
ret = SetupDiGetDeviceRegistryPropertyW(hSetUnk, spdid, SPDRP_DEVICEDESC, regType, ByVal 0, 0, cbReq)
If cbReq Then
sBufN = String$(cbReq / 2, 0)
ret = SetupDiGetDeviceRegistryPropertyW(hSetUnk, spdid, SPDRP_DEVICEDESC, regType, ByVal StrPtr(sBufN), LenB(sBufN), cbReq)
End If
If Left$(sBufN, 1) = vbNullChar Then
sBufN = sBufID
Debug.Print "Name fallback; no FN, no DD " & sBufID
End If
Else
If InStr(sBufN, Chr$(0)) > 1 Then
sBufN = Left$(sBufN, InStr(sBufN, Chr$(0)) - 1)
Else
sBufN = sBufID
End If
End If
If sBufN = "HTREE\ROOT\0" Then Continue Do 'Not a device; just the tree root object.
If CM_Get_DevNode_Status(dwStatus, nProbCode, spdid.DevInst, 0) = CR_SUCCESS Then
If (dwStatus And DN_HAS_PROBLEM) = DN_HAS_PROBLEM Then
bProblem = True
cbReq = 0
sBufP = String$(1024, 0)
cchProb = DeviceProblemTextW(0, spdid.DevInst, nProbCode, StrPtr(sBufP), Len(sBufP))
Debug.Print "GetProblemText ret=" & cchProb & ", Err=" & Err.LastDllError & IIf(Err.LastDllError, GetSystemErrorString(Err.LastDllError), "")
If cchProb Then
sBufP = Left$(sBufP, cchProb)
Else
sBufP = "Unknown problem, code " & nProbCode
End If
End If
End If
If Check3.Value = vbChecked Then
ret = SetupDiGetDeviceProperty(hSetUnk, spdid, DEVPKEY_Device_IsPresent, nPropType, fPresent, LenB(Of BOOL), cbReq, 0)
Else
fPresent = CTRUE
End If
ret = SetupDiLoadDeviceIcon(hSetUnk, spdid, cxyIcon, cxyIcon, 0, hIcon)
If oNodeOther Is Nothing Then
'Add 'Other devices' parent node
ReDim Preserve DMSet(nItems)
DMSet(nItems).DispName = "Other devices"
DMSet(nItems).Desc = "Other devices"
'DMSet(i).AsscGUID = arClasses(i)
hIcon = LoadImage(hModule, ByVal StrPtr(IDI_ICONUNK), IMAGE_ICON, cxyIcon, cxyIcon, LR_DEFAULTCOLOR Or LR_SHARED)
If hIcon Then
DMSet(nItems).nIcon = ImageList_AddIcon(himlMain, hIcon)
' DMSet(nItems).nIcon += 1
DestroyIcon hIcon
End If
Set oNodeOther = TreeView1.Nodes.Add(, , , DMSet(nItems).Desc)
DMSet(nItems).hItem = oNodeOther.Handle
oNodeOther.Key = CVar(CStr(nItems))
oNodeOther.Sorted = True
Dim tvi2 As TVITEMW
tvi2.Mask = TVIF_HANDLE Or TVIF_IMAGE Or TVIF_SELECTEDIMAGE
tvi2.hItem = oNodeOther.Handle
tvi2.iImage = DMSet(nItems).nIcon
tvi2.iSelectedImage = DMSet(nItems).nIcon
SendMessage TreeView1.hWnd, TVM_SETITEMW, 0, tvi2
nItems += 1
End If
'Debug.Print "AddOtherDevice " & sBufN & "=>" & sBufID
ReDim Preserve DMSet(nItems)
With DMSet(nItems)
.AsscGUID = tDevInfo.ClassGuid
.bDevice = True
.dvi = tDevInfo.DevInst
If sBufN = "" Then
.DispName = .InstId
Else
.DispName = sBufN
End If
.DevCap = dwCap
.InstId = sBufID
If hIcon = 0 Then
hIcon = LoadImage(hModule, ByVal StrPtr(IDI_ICONUNK), IMAGE_ICON, cxyIcon, cxyIcon, LR_DEFAULTCOLOR Or LR_SHARED)
End If
If hIcon Then
.nIcon = ImageList_AddIcon(himlMain, hIcon)
' .nIcon += 1
DestroyIcon hIcon
hIcon = 0
End If
Set oNode = TreeView1.Nodes.Add(oNodeOther, tvwChild, CVar(CStr(nItems)), DMSet(nItems).DispName)
.hItem = oNode.Handle
.hItemPar = oNodeOther.Handle
Dim tvi3 As TVITEMW
tvi3.Mask = TVIF_HANDLE Or TVIF_IMAGE Or TVIF_SELECTEDIMAGE
tvi3.hItem = oNode.Handle
tvi3.iImage = DMSet(nItems).nIcon
tvi3.iSelectedImage = DMSet(nItems).nIcon
SendMessage TreeView1.hWnd, TVM_SETITEMW, 0, tvi3
If bProblem Then
.ProblemCode = nProbCode
.ProblemText = sBufP
If nProbCode = CM_PROB_DISABLED Then
dwState = INDEXTOOVERLAYMASK(3)
Else
dwState = INDEXTOOVERLAYMASK(1)
End If
dwMask = TVIS_OVERLAYMASK
End If
If fPresent = 0 Then
dwState = dwState Or TVIS_CUT
dwMask = dwMask Or TVIS_CUT
End If
If dwMask Then TreeView_SetItemState TreeView1.hWnd, oNode.Handle, dwState, dwMask
End With
nItems += 1
nDevices += 1
j += 1
End If
End If
Loop
SetupDiDestroyDeviceInfoList hSetUnk
End If
SetupDiDestroyDeviceInfoList hSet
txtStatus.Text = "Found " & CStr(nDevices) & " devices."
RedrawWindow txtStatus.hWnd, ByVal vbNullPtr, 0, RDW_ALLCHILDREN Or RDW_ERASENOW Or RDW_INVALIDATE
UpdateWindow txtStatus.hWnd
Debug.Print "StatusText=" & txtStatus.Text
' txtStatus.SyncToSource()
Exit Sub
e0:
Debug.Print CurrentComponentName & "." & CurrentProcedureName & "->Error: " & Err.Number & " (" & Err.Number & "); LastDllError=0x" & Hex$(Err.LastDllError)
If hSet Then SetupDiDestroyDeviceInfoList hSet
If hSetUnk Then SetupDiDestroyDeviceInfoList hSetUnk
End Sub
[Description("Sets overlay icons for the device tree: 0 = None, 1 = Problem (warning icon), 2 = Info icon, 3 = Disabled by user icon. ")]
Private Sub SetItemOverlayIndex(ByVal hItem As LongPtr, ByVal nIndex As Long)
TreeView_SetItemState TreeView1.hWnd, hItem, INDEXTOOVERLAYMASK(nIndex), TVIS_OVERLAYMASK
End Sub
[Description("Shows the standard properties window for a given device.")]
Private Sub pvShowPropPage(idx As Long)
On Error GoTo e0
Dim hSet As LongPtr
Dim j As Long
Dim tDevInfo As SP_DEVINFO_DATA
Dim sBufN As String
Dim sBufID As String
Dim npReq As Long
Dim cchReq As Long
Dim ret As BOOL
hSet = SetupDiGetClassDevs(DMSet(idx).AsscGUID, vbNullString, Me.hWnd, DIGCF_ALLCLASSES)
If hSet = INVALID_HANDLE_VALUE Then
Debug.Print "Error getting classes for prop page search."
Exit Sub
End If
tDevInfo.cbSize = LenB(tDevInfo)
j = 0
Do While SetupDiEnumDeviceInfo(hSet, j, tDevInfo)
cchReq = 0
sBufN = "": sBufID = ""
ret = SetupDiGetDeviceInstanceId(hSet, tDevInfo, vbNullString, 0, cchReq)
If cchReq Then
sBufID = String$(cchReq, 0)
ret = SetupDiGetDeviceInstanceId(hSet, tDevInfo, sBufID, Len(sBufID), cchReq)
If InStr(sBufID, Chr$(0)) > 1 Then
sBufID = Left$(sBufID, InStr(sBufID, Chr$(0)) - 1)
End If
End If
If sBufID = DMSet(idx).InstId Then
Debug.Print "DevId=" & sBufID
'DeviceProperties_RunDLL Me.hWnd, 0, "/DeviceId " & sBufID, SW_SHOW
'That's the official way, but for some bizarre reason it activates DPI awareness
'if it's not already on; that makes the window tiny. Calling the API it wraps
'directly avoids the problem. No, 0 for hwnd/hinst doesn't change anything.
'Plus here we can add the resources tab; I don't know how to specify that flag
'for the command line version.
DevicePropertiesEx Me.hWnd, vbNullString, sBufID, DEVPROP_SHOW_RESOURCE_TAB, 0 'DEVPROP_SHOW_RESOURCE_TAB doesn't seem to work under WOW64
End If
j += 1
tDevInfo.cbSize = LenB(tDevInfo)
Loop
If hSet Then SetupDiDestroyDeviceInfoList hSet
Exit Sub
e0:
Debug.Print CurrentComponentName & "." & CurrentProcedureName & "->Error: " & Err.Number & " (" & Err.Number & "); LastDllError=0x" & Hex$(Err.LastDllError)
If hSet Then SetupDiDestroyDeviceInfoList hSet
End Sub
[Description("Retrieves a device set handle (hSet) and SP_DEVINFO_DATA type (pInfo) given a device index (idx). " & vbCrLf & "Important: It is the callers responsibility to free the device info list when True is returned.")]
Private Function DevInfoDataFromIndex(ByVal idx As Long, /* out */ hSet As LongPtr, /* out */ pInfo As SP_DEVINFO_DATA) As Boolean
On Error GoTo e0
Dim i As Long, j As Long
Dim sBufID As String
Dim npReq As Long
Dim cchReq As Long
Dim ret As BOOL
hSet = SetupDiGetClassDevs(DMSet(idx).AsscGUID, vbNullString, Me.hWnd, DIGCF_ALLCLASSES)
If hSet = INVALID_HANDLE_VALUE Then Return Err.LastDllError
pInfo.cbSize = LenB(Of SP_DEVINFO_DATA)
j = 0
Do While SetupDiEnumDeviceInfo(hSet, j, pInfo)
cchReq = 0
sBufID = ""
ret = SetupDiGetDeviceInstanceId(hSet, pInfo, vbNullString, 0, cchReq)
If cchReq Then
sBufID = String$(cchReq, 0)
ret = SetupDiGetDeviceInstanceId(hSet, pInfo, sBufID, Len(sBufID), cchReq)
If InStr(sBufID, Chr$(0)) > 1 Then
sBufID = Left$(sBufID, InStr(sBufID, Chr$(0)) - 1)
End If
End If
If sBufID = DMSet(idx).InstId Then
Return True
End If
j += 1
pInfo.cbSize = LenB(pInfo)
Loop
If hSet Then SetupDiDestroyDeviceInfoList hSet
Return False
e0:
Debug.Print CurrentComponentName & "." & CurrentProcedureName & "->Error: " & Err.Number & " (" & Err.Number & "); LastDllError=0x" & Hex$(Err.LastDllError)
If hSet Then SetupDiDestroyDeviceInfoList hSet
End Function
Private Function pvEnableDevice(idx As Long, fEnable As Boolean) As Long
On Error GoTo e0
Dim hSet As LongPtr
Dim i As Long, j As Long
Dim tDevInfo As SP_DEVINFO_DATA
Dim tParams As SP_PROPCHANGE_PARAMS
Dim sBufN As String
Dim sBufID As String
Dim cchReq As Long
Dim ret As BOOL
hSet = SetupDiGetClassDevs(DMSet(idx).AsscGUID, vbNullString, Me.hWnd, DIGCF_ALLCLASSES)
If hSet = INVALID_HANDLE_VALUE Then Return Err.LastDllError
tDevInfo.cbSize = LenB(Of SP_DEVINFO_DATA)
j = 0
Do While SetupDiEnumDeviceInfo(hSet, j, tDevInfo)
cchReq = 0
sBufN = "": sBufID = ""
ret = SetupDiGetDeviceInstanceId(hSet, tDevInfo, vbNullString, 0, cchReq)
If cchReq Then
sBufID = String$(cchReq, 0)
ret = SetupDiGetDeviceInstanceId(hSet, tDevInfo, sBufID, Len(sBufID), cchReq)
If InStr(sBufID, Chr$(0)) > 1 Then
sBufID = Left$(sBufID, InStr(sBufID, Chr$(0)) - 1)
End If
End If
If sBufID = DMSet(idx).InstId Then
tParams.ClassInstallHeader.cbSize = LenB(Of SP_CLASSINSTALL_HEADER)
tParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE
If fEnable Then
tParams.StateChange = DICS_ENABLE
Else
tParams.StateChange = DICS_DISABLE
End If
tParams.Scope = DICS_FLAG_CONFIGSPECIFIC
ret = SetupDiSetClassInstallParams(hSet, tDevInfo, tParams, LenB(Of SP_PROPCHANGE_PARAMS))
If ret Then
ret = SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hSet, tDevInfo)
If ret Then
SetItemOverlayIndex(DMSet(idx).hItem, IIf(fEnable, 0, 3))
SetupDiDestroyDeviceInfoList hSet
Return S_OK
Else
ret = Err.LastDllError
Debug.Print "Failed to disable device; SetupDiCallClassInstaller->" Err.LastDllError & ", " & GetSystemErrorString(Err.LastDllError)
SetupDiDestroyDeviceInfoList hSet
Return ret
End If
Else
ret = Err.LastDllError
SetupDiDestroyDeviceInfoList hSet
Return ret
End If
End If
j += 1
tDevInfo.cbSize = LenB(tDevInfo)
Loop
If hSet Then SetupDiDestroyDeviceInfoList hSet
Return S_FALSE
e0:
Debug.Print CurrentComponentName & "." & CurrentProcedureName & "->Error: " & Err.Number & " (" & Err.Number & "); LastDllError=0x" & Hex$(Err.LastDllError)
If hSet Then SetupDiDestroyDeviceInfoList hSet
End Function
Private Function pvRemoveDevice(idx As Long) As Long
On Error GoTo e0
Dim hSet As LongPtr
Dim i As Long, j As Long
Dim tDevInfo As SP_DEVINFO_DATA
Dim pPages As LongPtr
Dim tParams As SP_REMOVEDEVICE_PARAMS
Dim sBufN As String
Dim sBufID As String
Dim npReq As Long
Dim cchReq As Long
Dim ret As BOOL
Dim regType As REGTYPES
hSet = SetupDiGetClassDevs(DMSet(idx).AsscGUID, vbNullString, Me.hWnd, DIGCF_ALLCLASSES)
If hSet = INVALID_HANDLE_VALUE Then Return Err.LastDllError
tDevInfo.cbSize = LenB(Of SP_DEVINFO_DATA)
j = 0
Do While SetupDiEnumDeviceInfo(hSet, j, tDevInfo)
cchReq = 0
sBufN = "": sBufID = ""
ret = SetupDiGetDeviceInstanceId(hSet, tDevInfo, vbNullString, 0, cchReq)
If cchReq Then
sBufID = String$(cchReq, 0)
ret = SetupDiGetDeviceInstanceId(hSet, tDevInfo, sBufID, Len(sBufID), cchReq)
If InStr(sBufID, Chr$(0)) > 1 Then
sBufID = Left$(sBufID, InStr(sBufID, Chr$(0)) - 1)
End If
End If
If sBufID = DMSet(idx).InstId Then
tParams.ClassInstallHeader.cbSize = LenB(Of SP_CLASSINSTALL_HEADER)
tParams.ClassInstallHeader.InstallFunction = DIF_REMOVE
tParams.Scope = DI_REMOVEDEVICE_GLOBAL
ret = SetupDiSetClassInstallParams(hSet, tDevInfo, tParams, LenB(Of SP_REMOVEDEVICE_PARAMS))
If ret Then
ret = SetupDiCallClassInstaller(DIF_REMOVE, hSet, tDevInfo)
If ret Then
SetupDiDestroyDeviceInfoList hSet
Return S_OK
Else
ret = Err.LastDllError
Debug.Print "Failed to remove device; SetupDiCallClassInstaller->" Err.LastDllError & ", " & GetSystemErrorString(Err.LastDllError)
SetupDiDestroyDeviceInfoList hSet
Return ret
End If
Else
ret = Err.LastDllError
SetupDiDestroyDeviceInfoList hSet
Return ret
End If
End If
j += 1
tDevInfo.cbSize = LenB(tDevInfo)
Loop
If hSet Then SetupDiDestroyDeviceInfoList hSet
Return S_FALSE
e0:
Debug.Print CurrentComponentName & "." & CurrentProcedureName & "->Error: " & Err.Number & " (" & Err.Number & "); LastDllError=0x" & Hex$(Err.LastDllError)
If hSet Then SetupDiDestroyDeviceInfoList hSet
End Function
[Description("Returns a Node object given an HTREEITEM handle.")]
Private Function pvNodeFromHandle(hItem As LongPtr) As Node
Dim oNode As Node
For Each oNode In TreeView1.Nodes
If oNode.Handle = hItem Then
Set pvNodeFromHandle = oNode
End If
Next
End Function
[Description("Returns the DMSet items for the TreeView node represented by it's handle (HITEM)")]
Private Function pvItemIndexFromHITEM(ByVal hItem As LongPtr) As Long
Dim i As Long
For i = 0 To UBound(DMSet)
If DMSet(i).hItem = hItem Then Return i
Next
Return -1
End Function
[Description("Prunes unused device categories from the tree.")]
Private Function pvPruneUnused() As Boolean
Dim pNode As Node
For Each pNode In TreeView1.Nodes
If DMSet(CLng(pNode.Key)).bDevice = False Then
If pNode.Children = 0 Then
TreeView1.Nodes.Remove pNode.Index
End If
End If
Next
End Function
Private Sub OnRefresh() Handles cmdEnum.Click, mnuRefresh.Click
TreeView1.Nodes.Clear
ReDim arClasses(0)
ReDim DMSet(0)
nItems = 0
nDevices = 0
pvEnumClasses
pvPopulateDevices
If Check1.Value = vbUnchecked Then Call pvPruneUnused()
End Sub
Private Sub OnCmdPruneClick() Handles cmdPrune.Click
pvPruneUnused
End Sub
Private Sub TreeView1_DblClick() Handles TreeView1.DblClick, mnuProps.Click
Dim selIdx As Long = pvItemIndexFromHITEM(TreeView1.SelectedItem.Handle)
If DMSet(selIdx).bDevice = False Then
txtStatus.Text = "Please select a specific device."
Exit Sub
End If
idxSelected = selIdx
pvShowPropPage selIdx
End Sub
Private Sub OnEnableDevice() Handles cmdEnable.Click, mnuEnable.Click
If TreeView1.SelectedItem Is Nothing Then
txtStatus.Text = "Please select a specific device."
Beep
Exit Sub
End If
Dim selIdx As Long = pvItemIndexFromHITEM(TreeView1.SelectedItem.Handle)
If DMSet(selIdx).bDevice = False Then
txtStatus.Text = "Please select a specific device."
Exit Sub
End If
Dim ret As Long = pvEnableDevice(selIdx, True)
If ret = S_OK Then
txtStatus.Text = "Successfully enabled " & DMSet(selIdx).DispName
Else
If ret = S_FALSE Then
txtStatus.Text = "Couldn't obtain device reference."
Else
txtStatus.Text = "An error occured enabling device: " & ret & ", " & GetSystemErrorString(ret)
End If
End If
End Sub
Private Sub OnDisableDevice() Handles cmdDisable.Click, mnuDisable.Click
If TreeView1.SelectedItem Is Nothing Then
txtStatus.Text = "Please select a specific device."
Beep
Exit Sub
End If
Dim selIdx As Long = pvItemIndexFromHITEM(TreeView1.SelectedItem.Handle)
If DMSet(selIdx).bDevice = False Then
txtStatus.Text = "Please select a specific device."
Exit Sub
End If
Dim ret As Long = pvEnableDevice(selIdx, True)
If ret = S_OK Then
txtStatus.Text = "Successfully enabled " & DMSet(selIdx).DispName
Else
If ret = S_FALSE Then
txtStatus.Text = "Couldn't obtain device reference."
Else
txtStatus.Text = "An error occured disabling device: " & ret & ", " & GetSystemErrorString(ret)
End If
End If
End Sub
Private Sub OnRemoveDevice() Handles cmdRem.Click, mnuRemove.Click
If TreeView1.SelectedItem Is Nothing Then
txtStatus.Text = "Please select a specific device."
Beep
Exit Sub
End If
Dim selIdx As Long = pvItemIndexFromHITEM(TreeView1.SelectedItem.Handle)
If DMSet(selIdx).bDevice = False Then
txtStatus.Text = "Please select a specific device."
Exit Sub
End If
Dim ret As Long = pvRemoveDevice(selIdx)
If ret = S_OK Then
txtStatus.Text = "Successfully removed " & DMSet(selIdx).DispName
Else
If ret = S_FALSE Then
txtStatus.Text = "Couldn't obtain device reference."
Else
txtStatus.Text = "An error occured removing device: " & ret & ", " & GetSystemErrorString(ret)