Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / drivers / ksfilter / ks / filterfactory.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/ksfilter/ks/filterfactory.c
5 * PURPOSE: KS IKsFilterFactory interface functions
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9
10 #include "priv.h"
11
12 typedef struct
13 {
14 KSBASIC_HEADER Header;
15 KSFILTERFACTORY FilterFactory;
16
17 LONG ref;
18 PKSIDEVICE_HEADER DeviceHeader;
19 PFNKSFILTERFACTORYPOWER SleepCallback;
20 PFNKSFILTERFACTORYPOWER WakeCallback;
21
22 LIST_ENTRY SymbolicLinkList;
23 KMUTEX ControlMutex;
24
25 }IKsFilterFactoryImpl;
26
27 VOID
28 NTAPI
29 IKsFilterFactory_ItemFreeCb(
30 IN PKSOBJECT_CREATE_ITEM CreateItem)
31 {
32 /* callback when create item is freed in the device header */
33 IKsFilterFactory * iface = (IKsFilterFactory*)CONTAINING_RECORD(CreateItem->Context, IKsFilterFactoryImpl, FilterFactory);
34
35 iface->lpVtbl->Release(iface);
36 }
37
38 NTSTATUS
39 NTAPI
40 IKsFilterFactory_Create(
41 IN PDEVICE_OBJECT DeviceObject,
42 IN PIRP Irp)
43 {
44 PKSOBJECT_CREATE_ITEM CreateItem;
45 IKsFilterFactoryImpl * Factory;
46 IKsFilterFactory * iface;
47 NTSTATUS Status;
48
49 /* access the create item */
50 CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
51 if (!CreateItem)
52 {
53 DPRINT1("IKsFilterFactory_Create no CreateItem\n");
54 return STATUS_UNSUCCESSFUL;
55 }
56
57 /* get filter factory interface */
58 Factory = (IKsFilterFactoryImpl*)CONTAINING_RECORD(CreateItem->Context, IKsFilterFactoryImpl, FilterFactory);
59
60 /* get interface */
61 iface = (IKsFilterFactory*)&Factory->Header.OuterUnknown;
62
63 /* create a filter instance */
64 Status = KspCreateFilter(DeviceObject, Irp, iface);
65
66 DPRINT("KspCreateFilter Status %x\n", Status);
67
68 if (Status != STATUS_PENDING)
69 {
70 Irp->IoStatus.Information = 0;
71 Irp->IoStatus.Status = Status;
72 CompleteRequest(Irp, IO_NO_INCREMENT);
73 }
74
75 return Status;
76 }
77
78
79 NTSTATUS
80 NTAPI
81 IKsFilterFactory_fnQueryInterface(
82 IKsFilterFactory * iface,
83 IN REFIID refiid,
84 OUT PVOID* Output)
85 {
86 NTSTATUS Status;
87
88 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
89
90 if (IsEqualGUIDAligned(refiid, &IID_IUnknown))
91 {
92 *Output = &This->Header.OuterUnknown;
93 _InterlockedIncrement(&This->ref);
94 return STATUS_SUCCESS;
95 }
96
97 if (This->Header.ClientAggregate)
98 {
99 /* using client aggregate */
100 Status = This->Header.ClientAggregate->lpVtbl->QueryInterface(This->Header.ClientAggregate, refiid, Output);
101
102 if (NT_SUCCESS(Status))
103 {
104 /* client aggregate supports interface */
105 return Status;
106 }
107 }
108
109 DPRINT("IKsFilterFactory_fnQueryInterface no interface\n");
110 return STATUS_NOT_SUPPORTED;
111 }
112
113 ULONG
114 NTAPI
115 IKsFilterFactory_fnAddRef(
116 IKsFilterFactory * iface)
117 {
118 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
119
120 return InterlockedIncrement(&This->ref);
121 }
122
123 ULONG
124 NTAPI
125 IKsFilterFactory_fnRelease(
126 IKsFilterFactory * iface)
127 {
128 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
129
130 InterlockedDecrement(&This->ref);
131
132 if (This->ref == 0)
133 {
134 if (!IsListEmpty(&This->SymbolicLinkList))
135 {
136 /* disable device interfaces */
137 KspSetDeviceInterfacesState(&This->SymbolicLinkList, FALSE);
138 /* free device interface strings */
139 KspFreeDeviceInterfaces(&This->SymbolicLinkList);
140 }
141
142 FreeItem(This);
143 return 0;
144 }
145 /* Return new reference count */
146 return This->ref;
147 }
148
149 KSFILTERFACTORY*
150 NTAPI
151 IKsFilterFactory_fnGetStruct(
152 IKsFilterFactory * iface)
153 {
154 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
155
156 return &This->FilterFactory;
157 }
158
159 NTSTATUS
160 NTAPI
161 IKsFilterFactory_fnSetDeviceClassesState(
162 IKsFilterFactory * iface,
163 IN BOOLEAN Enable)
164 {
165 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
166
167 return KspSetDeviceInterfacesState(&This->SymbolicLinkList, Enable);
168 }
169
170 VOID
171 IKsFilterFactory_AttachFilterFactoryToDeviceHeader(
172 IKsFilterFactoryImpl * This,
173 PKSIDEVICE_HEADER DeviceHeader)
174 {
175 PKSBASIC_HEADER BasicHeader;
176 PKSFILTERFACTORY FilterFactory;
177
178 if (DeviceHeader->BasicHeader.FirstChild.FilterFactory == NULL)
179 {
180 /* first attached filter factory */
181 DeviceHeader->BasicHeader.FirstChild.FilterFactory = &This->FilterFactory;
182 return;
183 }
184
185 /* set to first entry */
186 FilterFactory = DeviceHeader->BasicHeader.FirstChild.FilterFactory;
187
188 do
189 {
190 /* get basic header */
191 BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)FilterFactory - sizeof(KSBASIC_HEADER));
192 /* sanity check */
193 ASSERT(BasicHeader->Type == KsObjectTypeFilterFactory);
194
195 if (BasicHeader->Next.FilterFactory)
196 {
197 /* iterate to next filter factory */
198 FilterFactory = BasicHeader->Next.FilterFactory;
199 }
200 else
201 {
202 /* found last entry */
203 break;
204 }
205 }while(FilterFactory);
206
207 /* attach filter factory */
208 BasicHeader->Next.FilterFactory = &This->FilterFactory;
209 }
210
211 NTSTATUS
212 NTAPI
213 IKsFilterFactory_fnInitialize(
214 IKsFilterFactory * iface,
215 IN PDEVICE_OBJECT DeviceObject,
216 IN const KSFILTER_DESCRIPTOR *Descriptor,
217 IN PWSTR RefString OPTIONAL,
218 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
219 IN ULONG CreateItemFlags,
220 IN PFNKSFILTERFACTORYPOWER SleepCallback OPTIONAL,
221 IN PFNKSFILTERFACTORYPOWER WakeCallback OPTIONAL,
222 OUT PKSFILTERFACTORY *FilterFactory OPTIONAL)
223 {
224 UNICODE_STRING ReferenceString;
225 NTSTATUS Status;
226 PDEVICE_EXTENSION DeviceExtension;
227 KSOBJECT_CREATE_ITEM CreateItem;
228 BOOL FreeString = FALSE;
229 IKsDevice * KsDevice;
230
231 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
232
233 /* get device extension */
234 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
235
236 /* initialize filterfactory */
237 This->SleepCallback = SleepCallback;
238 This->WakeCallback = WakeCallback;
239 This->FilterFactory.FilterDescriptor = Descriptor;
240 This->Header.KsDevice = &DeviceExtension->DeviceHeader->KsDevice;
241 This->Header.Type = KsObjectTypeFilterFactory;
242 This->Header.Parent.KsDevice = &DeviceExtension->DeviceHeader->KsDevice;
243 This->DeviceHeader = DeviceExtension->DeviceHeader;
244
245 /* initialize filter factory control mutex */
246 This->Header.ControlMutex = &This->ControlMutex;
247 KeInitializeMutex(This->Header.ControlMutex, 0);
248
249 /* unused fields */
250 InitializeListHead(&This->Header.EventList);
251 KeInitializeSpinLock(&This->Header.EventListLock);
252
253 InitializeListHead(&This->SymbolicLinkList);
254
255 /* does the device use a reference string */
256 if (RefString || !Descriptor->ReferenceGuid)
257 {
258 /* use device reference string */
259 RtlInitUnicodeString(&ReferenceString, RefString);
260 }
261 else
262 {
263 /* create reference string from descriptor guid */
264 Status = RtlStringFromGUID(Descriptor->ReferenceGuid, &ReferenceString);
265
266 /* check for success */
267 if (!NT_SUCCESS(Status))
268 {
269 /* omg, we failed */
270 return Status;
271 }
272
273 FreeString = TRUE;
274 }
275
276 DPRINT("IKsFilterFactory_fnInitialize CategoriesCount %u ReferenceString '%S'\n", Descriptor->CategoriesCount,ReferenceString.Buffer);
277
278 /* now register the device interface */
279 Status = KspRegisterDeviceInterfaces(DeviceExtension->DeviceHeader->KsDevice.PhysicalDeviceObject,
280 Descriptor->CategoriesCount,
281 Descriptor->Categories,
282 &ReferenceString,
283 &This->SymbolicLinkList);
284 /* check for success */
285 if (!NT_SUCCESS(Status))
286 {
287 DPRINT1("KspRegisterDeviceInterfaces failed with %x\n", Status);
288
289 if (FreeString)
290 {
291 /* free unicode string */
292 RtlFreeUnicodeString(&ReferenceString);
293 }
294
295 return Status;
296 }
297
298 /* now setup the create item */
299 CreateItem.SecurityDescriptor = SecurityDescriptor;
300 CreateItem.Flags = CreateItemFlags;
301 CreateItem.Create = IKsFilterFactory_Create;
302 CreateItem.Context = (PVOID)&This->FilterFactory;
303 RtlInitUnicodeString(&CreateItem.ObjectClass, ReferenceString.Buffer);
304
305 /* insert create item to device header */
306 Status = KsAllocateObjectCreateItem((KSDEVICE_HEADER)DeviceExtension->DeviceHeader, &CreateItem, TRUE, IKsFilterFactory_ItemFreeCb);
307
308 if (FreeString)
309 {
310 /* free unicode string */
311 RtlFreeUnicodeString(&ReferenceString);
312 }
313
314 if (FilterFactory)
315 {
316 /* return filterfactory */
317 *FilterFactory = &This->FilterFactory;
318
319 /* create a object bag for the filter factory */
320 This->FilterFactory.Bag = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_BAG));
321 if (This->FilterFactory.Bag)
322 {
323 /* initialize object bag */
324 KsDevice = (IKsDevice*)&DeviceExtension->DeviceHeader->BasicHeader.OuterUnknown;
325 KsDevice->lpVtbl->InitializeObjectBag(KsDevice, (PKSIOBJECT_BAG)This->FilterFactory.Bag, NULL);
326 }
327 }
328
329 /* attach filterfactory to device header */
330 IKsFilterFactory_AttachFilterFactoryToDeviceHeader(This, DeviceExtension->DeviceHeader);
331
332 /* return result */
333 return Status;
334 }
335
336 static IKsFilterFactoryVtbl vt_IKsFilterFactoryVtbl =
337 {
338 IKsFilterFactory_fnQueryInterface,
339 IKsFilterFactory_fnAddRef,
340 IKsFilterFactory_fnRelease,
341 IKsFilterFactory_fnGetStruct,
342 IKsFilterFactory_fnSetDeviceClassesState,
343 IKsFilterFactory_fnInitialize
344 };
345
346
347 NTSTATUS
348 NTAPI
349 KspCreateFilterFactory(
350 IN PDEVICE_OBJECT DeviceObject,
351 IN const KSFILTER_DESCRIPTOR *Descriptor,
352 IN PWSTR RefString OPTIONAL,
353 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
354 IN ULONG CreateItemFlags,
355 IN PFNKSFILTERFACTORYPOWER SleepCallback OPTIONAL,
356 IN PFNKSFILTERFACTORYPOWER WakeCallback OPTIONAL,
357 OUT PKSFILTERFACTORY *FilterFactory OPTIONAL)
358 {
359 IKsFilterFactoryImpl * This;
360 IKsFilterFactory * Filter;
361 NTSTATUS Status;
362
363 DPRINT("KsCreateFilterFactory\n");
364
365 /* Lets allocate a filterfactory */
366 This = AllocateItem(NonPagedPool, sizeof(IKsFilterFactoryImpl));
367 if (!This)
368 {
369 /* not enough memory */
370 return STATUS_INSUFFICIENT_RESOURCES;
371 }
372
373 /* initialize struct */
374 This->ref = 1;
375 This->Header.OuterUnknown = (PUNKNOWN)&vt_IKsFilterFactoryVtbl;
376
377 /* map to com object */
378 Filter = (IKsFilterFactory*)&This->Header.OuterUnknown;
379
380 /* initialize filter */
381 Status = Filter->lpVtbl->Initialize(Filter, DeviceObject, Descriptor, RefString, SecurityDescriptor, CreateItemFlags, SleepCallback, WakeCallback, FilterFactory);
382 /* did we succeed */
383 if (!NT_SUCCESS(Status))
384 {
385 /* destroy filterfactory */
386 Filter->lpVtbl->Release(Filter);
387 }
388
389 /* return result */
390 DPRINT("KsCreateFilterFactory %x\n", Status);
391 /* sanity check */
392 ASSERT(Status == STATUS_SUCCESS);
393
394 return Status;
395 }
396
397 /*
398 @implemented
399 */
400 KSDDKAPI
401 NTSTATUS
402 NTAPI
403 KsCreateFilterFactory(
404 IN PDEVICE_OBJECT DeviceObject,
405 IN const KSFILTER_DESCRIPTOR *Descriptor,
406 IN PWSTR RefString OPTIONAL,
407 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
408 IN ULONG CreateItemFlags,
409 IN PFNKSFILTERFACTORYPOWER SleepCallback OPTIONAL,
410 IN PFNKSFILTERFACTORYPOWER WakeCallback OPTIONAL,
411 OUT PKSFILTERFACTORY *FilterFactory OPTIONAL)
412 {
413 return KspCreateFilterFactory(DeviceObject, Descriptor, RefString, SecurityDescriptor, CreateItemFlags, SleepCallback, WakeCallback, FilterFactory);
414
415 }
416
417 /*
418 @implemented
419 */
420 KSDDKAPI
421 NTSTATUS
422 NTAPI
423 KsFilterFactorySetDeviceClassesState(
424 IN PKSFILTERFACTORY FilterFactory,
425 IN BOOLEAN NewState)
426 {
427 IKsFilterFactory * Factory;
428 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
429
430 Factory = (IKsFilterFactory*)&This->Header.OuterUnknown;
431 return Factory->lpVtbl->SetDeviceClassesState(Factory, NewState);
432 }
433
434
435 /*
436 @implemented
437 */
438 KSDDKAPI
439 PUNICODE_STRING
440 NTAPI
441 KsFilterFactoryGetSymbolicLink(
442 IN PKSFILTERFACTORY FilterFactory)
443 {
444 PSYMBOLIC_LINK_ENTRY LinkEntry;
445 IKsFilterFactoryImpl * Factory = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
446
447 if (IsListEmpty(&Factory->SymbolicLinkList))
448 {
449 /* device has not registered any interfaces */
450 return NULL;
451 }
452
453 /* get first entry */
454 LinkEntry = (PSYMBOLIC_LINK_ENTRY)CONTAINING_RECORD(Factory->SymbolicLinkList.Flink, SYMBOLIC_LINK_ENTRY, Entry);
455
456 /* return first link */
457 return &LinkEntry->SymbolicLink;
458 }
459
460 /*
461 @implemented
462 */
463 KSDDKAPI
464 NTSTATUS
465 NTAPI
466 KsFilterFactoryAddCreateItem(
467 IN PKSFILTERFACTORY FilterFactory,
468 IN PWSTR RefString,
469 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
470 IN ULONG CreateItemFlags)
471 {
472 KSOBJECT_CREATE_ITEM CreateItem;
473
474 IKsFilterFactoryImpl * Factory = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
475
476 /* initialize create item */
477 CreateItem.Context = (PVOID)&Factory->FilterFactory;
478 CreateItem.Create = IKsFilterFactory_Create;
479 CreateItem.Flags = CreateItemFlags;
480 CreateItem.SecurityDescriptor = SecurityDescriptor;
481 RtlInitUnicodeString(&CreateItem.ObjectClass, RefString);
482
483 /* insert create item to device header */
484 return KsAllocateObjectCreateItem((KSDEVICE_HEADER)Factory->DeviceHeader, &CreateItem, TRUE, IKsFilterFactory_ItemFreeCb);
485 }
486
487 ULONG
488 KspCacheAddData(
489 PKSPCACHE_DESCRIPTOR Descriptor,
490 LPCVOID Data,
491 ULONG Length)
492 {
493 ULONG Index;
494
495 for(Index = 0; Index < Descriptor->DataOffset; Index++)
496 {
497 if (RtlCompareMemory(Descriptor->DataCache, Data, Length) == Length)
498 {
499 if (Index + Length > Descriptor->DataOffset)
500 {
501 /* adjust used space */
502 Descriptor->DataOffset = Index + Length;
503 /* return absolute offset */
504 return Descriptor->DataLength + Index;
505 }
506 }
507 }
508
509 /* sanity check */
510 ASSERT(Descriptor->DataOffset + Length < Descriptor->DataLength);
511
512 /* copy to data blob */
513 RtlMoveMemory((Descriptor->DataCache + Descriptor->DataOffset), Data, Length);
514
515 /* backup offset */
516 Index = Descriptor->DataOffset;
517
518 /* adjust used space */
519 Descriptor->DataOffset += Length;
520
521 /* return absolute offset */
522 return Descriptor->DataLength + Index;
523 }
524
525 /*
526 @implemented
527 */
528 KSDDKAPI
529 NTSTATUS
530 NTAPI
531 KsFilterFactoryUpdateCacheData(
532 IN PKSFILTERFACTORY FilterFactory,
533 IN const KSFILTER_DESCRIPTOR* FilterDescriptor OPTIONAL)
534 {
535 KSPCACHE_DESCRIPTOR Descriptor;
536 PKSPCACHE_FILTER_HEADER FilterHeader;
537 UNICODE_STRING FilterData = RTL_CONSTANT_STRING(L"FilterData");
538 PKSPCACHE_PIN_HEADER PinHeader;
539 ULONG Index, SubIndex;
540 PLIST_ENTRY Entry;
541 PSYMBOLIC_LINK_ENTRY SymEntry;
542 BOOLEAN Found;
543 HKEY hKey;
544 NTSTATUS Status = STATUS_SUCCESS;
545
546 IKsFilterFactoryImpl * Factory = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
547
548 DPRINT("KsFilterFactoryUpdateCacheData %p\n", FilterDescriptor);
549
550 if (!FilterDescriptor)
551 FilterDescriptor = Factory->FilterFactory.FilterDescriptor;
552
553 ASSERT(FilterDescriptor);
554
555 /* initialize cache descriptor */
556 RtlZeroMemory(&Descriptor, sizeof(KSPCACHE_DESCRIPTOR));
557
558 /* calculate filter data size */
559 Descriptor.FilterLength = sizeof(KSPCACHE_FILTER_HEADER);
560
561 /* FIXME support variable size pin descriptors */
562 ASSERT(FilterDescriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
563
564 for(Index = 0; Index < FilterDescriptor->PinDescriptorsCount; Index++)
565 {
566 /* add filter descriptor */
567 Descriptor.FilterLength += sizeof(KSPCACHE_PIN_HEADER);
568
569 if (FilterDescriptor->PinDescriptors[Index].PinDescriptor.Category)
570 {
571 /* add extra ULONG for offset to category */
572 Descriptor.FilterLength += sizeof(ULONG);
573
574 /* add size for clsid */
575 Descriptor.DataLength += sizeof(CLSID);
576 }
577
578 /* add space for formats */
579 Descriptor.FilterLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount * sizeof(KSPCACHE_DATARANGE);
580
581 /* add space for MajorFormat / MinorFormat */
582 Descriptor.DataLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount * sizeof(CLSID) * 2;
583
584 /* add space for mediums */
585 Descriptor.FilterLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount * sizeof(ULONG);
586
587 /* add space for the data */
588 Descriptor.DataLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount * sizeof(KSPCACHE_MEDIUM);
589 }
590
591 /* now allocate the space */
592 Descriptor.FilterData = (PUCHAR)AllocateItem(NonPagedPool, Descriptor.DataLength + Descriptor.FilterLength);
593 if (!Descriptor.FilterData)
594 {
595 /* no memory */
596 return STATUS_INSUFFICIENT_RESOURCES;
597 }
598
599 /* initialize data cache */
600 Descriptor.DataCache = (PUCHAR)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterLength);
601
602 /* setup filter header */
603 FilterHeader = (PKSPCACHE_FILTER_HEADER)Descriptor.FilterData;
604
605 FilterHeader->dwVersion = 2;
606 FilterHeader->dwMerit = MERIT_DO_NOT_USE;
607 FilterHeader->dwUnused = 0;
608 FilterHeader->dwPins = FilterDescriptor->PinDescriptorsCount;
609
610 Descriptor.FilterOffset = sizeof(KSPCACHE_FILTER_HEADER);
611
612 /* write pin headers */
613 for(Index = 0; Index < FilterDescriptor->PinDescriptorsCount; Index++)
614 {
615 /* get offset to pin */
616 PinHeader = (PKSPCACHE_PIN_HEADER)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterOffset);
617
618 /* write pin header */
619 PinHeader->Signature = 0x33697030 + Index;
620 PinHeader->Flags = 0;
621 PinHeader->Instances = FilterDescriptor->PinDescriptors[Index].InstancesPossible;
622 if (PinHeader->Instances > 1)
623 PinHeader->Flags |= REG_PINFLAG_B_MANY;
624
625
626 PinHeader->MediaTypes = FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount;
627 PinHeader->Mediums = FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount;
628 PinHeader->Category = (FilterDescriptor->PinDescriptors[Index].PinDescriptor.Category ? TRUE : FALSE);
629
630 Descriptor.FilterOffset += sizeof(KSPCACHE_PIN_HEADER);
631
632 if (PinHeader->Category)
633 {
634 /* get category offset */
635 PULONG Category = (PULONG)(PinHeader + 1);
636
637 /* write category offset */
638 *Category = KspCacheAddData(&Descriptor, FilterDescriptor->PinDescriptors[Index].PinDescriptor.Category, sizeof(CLSID));
639
640 /* adjust offset */
641 Descriptor.FilterOffset += sizeof(ULONG);
642 }
643
644 /* add dataranges */
645 for(SubIndex = 0; SubIndex < FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount; SubIndex++)
646 {
647 /* get datarange offset */
648 PKSPCACHE_DATARANGE DataRange = (PKSPCACHE_DATARANGE)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterOffset);
649
650 /* initialize data range */
651 DataRange->Signature = 0x33797430 + SubIndex;
652 DataRange->dwUnused = 0;
653 DataRange->OffsetMajor = KspCacheAddData(&Descriptor, &FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRanges[SubIndex]->MajorFormat, sizeof(CLSID));
654 DataRange->OffsetMinor = KspCacheAddData(&Descriptor, &FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRanges[SubIndex]->SubFormat, sizeof(CLSID));
655
656 /* adjust offset */
657 Descriptor.FilterOffset += sizeof(KSPCACHE_DATARANGE);
658 }
659
660 /* add mediums */
661 for(SubIndex = 0; SubIndex < FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount; SubIndex++)
662 {
663 KSPCACHE_MEDIUM Medium;
664 PULONG MediumOffset;
665
666 /* get pin medium offset */
667 MediumOffset = (PULONG)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterOffset);
668
669 /* copy medium guid */
670 RtlMoveMemory(&Medium.Medium, &FilterDescriptor->PinDescriptors[Index].PinDescriptor.Mediums[SubIndex].Set, sizeof(GUID));
671 Medium.dw1 = FilterDescriptor->PinDescriptors[Index].PinDescriptor.Mediums[SubIndex].Id; /* FIXME verify */
672 Medium.dw2 = 0;
673
674 *MediumOffset = KspCacheAddData(&Descriptor, &Medium, sizeof(KSPCACHE_MEDIUM));
675
676 /* adjust offset */
677 Descriptor.FilterOffset += sizeof(ULONG);
678 }
679 }
680
681 /* sanity checks */
682 ASSERT(Descriptor.FilterOffset == Descriptor.FilterLength);
683 ASSERT(Descriptor.DataOffset <= Descriptor.DataLength);
684
685
686 /* now go through all entries and update 'FilterData' key */
687 for(Index = 0; Index < FilterDescriptor->CategoriesCount; Index++)
688 {
689 /* get first entry */
690 Entry = Factory->SymbolicLinkList.Flink;
691
692 /* set status to not found */
693 Found = FALSE;
694 /* loop list until the the current category is found */
695 while(Entry != &Factory->SymbolicLinkList)
696 {
697 /* fetch symbolic link entry */
698 SymEntry = (PSYMBOLIC_LINK_ENTRY)CONTAINING_RECORD(Entry, SYMBOLIC_LINK_ENTRY, Entry);
699
700 if (IsEqualGUIDAligned(&SymEntry->DeviceInterfaceClass, &FilterDescriptor->Categories[Index]))
701 {
702 /* found category */
703 Found = TRUE;
704 break;
705 }
706
707 /* move to next entry */
708 Entry = Entry->Flink;
709 }
710
711 if (!Found)
712 {
713 /* filter category is not present */
714 Status = STATUS_INVALID_PARAMETER;
715 break;
716 }
717
718 /* now open device interface */
719 Status = IoOpenDeviceInterfaceRegistryKey(&SymEntry->SymbolicLink, KEY_WRITE, &hKey);
720 if (!NT_SUCCESS(Status))
721 {
722 /* failed to open interface key */
723 break;
724 }
725
726 /* update filterdata key */
727 Status = ZwSetValueKey(hKey, &FilterData, 0, REG_BINARY, Descriptor.FilterData, Descriptor.FilterLength + Descriptor.DataOffset);
728
729 /* close filterdata key */
730 ZwClose(hKey);
731
732 if (!NT_SUCCESS(Status))
733 {
734 /* failed to set key value */
735 break;
736 }
737 }
738 /* free filter data */
739 FreeItem(Descriptor.FilterData);
740
741 /* done */
742 return Status;
743 }
744