![]() |
Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
Guten Abend,
seit ein paar Tagen beschäftige ich mich damit, die Audioendgeräte unter Win7 zu ermitteln und aufzulisten. Grund dafür ist, das ich versuchen möchte, eine Anwendung zu schreiben, mit der ich das Standardausgabegerät ändern kann - von den Boxen schnell zu den Kopfhörern wechseln und umgegehrt. Nun habe ich über zahlreiche Seiten Informationen bekommen, doch leider schaff ich es nicht die Geräte aufzulisten auch nicht aufzuzählen. Probleme machen mir manche Deklarationen die in der MSDN wohl anders sind als die Übersetzung die ich habe, mit den doppelten Pointer komm ich noch nicht ganz klar. zunächst folgende Links und Codeblöcke: ![]() ![]() ![]()
Code:
Über folgenden Abschnitt versuche ich anhand der oben genannten Informationen die Geräte auszulesen bzw. aufzuzählen:
unit Unit2;
interface uses Windows, ActiveX, ComObj; const CLSID_MMDeviceEnumerator : TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}'; IID_IMMDeviceEnumerator : TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}'; IID_IMMDevice : TGUID = '{D666063F-1587-4E43-81F1-B948E807363F}'; IID_IMMDeviceCollection : TGUID = '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}'; IID_IAudioEndpointVolume : TGUID = '{5CDF2C82-841E-4546-9722-0CF74078229A}'; IID_IAudioMeterInformation : TGUID = '{C02216F6-8C67-4B5B-9D00-D008E73E0064}'; IID_IAudioEndpointVolumeCallback : TGUID = '{657804FA-D6AD-4496-8A60-352752AF4F89}'; DEVICE_STATE_ACTIVE = $00000001; DEVICE_STATE_UNPLUGGED = $00000002; DEVICE_STATE_NOTPRESENT = $00000004; DEVICE_STATEMASK_ALL = $00000007; type EDataFlow = TOleEnum; const eRender = $00000000; eCapture = $00000001; eAll = $00000002; EDataFlow_enum_count = $00000003; type ERole = TOleEnum; const eConsole = $00000000; eMultimedia = $00000001; eCommunications = $00000002; ERole_enum_count = $00000003; type IAudioEndpointVolumeCallback = interface(IUnknown) ['{657804FA-D6AD-4496-8A60-352752AF4F89}'] end; IAudioEndpointVolume = interface(IUnknown) ['{5CDF2C82-841E-4546-9722-0CF74078229A}'] function RegisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall; function UnregisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall; function GetChannelCount(out PInteger): Integer; stdcall; function SetMasterVolumeLevel(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall; function SetMasterVolumeLevelScalar(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall; function GetMasterVolumeLevel(out fLevelDB: single): Integer; stdcall; function GetMasterVolumeLevelScaler(out fLevelDB: single): Integer; stdcall; function SetChannelVolumeLevel(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall; function SetChannelVolumeLevelScalar(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall; function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double): Integer; stdcall; function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double): Integer; stdcall; function SetMute(bMute: Boolean; pguidEventContext: PGUID): Integer; stdcall; function GetMute(out bMute: Boolean): Integer; stdcall; function GetVolumeStepInfo(pnStep: Integer; out pnStepCount: Integer): Integer; stdcall; function VolumeStepUp(pguidEventContext: PGUID): Integer; stdcall; function VolumeStepDown(pguidEventContext: PGUID): Integer; stdcall; function QueryHardwareSupport(out pdwHardwareSupportMask): Integer; stdcall; function GetVolumeRange(out pflVolumeMindB: double; out pflVolumeMaxdB: double; out pflVolumeIncrementdB: double): Integer; stdcall; end; IAudioMeterInformation = interface(IUnknown) ['{C02216F6-8C67-4B5B-9D00-D008E73E0064}'] function GetPeakValue(out Peak: Real): HRESULT; stdcall; end; IPropertyStore = interface(IUnknown) end; IMMDevice = interface(IUnknown) ['{D666063F-1587-4E43-81F1-B948E807363F}'] function Activate(const refId: TGUID; dwClsCtx: DWORD; pActivationParams: PInteger; out pEndpointVolume: IAudioEndpointVolume): Hresult; stdCall; function OpenPropertyStore(stgmAccess: DWORD; out ppProperties: IPropertyStore): Hresult; stdcall; function GetId(out ppstrId: PLPWSTR): Hresult; stdcall; function GetState(out State: Integer): Hresult; stdcall; end; IMMDeviceCollection = interface(IUnknown) ['{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}'] function GetCount(out pcDevices: UINT): HRESULT; stdcall; function Item(nDevice: UINT; out ppDevice: IMMDevice): HRESULT; stdcall; end; IMMNotificationClient = interface(IUnknown) ['{7991EEC9-7E89-4D85-8390-6C703CEC60C0}'] end; IMMDeviceEnumerator = interface(IUnknown) ['{A95664D2-9614-4F35-A746-DE8DB63617E6}'] function EnumAudioEndpoints(dataFlow: EDataFlow; deviceState: SYSUINT; DevCollection: IMMDeviceCollection): Hresult; stdcall; function GetDefaultAudioEndpoint(EDF: SYSUINT; ER: SYSUINT; out Dev :IMMDevice ): Hresult; stdcall; function GetDevice(pwstrId: pointer; out Dev: IMMDevice): HResult; stdcall; function RegisterEndpointNotificationCallback(pClient: IMMNotificationClient): Hresult; stdcall; end; implementation end.
Code:
Das Problem ist, das durch EnumAudioEndpoints ein Fehler mit der MMDeviceCollection vorliegt, hr von CoCreateInstance ist 0.
procedure TForm1.Button2Click(Sender: TObject);
var MMDeviceCollection: IMMDeviceCollection; MMDeviceEnumerator: IMMDeviceEnumerator; hr: HResult; count : UINT; begin hr := CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, MMDeviceEnumerator); hr := MMDeviceEnumerator.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, MMDeviceCollection); // Ungültiger Zeiger ShowMessage(SysErrorMessage(hr)); // führt zum Programmabbruch - Lesen von Adresse 00000000 ... hr := MMDeviceCollection.GetCount(count); end; Im dritten Link zur MSDN wird aber im CoCreateInstance mit einem void** gearbeitet, was mir erstmal nicht viel sagt. Weiterhin werden für die IMMDevice... Pointer deklariert, was aber laut Delphideklaration nicht der Fall ist, funktionieren tu es aber bis zum genannten Punkt dennoch. Hat jemand einen Rat oder einen Ansatz, damit ich die Ausgabegeräte ermitteln und am Ende auch über die Anwendung setzen kann? Grüße Marcel |
AW: Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
Probier es mal so wie das in dem Post von mir gemacht ist:
![]() PS. Ich würde dir auch dringend dazu raten, den Rückgabe wert auszuwerten, und erst bei erfolgreichem Verbinden, EnumEndPoints usw. aufzurufen... |
AW: Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
Guten Abend,
soweit ich das überblicken kann, ist die MMDevApi bis auf GetCount und Item für IMMDeviceCollection identisch, sicherlich gleich oder ähnliche Quelle. Der Unterschied besteht lediglich darin, das im FormCreate die Initialisierung statt findet. Füge ich dann den Teil zur Ermittlung der Devices hinzu, ändert das leider nichts am Problem. Das Beipsiel mit dem Setzen der Lautstärke hatte ich auch probiert und das funktioniert sehr gut. Prinzipiell geht es also. |
AW: Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
Delphi-Quellcode:
-->CLSCTX_INPROC_SERVER
CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, deviceEnumerator);
Zitat:
Ich denk CoCreateInstance schlägt fehl? Dann kann das mit der Lautstärke auch nicht gehen :? |
AW: Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
Moin,
nein, das CoCreateInstance schlägt nicht fehl. Zitat:
MMDeviceEnumerator.EnumAudioEndpoints schlägt mit dem Fehler "ungültiger Zeiger" fehl. |
AW: Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
Hat keiner eine Idee oder einen Rat?
|
AW: Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
Im Prinzip finde ich es eine prakrische Sache (hier streitet sich auch manchmal die Soundkarte mit den USB-Lautsprechern, so daß ich dann nicht immer am richtigen Ende etwas höre), aber hab grade nicht nicht Zeit dafür.
Aber vielleicht finde ich nächste Woche mal etwas Zeit um hier genauer zu gucken. Dennoch schonmal ein anderer Tipp: Typisierte Konstanten sind nicht immer optimial, da es eigentlich "nur" schreibgeschütze Varialen sind. Und als "echte" Konstante kann man sie auch gleich weiterverwenden
Delphi-Quellcode:
const
IID_IAudioEndpointVolumeCallback = '{657804FA-D6AD-4496-8A60-352752AF4F89}'; type IAudioEndpointVolumeCallback = interface(IUnknown) [IID_IAudioEndpointVolumeCallback] ... end; |
AW: Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
Danke erstmal für den Tipp.
Dadurch muss ich natürlich mit StringToGUID() die Constanten erstmal umwandeln. Ich hatte zum eigentlichen Problem noch weiter gesucht, leider keine Variante gefunden, das Problem zu lösen. Ich versteh nicht warum ich einen "ungültigen Zeiger" habe. Gruß Marcel |
AW: Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
Ich hab mich da auch mal ein wenig kundig gemacht, konnte bisher nur finden, dass andere Leute wohl ähnliche Probleme mit Delphi haben, mit anderen Sprachen soll das aber funktionieren, also liegt es wohl an Delphi??
|
AW: Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
OK, dann wenigstens so ... hab's grade mal ausprobiert und der Compiler nimmt dort auch die GUID direkt an.
Delphi-Quellcode:
const
IID_IAudioEndpointVolumeCallback: TGUID = '{657804FA-D6AD-4496-8A60-352752AF4F89}'; type IAudioEndpointVolumeCallback = interface(IUnknown) [IID_IAudioEndpointVolumeCallback] end; Hmm, aber an Delphi sollte es doch nicht liegen? Da es hier nix Delphieigenes gibt. Du solltst aber dringend eine Deklarationen prüfen. Bei IMMDeviceEnumerator fehlte z.B. die letzte Methode. PS: Es kommt hier auch auf die Reihenfolge der Methoden drauf an, da diese "nur" durchnummeriert werden und Delphi/Windows nicht auf die Methodennamen achtet. OUT-Parameter sind OUT nicht nicht VAR, denn bei OUT wird der Eingangswert ignoriert. Bei Interfaces würde also der Referenzzähler eines enthaltenen Interfaces nicht dekrementiert und es entsteht quasi ein Speicherleck. Ob es nun als OUT oder VAR deklariert ist, ist egal, da dieses an der Funktion selber liegt, aber beim OUT sieht man wenigstens gleich, daß man aufpassen muß. So, das geht jetzt erstmal. :angle2:
Delphi-Quellcode:
*1 In diesem Fall ist es zwar schon NIL, aber es kann nicht schaden (falls das mal jemand z.B. in einer Schleife aufruft).
uses
Windows, ActiveX, ComObj; const CLSID_MMDeviceEnumerator : TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}'; IID_IMMDeviceEnumerator : TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}'; IID_IMMDevice : TGUID = '{D666063F-1587-4E43-81F1-B948E807363F}'; IID_IMMDeviceCollection : TGUID = '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}'; IID_IAudioEndpointVolume : TGUID = '{5CDF2C82-841E-4546-9722-0CF74078229A}'; IID_IAudioMeterInformation : TGUID = '{C02216F6-8C67-4B5B-9D00-D008E73E0064}'; IID_IAudioEndpointVolumeCallback : TGUID = '{657804FA-D6AD-4496-8A60-352752AF4F89}'; IID_IMMNotificationClient : TGUID = '{7991EEC9-7E89-4D85-8390-6C703CEC60C0}'; DEVICE_STATE_ACTIVE = $00000001; DEVICE_STATE_UNPLUGGED = $00000002; DEVICE_STATE_NOTPRESENT = $00000004; DEVICE_STATEMASK_ALL = $00000007; type EDataFlow = TOleEnum; const eRender = $00000000; eCapture = $00000001; eAll = $00000002; EDataFlow_enum_count = $00000003; type ERole = TOleEnum; const eConsole = $00000000; eMultimedia = $00000001; eCommunications = $00000002; ERole_enum_count = $00000003; type IAudioEndpointVolumeCallback = interface(IUnknown) [IID_IAudioEndpointVolumeCallback] end; IAudioEndpointVolume = interface(IUnknown) [IID_IAudioEndpointVolume] function RegisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall; function UnregisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall; function GetChannelCount(out PInteger): Integer; stdcall; function SetMasterVolumeLevel(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall; function SetMasterVolumeLevelScalar(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall; function GetMasterVolumeLevel(out fLevelDB: single): Integer; stdcall; function GetMasterVolumeLevelScaler(out fLevelDB: single): Integer; stdcall; function SetChannelVolumeLevel(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall; function SetChannelVolumeLevelScalar(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall; function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double): Integer; stdcall; function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double): Integer; stdcall; function SetMute(bMute: Boolean; pguidEventContext: PGUID): Integer; stdcall; function GetMute(out bMute: Boolean): Integer; stdcall; function GetVolumeStepInfo(pnStep: Integer; out pnStepCount: Integer): Integer; stdcall; function VolumeStepUp(pguidEventContext: PGUID): Integer; stdcall; function VolumeStepDown(pguidEventContext: PGUID): Integer; stdcall; function QueryHardwareSupport(out pdwHardwareSupportMask): Integer; stdcall; function GetVolumeRange(out pflVolumeMindB: double; out pflVolumeMaxdB: double; out pflVolumeIncrementdB: double): Integer; stdcall; end; IAudioMeterInformation = interface(IUnknown) [IID_IAudioMeterInformation] function GetPeakValue(out Peak: Real): HRESULT; stdcall; end; IPropertyStore = interface(IUnknown) end; IMMDevice = interface(IUnknown) [IID_IMMDevice] function Activate(const refId: TGUID; dwClsCtx: DWORD; pActivationParams: PInteger; out pEndpointVolume: IAudioEndpointVolume): HRESULT; stdCall; function OpenPropertyStore(stgmAccess: DWORD; out ppProperties: IPropertyStore): HRESULT; stdcall; function GetId(out ppstrId: PLPWSTR): HRESULT; stdcall; function GetState(out State: Integer): HRESULT; stdcall; end; IMMDeviceCollection = interface(IUnknown) [IID_IMMDeviceCollection] function GetCount(out pcDevices: UINT): HRESULT; stdcall; function Item(nDevice: UINT; out ppDevice: IMMDevice): HRESULT; stdcall; end; IMMNotificationClient = interface(IUnknown) [IID_IMMNotificationClient] end; IMMDeviceEnumerator = interface(IUnknown) [IID_IMMDeviceEnumerator] function EnumAudioEndpoints(dataFlow: EDataFlow; deviceState: SYSUINT; out DevCollection: IMMDeviceCollection): HRESULT; stdcall; function GetDefaultAudioEndpoint(EDF: SYSUINT; ER: SYSUINT; out Dev: IMMDevice): HRESULT; stdcall; function GetDevice(pwstrId: pointer; out Dev: IMMDevice): HRESULT; stdcall; function RegisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall; function UnregisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall; end; procedure TForm1.FormCreate(Sender: TObject); var MMDeviceCollection: IMMDeviceCollection; MMDeviceEnumerator: IMMDeviceEnumerator; hr: HRESULT; count : UINT; begin hr := CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, MMDeviceEnumerator); if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr)); MMDeviceCollection := nil; // wegen dem OUT-Parameter *1 hr := MMDeviceEnumerator.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, MMDeviceCollection); if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr)); hr := MMDeviceCollection.GetCount(count); if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr)); end; PS: bitte den Code via EDIT oder ZITAT kopieren, da der Delphi-Syntaxhighlighter immernoch Leerzeichen ignoriert. :wall: |
AW: Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
himitsu, recht vielen Dank für deine Mühe an diesem Pfingstmontag :).
Das auslesen funktioniert nun, kann also an der Anwendung weiter bauen und sie schnellsmöglich veröffentlichen ;). Was nicht geht ist, dass ich die TGUID im Interface verwenden kann. Ich nutze Delphi 7, möglicherweise ist hier noch eine Beschränkung. Danke auch für die Informationen zu den Interfaces selbst, mit den Methoden und den OUT, VAR Parametern, alles zusammen war mir so nicht bewusst. Da gilt für mich noch mehr in Erfahrung zu bringen. Marcel |
AW: Win7 Audioendgerärte über EnumAudioEndpoints ermitteln
Ich bin mit dem OUT mal beim WMI in die Falle getreten ... das ist auch der Grund, warum viele WMI-Klassen ein Speicherleck besitzen, da jeder von jedem abguckt und so den Fehler verbreiten. :lol:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:41 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz