COM 오브젝트를 인젝션해서 분석해 보면 답이 나옴 ㅋ.
기본 사운드 장치 선택은 rundll32.exe 라는 호스트 프로세스에 의해서 로드 되는 mmsys.cpl 이라는
Control Panel Applet에 의해서 선택되게 되어있고,
class GUID가 870af99c_171d_4f9e_af0d_e63df40c2bc9 인 COM 객체를 통해서,
GUID가 f8679f50_850a_41cf_9c72_430f290290c8 인 Interface 를 취하고 있음.
MS사에서 이와 관련한 COM Interface에 대한 헤더파일을 제공하고 있지 않기 때문에 Interface 이름에 대해선 알수 없지만
내부적으로 사용하는 이름이 SetDefaultEndpointDevice? 정도가 아닐까 하는 추론이 가능함.
GUID가 f8679f50_850a_41cf_9c72_430f290290c8 인 COM Interface의 Virtual Method Table을 분석해 보면
도합 12개의 Virtual Method를 정의해서 사용하고 있는 것을 알수 있는데,
이중 0 기준으로 10번째 인덱스로 정의 되어 있는 인터페이스 버추얼 메소드가 사운드 기본장치를 선택하는데 사용되고 있음
IMMDeviceEnumerator 로 얻은 스트롱 네임의 Endpoint Device ID 중에 하나를 파라미터로 이 인터페이스에 Dummy 값 하나와
같이 넘겨주면 제어판 경유 없이, 다이렉트로 프로그래밍 방법으로 강제적으로 원하는 기본 사운드 장치를 선택할 수 있음.
테스트 해보니까 Win7, Win8 다 먹힘 ㅋ
하두고 님이 쓰신 글 :
: 그냥 제어판의 사운드창을 백그라운드에 띄워놓고
: 창에 나열된 사운드 장치 정보를 읽어서
: 선택한 후 [기본장치]버튼을 눌러주도록 해서 처리했습니다.
: 뭐 간단하게 해결되네요.
:
: 하지만 문제는 사운드 장치 이름만 읽어오고
: 장치 이름 아래 있는 설명을 읽어올 수 없어 사운드 장치가 모두 "스피커"라고 표시되서
: 도데체 어느 스피커가 어떤 사운드 장치의 스피커인지 알 수가 없네요.
:
: 리버스엔지니어링 님이 쓰신 글 :
: : 윈도우에서 디폴트 사운드 장치를 선택하는 방법은 제어판을 통한 방법 밖에 없습니다
: : MS에서 그런 API를 제공했다간 사운드카드 만드는 회사들이 경쟁적으로 자기들 카드를 디폴트 사운드장치로
: : 설정하려는 사태가 벌어지겠죠. 여러 사운드장치 중 하나로 웨이브 데이타가 출력되게 할수는 있어도 시스템 디폴트
: : 사운드장치를 선택해주는 API는 없습니다.
: :
: : 해결 방법은 비스타 이후 COM으로 바뀐 윈도우 오디오 아키텍쳐를 리버스엔지니어링으로 해킹하는 방법 밖에는 없습니다.
: : COM은 일반적인 API처럼 노출되는게 아니라 해킹하기도 쉽지 않습니다. 그럼에도 불구하고 정 필요하고 패이 조건이 맞으면
: : 리버스엔지니어링으로 해킹해 드릴 수는 있습니다
: :
: :
: :
: : 하두고 님이 쓰신 글 :
: : : 앞에서 했던 질문인데 시원한 답변이 없어 여기 저기 돌아다니며 찾은 소스코드입니다.
: : : 아래 소스코드는 피시에 장착된 사운드장치를 나열하는 소스코드인데요.
: : :
: : : 아래 소스에서 나열된 사운드장치를 선택하여 더블클릭하면
: : : 해당 사운드장치가 윈도우 기본 사운드장치로 바뀌게 하고 싶은데요.
: : :
: : : 기본 사운드 장치를 바꾸는 방법을 모르겠습니다.
: : :
: : : procedure TForm1.EnumAudioDevices;
: : : var
: : : dsCreateDevEnum : ICreateDevEnum;
: : : EnumDevice : IEnumMoniker;
: : : DeviceMoniker : IMoniker;
: : : Data : Integer;
: : : DevicePropBag : IPropertyBag;
: : : DeviceName : OLEVariant;
: : : begin
: : : If CoCreateInstance(CLSID_SystemDeviceEnum,nil,CLSCTX_INPROC_SERVER,IID_ICreateDevEnum,dsCreateDevEnum) = S_OK then
: : : Begin
: : : If dsCreateDevEnum.CreateClassEnumerator(CLSID_AudioRendererCategory,EnumDevice,0) = S_OK then
: : : Begin
: : : EnumDevice.Reset;
: : : While EnumDevice.Next(1,DeviceMoniker,@Data) = S_OK do
: : : Begin
: : : If DeviceMoniker.BindToStorage(nil,nil,IID_IPropertyBag,DevicePropBag) = NOERROR then
: : : Begin
: : : If DevicePropBag.Read('FriendlyName',DeviceName,nil) = NOERROR then
: : : IF Copy(DeviceName, 1, Length('DirectSound')) = 'DirectSound' Then
: : : ListBox1.Items.Add(Copy(DeviceName, Length('DirectSound: ') + 1, Length(DeviceName) - Length('DirectSound: ')));
: : : DevicePropBag := nil;
: : : End;
: : : DeviceMoniker := nil;
: : : End;
: : : EnumDevice := nil;
: : : End;
: : : dsCreateDevEnum := nil;
: : : End;
: : : End;
|