• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

AndreMiras / pycaw / 20382538633

19 Dec 2025 09:04PM UTC coverage: 65.643% (-1.6%) from 67.239%
20382538633

push

github

AndreMiras
:sparkles: Add robust PROPVARIANT handling and PolicyConfig fallback

Improve reliability across different Windows versions and comtypes
installations by adding fallback logic for PROPVARIANT union access
patterns and IPolicyConfigVista interface support.

- Handle multiple comtypes memory layouts for VT_LPWSTR in GetValue()
- Add FriendlyName fallback to DeviceDesc property
- Add IPolicyConfigVista interface for Windows Vista/7 compatibility
- Add SetDefaultDevice fallback from IPolicyConfig to IPolicyConfigVista

Based on patterns from Mr5niper's WindowsAudioControl-CLI-wGUI, closes TODO-108

9 of 34 new or added lines in 3 files covered. (26.47%)

556 of 847 relevant lines covered (65.64%)

0.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.85
/pycaw/api/mmdeviceapi/depend/structures.py
1
from ctypes import Structure, Union, byref, windll
1✔
2
from ctypes.wintypes import DWORD, LONG, LPWSTR, ULARGE_INTEGER, VARIANT_BOOL, WORD
1✔
3

4
from comtypes import GUID
1✔
5
from comtypes.automation import VARTYPE, VT_BOOL, VT_CLSID, VT_LPWSTR, VT_UI4
1✔
6

7

8
class PROPVARIANT_UNION(Union):
1✔
9
    _fields_ = [
1✔
10
        ("lVal", LONG),
11
        ("uhVal", ULARGE_INTEGER),
12
        ("boolVal", VARIANT_BOOL),
13
        ("pwszVal", LPWSTR),
14
        ("puuid", GUID),
15
    ]
16

17

18
class PROPVARIANT(Structure):
1✔
19
    _fields_ = [
1✔
20
        ("vt", VARTYPE),
21
        ("reserved1", WORD),
22
        ("reserved2", WORD),
23
        ("reserved3", WORD),
24
        ("union", PROPVARIANT_UNION),
25
    ]
26

27
    def GetValue(self):
1✔
28
        vt = self.vt
1✔
29
        if vt == VT_BOOL:
1✔
30
            return self.union.boolVal != 0
1✔
31
        elif vt == VT_LPWSTR:
1✔
32
            # Try multiple access patterns for comtypes compatibility
33
            # Pattern 1: Direct union access
34
            result = getattr(self.union, "pwszVal", None)
1✔
35
            if result is not None:
1✔
36
                return result
1✔
37
            # Pattern 2: Nested value object
NEW
38
            value_obj = getattr(self, "value", None)
×
NEW
39
            if value_obj is not None:
×
NEW
40
                result = getattr(value_obj, "pwszVal", None)
×
NEW
41
                if result is not None:
×
NEW
42
                    return result
×
43
            # Pattern 3: Anonymous union access
NEW
44
            result = getattr(self, "pwszVal", None)
×
NEW
45
            if result is not None:
×
NEW
46
                return result
×
47
            # Pattern 4: Data object access
NEW
48
            data_obj = getattr(self, "data", None)
×
NEW
49
            if data_obj is not None:
×
NEW
50
                result = getattr(data_obj, "pwszVal", None)
×
NEW
51
                if result is not None:
×
NEW
52
                    return result
×
53
            # If all patterns fail, return None
NEW
54
            return None
×
55
        elif vt == VT_UI4:
1✔
56
            return self.union.lVal
1✔
57
        elif vt == VT_CLSID:
1✔
58
            return
1✔
59
        else:
60
            return "%s:?" % (vt)
1✔
61

62
    def clear(self):
1✔
63
        windll.ole32.PropVariantClear(byref(self))
1✔
64

65

66
class PROPERTYKEY(Structure):
1✔
67
    _fields_ = [
1✔
68
        ("fmtid", GUID),
69
        ("pid", DWORD),
70
    ]
71

72
    def __str__(self):
1✔
73
        return "%s %s" % (self.fmtid, self.pid)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc