Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

496 lines
11 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: shi.cpp
  4. //
  5. // Description:
  6. //
  7. // Shingle Instance Class
  8. //
  9. //@@BEGIN_MSINTERNAL
  10. // Development Team:
  11. // Mike McLaughlin
  12. //
  13. // History: Date Author Comment
  14. //
  15. // To Do: Date Author Comment
  16. //
  17. //@@END_MSINTERNAL
  18. //
  19. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  20. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  21. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  22. // PURPOSE.
  23. //
  24. // Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
  25. //
  26. //---------------------------------------------------------------------------
  27. #include "common.h"
  28. //---------------------------------------------------------------------------
  29. //---------------------------------------------------------------------------
  30. const WCHAR cwstrDefaultDevicePath[] =
  31. REGSTR_PATH_MULTIMEDIA_AUDIO_DEFAULT_DEVICE;
  32. const WCHAR cwstrDefaultMidiDevicePath[] =
  33. REGSTR_PATH_MULTIMEDIA_MIDI_DEFAULT_DEVICE;
  34. const WCHAR cwstrPlayback[] = REGSTR_VAL_DEFAULT_PLAYBACK_DEVICE;
  35. const WCHAR cwstrRecord[] = REGSTR_VAL_DEFAULT_RECORD_DEVICE;
  36. const WCHAR cwstrMidi[] = REGSTR_VAL_DEFAULT_MIDI_DEVICE;
  37. const WCHAR cwstrFilterTypeName[] = KSSTRING_Filter;
  38. const WCHAR cwstrPlaybackShingleName[] = L"PLAYBACK";
  39. const WCHAR cwstrRecordShingleName[] = L"RECORD";
  40. const WCHAR cwstrMidiShingleName[] = L"MIDI";
  41. const WCHAR cwstrMixerShingleName[] = L"MIXER";
  42. #ifdef DEBUG
  43. const WCHAR cwstrPinsShingleName[] = L"PINS";
  44. #endif
  45. PSHINGLE_INSTANCE apShingleInstance[] = {
  46. NULL, // KSPROPERTY_SYSAUDIO_NORMAL_DEFAULT
  47. NULL, // KSPROPERTY_SYSAUDIO_PLAYBACK_DEFAULT
  48. NULL, // KSPROPERTY_SYSAUDIO_RECORD_DEFAULT
  49. NULL, // KSPROPERTY_SYSAUDIO_MIDI_DEFAULT
  50. NULL, // KSPROPERTY_SYSAUDIO_MIXER_DEFAULT
  51. #ifdef DEBUG
  52. NULL,
  53. #endif
  54. };
  55. ULONG aulFlags[] = {
  56. FLAGS_COMBINE_PINS | GN_FLAGS_PLAYBACK | GN_FLAGS_RECORD | GN_FLAGS_MIDI,
  57. FLAGS_COMBINE_PINS | GN_FLAGS_PLAYBACK,
  58. FLAGS_COMBINE_PINS | GN_FLAGS_RECORD,
  59. FLAGS_COMBINE_PINS | GN_FLAGS_MIDI,
  60. FLAGS_MIXER_TOPOLOGY | GN_FLAGS_PLAYBACK | GN_FLAGS_RECORD | GN_FLAGS_MIDI,
  61. #ifdef DEBUG
  62. GN_FLAGS_PLAYBACK,
  63. #endif
  64. };
  65. PCWSTR apcwstrRegistryPath[] = {
  66. NULL,
  67. cwstrDefaultDevicePath,
  68. cwstrDefaultDevicePath,
  69. cwstrDefaultMidiDevicePath,
  70. NULL,
  71. #ifdef DEBUG
  72. cwstrDefaultDevicePath,
  73. #endif
  74. };
  75. PCWSTR apcwstrRegistryValue[] = {
  76. NULL,
  77. cwstrPlayback,
  78. cwstrRecord,
  79. cwstrMidi,
  80. NULL,
  81. #ifdef DEBUG
  82. cwstrPlayback,
  83. #endif
  84. };
  85. PCWSTR apcwstrReference[] = {
  86. cwstrFilterTypeName,
  87. cwstrPlaybackShingleName,
  88. cwstrRecordShingleName,
  89. cwstrMidiShingleName,
  90. cwstrMixerShingleName,
  91. #ifdef DEBUG
  92. cwstrPinsShingleName,
  93. #endif
  94. };
  95. //---------------------------------------------------------------------------
  96. //---------------------------------------------------------------------------
  97. NTSTATUS
  98. CShingleInstance::InitializeShingle(
  99. )
  100. {
  101. NTSTATUS Status = STATUS_SUCCESS;
  102. int i;
  103. for(i = 0; i < SIZEOF_ARRAY(apShingleInstance); i++) {
  104. apShingleInstance[i] = new SHINGLE_INSTANCE(
  105. aulFlags[i],
  106. apcwstrRegistryPath[i],
  107. apcwstrRegistryValue[i]);
  108. if(apShingleInstance[i] == NULL) {
  109. Status = STATUS_INSUFFICIENT_RESOURCES;
  110. goto exit;
  111. }
  112. Status = apShingleInstance[i]->CreateCreateItem(apcwstrReference[i]);
  113. if(!NT_SUCCESS(Status)) {
  114. goto exit;
  115. }
  116. }
  117. Status = QueueWorkList(
  118. CShingleInstance::InitializeShingleWorker,
  119. NULL,
  120. NULL);
  121. if(!NT_SUCCESS(Status)) {
  122. goto exit;
  123. }
  124. exit:
  125. if(!NT_SUCCESS(Status)) {
  126. UninitializeShingle();
  127. }
  128. return(Status);
  129. }
  130. VOID
  131. CShingleInstance::UninitializeShingle(
  132. )
  133. {
  134. int i;
  135. for(i = 0; i < SIZEOF_ARRAY(apShingleInstance); i++) {
  136. delete apShingleInstance[i];
  137. apShingleInstance[i] = NULL;
  138. }
  139. }
  140. NTSTATUS
  141. CShingleInstance::InitializeShingleWorker(
  142. PVOID pReference1,
  143. PVOID pReference2
  144. )
  145. {
  146. NTSTATUS Status;
  147. Status = apShingleInstance[KSPROPERTY_SYSAUDIO_PLAYBACK_DEFAULT]->Create(
  148. NULL,
  149. (LPGUID)&KSCATEGORY_PREFERRED_WAVEOUT_DEVICE);
  150. if(!NT_SUCCESS(Status)) {
  151. goto exit;
  152. }
  153. Status = apShingleInstance[KSPROPERTY_SYSAUDIO_RECORD_DEFAULT]->Create(
  154. NULL,
  155. (LPGUID)&KSCATEGORY_PREFERRED_WAVEIN_DEVICE);
  156. if(!NT_SUCCESS(Status)) {
  157. goto exit;
  158. }
  159. Status = apShingleInstance[KSPROPERTY_SYSAUDIO_MIDI_DEFAULT]->Create(
  160. NULL,
  161. (LPGUID)&KSCATEGORY_PREFERRED_MIDIOUT_DEVICE);
  162. if(!NT_SUCCESS(Status)) {
  163. goto exit;
  164. }
  165. exit:
  166. return(Status);
  167. }
  168. //---------------------------------------------------------------------------
  169. CShingleInstance::CShingleInstance(
  170. ULONG ulFlags,
  171. PCWSTR pcwstrRegistryPath,
  172. PCWSTR pcwstrRegistryValue
  173. )
  174. {
  175. this->ulFlags = ulFlags;
  176. this->pcwstrRegistryPath = pcwstrRegistryPath;
  177. this->pcwstrRegistryValue = pcwstrRegistryValue;
  178. }
  179. CShingleInstance::~CShingleInstance(
  180. )
  181. {
  182. PKSOBJECT_CREATE_ITEM pCreateItem;
  183. DPF1(60, "~CShingleInstance: %08x", this);
  184. ASSERT(this != NULL);
  185. Assert(this);
  186. DestroyDeviceInterface();
  187. FOR_EACH_LIST_ITEM(&lstCreateItem, pCreateItem) {
  188. DestroyCreateItem(pCreateItem);
  189. } END_EACH_LIST_ITEM
  190. }
  191. NTSTATUS
  192. CShingleInstance::Create(
  193. IN PDEVICE_NODE pDeviceNode,
  194. IN LPGUID pguidClass
  195. )
  196. {
  197. NTSTATUS Status = STATUS_SUCCESS;
  198. static ULONG cShingles = 0;
  199. this->pDeviceNode = pDeviceNode;
  200. swprintf(wstrReference, L"SAD%d", cShingles++);
  201. Status = CreateCreateItem(wstrReference);
  202. if(!NT_SUCCESS(Status)) {
  203. goto exit;
  204. }
  205. Status = CreateDeviceInterface(pguidClass, wstrReference);
  206. if(!NT_SUCCESS(Status)) {
  207. goto exit;
  208. }
  209. DPF2(60, "CShingleInstance::Create: %08x DN: %08x", this, pDeviceNode);
  210. exit:
  211. return(Status);
  212. }
  213. NTSTATUS
  214. CShingleInstance::SetDeviceNode(
  215. IN PDEVICE_NODE pDeviceNode
  216. )
  217. {
  218. NTSTATUS Status = STATUS_SUCCESS;
  219. DisableDeviceInterface();
  220. this->pDeviceNode = pDeviceNode;
  221. Status = EnableDeviceInterface();
  222. if(!NT_SUCCESS(Status)) {
  223. goto exit;
  224. }
  225. DPF2(60, "CShingleInstance::SetDeviceNode: %08x DN: %08x",
  226. this,
  227. pDeviceNode);
  228. exit:
  229. return(Status);
  230. }
  231. NTSTATUS
  232. CShingleInstance::CreateCreateItem(
  233. IN PCWSTR pcwstrReference
  234. )
  235. {
  236. PKSOBJECT_CREATE_ITEM pCreateItem = NULL;
  237. NTSTATUS Status = STATUS_SUCCESS;
  238. pCreateItem = new KSOBJECT_CREATE_ITEM;
  239. if(pCreateItem == NULL) {
  240. Status = STATUS_INSUFFICIENT_RESOURCES;
  241. goto exit;
  242. }
  243. pCreateItem->Create = CFilterInstance::FilterDispatchCreate;
  244. pCreateItem->Context = this;
  245. RtlInitUnicodeString(&pCreateItem->ObjectClass, pcwstrReference);
  246. Status = KsAllocateObjectCreateItem(
  247. gpDeviceInstance->pDeviceHeader,
  248. pCreateItem,
  249. FALSE,
  250. NULL);
  251. if(!NT_SUCCESS(Status)) {
  252. pCreateItem->ObjectClass.Buffer = NULL;
  253. goto exit;
  254. }
  255. Status = lstCreateItem.AddList(pCreateItem);
  256. if(!NT_SUCCESS(Status)) {
  257. goto exit;
  258. }
  259. DPF3(60, "CSHI::CreateItem SHI %08x CI %08x %s",
  260. this,
  261. pCreateItem,
  262. DbgUnicode2Sz((PWSTR)pcwstrReference));
  263. exit:
  264. if(!NT_SUCCESS(Status)) {
  265. DestroyCreateItem(pCreateItem);
  266. }
  267. return(Status);
  268. }
  269. ENUMFUNC
  270. CShingleInstance::DestroyCreateItem(
  271. IN PKSOBJECT_CREATE_ITEM pCreateItem
  272. )
  273. {
  274. if(pCreateItem != NULL) {
  275. if(pCreateItem->ObjectClass.Buffer != NULL) {
  276. KsFreeObjectCreateItem(
  277. gpDeviceInstance->pDeviceHeader,
  278. &pCreateItem->ObjectClass);
  279. }
  280. delete pCreateItem;
  281. }
  282. return(STATUS_CONTINUE);
  283. }
  284. NTSTATUS
  285. CShingleInstance::CreateDeviceInterface(
  286. IN LPGUID pguidClass,
  287. IN PCWSTR pcwstrReference
  288. )
  289. {
  290. UNICODE_STRING ustrReference;
  291. NTSTATUS Status = STATUS_SUCCESS;
  292. ASSERT(gpDeviceInstance != NULL);
  293. ASSERT(gpDeviceInstance->pPhysicalDeviceObject != NULL);
  294. ASSERT(gpDeviceInstance->pDeviceHeader != NULL);
  295. ASSERT(this->ustrSymbolicLinkName.Buffer == NULL);
  296. RtlInitUnicodeString(&ustrReference, pcwstrReference);
  297. Status = IoRegisterDeviceInterface(
  298. gpDeviceInstance->pPhysicalDeviceObject,
  299. pguidClass,
  300. &ustrReference,
  301. &this->ustrSymbolicLinkName);
  302. if(!NT_SUCCESS(Status)) {
  303. goto exit;
  304. }
  305. Status = EnableDeviceInterface();
  306. if(!NT_SUCCESS(Status)) {
  307. goto exit;
  308. }
  309. DPF3(60, "CSHI::CreateDeviceInterface: %08x %s %s",
  310. this,
  311. DbgGuid2Sz(pguidClass),
  312. DbgUnicode2Sz(this->ustrSymbolicLinkName.Buffer));
  313. exit:
  314. return(Status);
  315. }
  316. NTSTATUS
  317. CShingleInstance::EnableDeviceInterface(
  318. )
  319. {
  320. NTSTATUS Status = STATUS_SUCCESS;
  321. PWSTR pwstrFriendlyName = L"";
  322. UNICODE_STRING ustrValueName;
  323. UNICODE_STRING ustrValue;
  324. HANDLE hkey = NULL;
  325. if(this->ustrSymbolicLinkName.Buffer == NULL) {
  326. ASSERT(NT_SUCCESS(Status));
  327. goto exit;
  328. }
  329. //
  330. // Put the proxy's CLSID in the new device interface
  331. //
  332. Status = IoOpenDeviceInterfaceRegistryKey(
  333. &this->ustrSymbolicLinkName,
  334. STANDARD_RIGHTS_ALL,
  335. &hkey);
  336. if(!NT_SUCCESS(Status)) {
  337. goto exit;
  338. }
  339. RtlInitUnicodeString(&ustrValueName, L"CLSID");
  340. RtlInitUnicodeString(&ustrValue, L"{17CCA71B-ECD7-11D0-B908-00A0C9223196}");
  341. Status = ZwSetValueKey(
  342. hkey,
  343. &ustrValueName,
  344. 0,
  345. REG_SZ,
  346. ustrValue.Buffer,
  347. ustrValue.Length);
  348. if(!NT_SUCCESS(Status)) {
  349. goto exit;
  350. }
  351. //
  352. // Set the friendly name into the new device interface
  353. //
  354. if(pDeviceNode != NULL) {
  355. Assert(pDeviceNode);
  356. if(pDeviceNode->GetFriendlyName() != NULL) {
  357. pwstrFriendlyName = pDeviceNode->GetFriendlyName();
  358. }
  359. else {
  360. DPF(5, "CSHI::EnableDeviceInterface no friendly name");
  361. }
  362. }
  363. RtlInitUnicodeString(&ustrValueName, L"FriendlyName");
  364. Status = ZwSetValueKey(
  365. hkey,
  366. &ustrValueName,
  367. 0,
  368. REG_SZ,
  369. pwstrFriendlyName,
  370. (wcslen(pwstrFriendlyName) * sizeof(WCHAR)) + sizeof(UNICODE_NULL));
  371. if(!NT_SUCCESS(Status)) {
  372. goto exit;
  373. }
  374. Status = IoSetDeviceInterfaceState(&this->ustrSymbolicLinkName, TRUE);
  375. if(!NT_SUCCESS(Status)) {
  376. goto exit;
  377. }
  378. DPF2(60, "CSHI::EnableDeviceInterface: %08x %s",
  379. this,
  380. DbgUnicode2Sz(this->ustrSymbolicLinkName.Buffer));
  381. exit:
  382. if(hkey != NULL) {
  383. ZwClose(hkey);
  384. }
  385. return(Status);
  386. }
  387. VOID
  388. CShingleInstance::DisableDeviceInterface(
  389. )
  390. {
  391. Assert(this);
  392. DPF1(60, "CSHI::DisableDeviceInterface %08x", this);
  393. if(this->ustrSymbolicLinkName.Buffer != NULL) {
  394. DPF1(60, "CSHI::DisableDeviceInterface %s",
  395. DbgUnicode2Sz(this->ustrSymbolicLinkName.Buffer));
  396. IoSetDeviceInterfaceState(&this->ustrSymbolicLinkName, FALSE);
  397. }
  398. }
  399. VOID
  400. CShingleInstance::DestroyDeviceInterface(
  401. )
  402. {
  403. DisableDeviceInterface();
  404. RtlFreeUnicodeString(&this->ustrSymbolicLinkName);
  405. this->ustrSymbolicLinkName.Buffer = NULL;
  406. }
  407. //---------------------------------------------------------------------------
  408. #ifdef DEBUG
  409. ENUMFUNC
  410. CShingleInstance::Dump()
  411. {
  412. PKSOBJECT_CREATE_ITEM pCreateItem;
  413. dprintf("SHI: %08x DN %08x ulFlags %08x\n", this, pDeviceNode, ulFlags);
  414. if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
  415. dprintf(" lstCreateItem:");
  416. FOR_EACH_LIST_ITEM(&lstCreateItem, pCreateItem) {
  417. dprintf(" %08x", pCreateItem);
  418. } END_EACH_LIST_ITEM
  419. dprintf("\n");
  420. dprintf(" %s\n", DbgUnicode2Sz(ustrSymbolicLinkName.Buffer));
  421. dprintf(" %s\n", DbgUnicode2Sz((PWSTR)pcwstrRegistryPath));
  422. dprintf(" %s\n", DbgUnicode2Sz((PWSTR)pcwstrRegistryValue));
  423. }
  424. return(STATUS_CONTINUE);
  425. }
  426. #endif