Доброго времени!
Уважаемые гуру, подскажите, есть ли какие-то принципиальные различия при использовании интерфейсов в GUI и в консольных приложениях?
Суть вопроса в следующем:
Имеется код с использованием интерфейсов, который прекрасно работает в GUI (Delphi 7).
При переносе кода в консольное приложение возникает ошибка:
Exception EAccessViolation in module adevdef.exe at 000521C9.
Access violation at address 004521C9 in module 'adevdef.exe'. Read of address 00000000.
Код:
program adevdef;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows, Classes, ActiveX, OleServer, MMSystem, ShlObj;
const
CLSID_MMDeviceEnumerator: TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
Class_PolicyConfigClient: TGUID ='{870af99c-171d-4f9e-af0d-e63df40c2bc9}';
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}';
IID_IPropertyStore: TGUID = '{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}';
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
_tagpropertykey = packed record
fmtid: TGUID;
pid: DWORD;
end;
PROPERTYKEY = _tagpropertykey;
PPropertyKey = ^TPropertyKey;
TPropertyKey = _tagpropertykey;
const
PKEY_Device_FriendlyName: TPropertyKey = (fmtid:(D1:$a45c254e;D2:$df1c;D3:$4efd;D4:($80,$20,$67,$d1,$46,$a8,$50,$e0));pid:14);
type
IAudioEndpointVolumeCallback = interface(IUnknown)
['{657804FA-D6AD-4496-8A60-352752AF4F89}']
end;
IAudioEndpointVolume = interface(IUnknown)
['{5CDF2C82-841E-4546-9722-0CF74078229A}']
end;
IAudioMeterInformation = interface(IUnknown)
['{C02216F6-8C67-4B5B-9D00-D008E73E0064}']
end;
IPropertyStore = interface(IUnknown)
['{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}']
function GetCount(out cProps: LongWord): HResult; stdcall;
function GetAt(iProp: LongWord; out pkey: _tagpropertykey): HResult; stdcall;
function GetValue(const key: TPropertyKey; out pv: TPROPVARIANT): HResult; stdcall;
function SetValue(const key: TPropertyKey; out propvar: TPROPVARIANT): HResult; stdcall;
function Commit: HResult; stdcall;
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: PWideChar): 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; out DevCollection: IMMDeviceCollection): HRESULT; stdcall;
end;
IPolicyConfig = interface(IUnknown)
['{f8679f50-850a-41cf-9c72-430f290290c8}']
function GetMixFormat(a: PWideChar; var b: TWAVEFORMATEX): HRESULT; stdcall;
function GetDeviceFormat(a: PWideChar; b: integer; var c: TWAVEFORMATEX): HRESULT; stdcall;
function ResetDeviceFormat(a: PWideChar): HRESULT; stdcall;
function SetDeviceFormat(a: PWideChar; var b: TWAVEFORMATEX; var c: TWAVEFORMATEX): HRESULT; stdcall;
function GetProcessingPeriod(a: PWideChar; b: integer; c: PINT64; d: PINT64): HRESULT; stdcall;
function SetProcessingPeriod(a: PWideChar; b: PINT64): HRESULT; stdcall;
function GetShareMode(a: PWideChar; b: pointer{struct DeviceShareMode *}): HRESULT; stdcall;
function SetShareMode(a: PWideChar; b: pointer{struct DeviceShareMode *}): HRESULT; stdcall;
function GetPropertyValue(devID: PWideChar; const Key: _tagpropertykey; V: TPROPVARIANT): HRESULT; stdcall;
function SetPropertyValue(devID: PWideChar; const Key: _tagpropertykey; V: TPROPVARIANT): HRESULT; stdcall;
function SetDefaultEndpoint(wszDeviceID: PWideChar; ARole: ERole):Hresult; stdcall;
end;
function GetAudioDeviceList(DevList: TStrings): boolean;
var
AudioEndpoints: IMMDeviceEnumerator;
Collection: IMMDeviceCollection;
Device: IMMDevice;
Proper: IPropertyStore;
i: Integer;
Count_Dev: UINT;
Id_Dev: PWideChar;
DId: WideString;
Prop: IPropertyStore;
DeviceName: PROPVARIANT;
begin
Result := false;
CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, AudioEndpoints);
AudioEndpoints.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, Collection);
Collection.GetCount(Count_Dev);
for i:=0 to Count_Dev-1 do
begin
Collection.Item(i, Device);
DId := '';
Result := Succeeded(Device.GetId(Id_Dev)) and (Id_Dev <> nil);
if Result then
begin
DId := WideString(Id_Dev);
Device.OpenPropertyStore(STGM_READ, Prop);
Prop.GetValue(PKEY_Device_FriendlyName, DeviceName);
CoTaskMemFree(Id_Dev);
DevList.Append(DId + ' ' + PROPVARIANT(DeviceName).pwszVal);
end;
end;
end;
procedure SetAudioDeviceDefault(Index: integer);
var
AudioEndpoints: IMMDeviceEnumerator;
Collection: IMMDeviceCollection;
Device: IMMDevice;
Def_Dev_Ch: IPolicyConfig;
Id_Dev: PWideChar;
ID_Dev_Def: WideString;
begin
CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, AudioEndpoints);
AudioEndpoints.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, Collection);
Collection.Item(Index, Device);
Device.GetId(Id_Dev);
if Succeeded(CoCreateInstance(Class_PolicyConfigClient, nil, CLSCTX_INPROC_SERVER, IPolicyConfig, Def_Dev_Ch)) then begin
if Succeeded(Def_Dev_Ch.SetDefaultEndpoint(Id_Dev, eConsole)) then begin
Writeln('eConsole')
end
else begin
Writeln(IntToStr(HResult(Def_Dev_Ch.SetDefaultEndpoint(Id_Dev, eConsole))));
end;
if Succeeded(Def_Dev_Ch.SetDefaultEndpoint(Id_Dev, eMultimedia)) then begin
Writeln('eMultimedia')
end
else begin
Writeln(IntToStr(HResult(Def_Dev_Ch.SetDefaultEndpoint(Id_Dev, eMultimedia))));
end;
if Succeeded(Def_Dev_Ch.SetDefaultEndpoint(Id_Dev,eCommunications)) then begin
Writeln('eCommunications')
end
else begin
Writeln(IntToStr(HResult(Def_Dev_Ch.SetDefaultEndpoint(Id_Dev, eCommunications))));
end;
end;
end;
var
i: integer;
R: boolean;
MyDevList: TStringList;
begin
{ TODO -oUser -cConsole Main : Insert code here }
MyDevList := TStringList.Create;
R := GetAudioDeviceList(MyDevList);
for i:=0 to MyDevList.Count-1 do
begin
Writeln(MyDevList.Strings[i]);
end;
if MyDevList <> nil then MyDevList.Free;
end.