[KS]
[reactos.git] / reactos / drivers / ksfilter / ks / api.c
index 0626e62..2067de5 100644 (file)
@@ -94,6 +94,8 @@ KsReleaseDeviceSecurityLock(
 {
     PKSIDEVICE_HEADER Header = (PKSIDEVICE_HEADER)DevHeader;
 
+    DPRINT("KsReleaseDevice\n");
+
     ExReleaseResourceLite(&Header->SecurityLock);
     KeLeaveCriticalRegion();
 }
@@ -494,8 +496,8 @@ KspFreeCreateItems(
         Entry = (PCREATE_ITEM_ENTRY)CONTAINING_RECORD(RemoveHeadList(ListHead), CREATE_ITEM_ENTRY, Entry);
 
         /* caller shouldnt have any references */
-        ASSERT(Entry->ReferenceCount == 0);
-        ASSERT(IsListEmpty(&Entry->ObjectItemList));
+        //ASSERT(Entry->ReferenceCount == 0);
+        //ASSERT(IsListEmpty(&Entry->ObjectItemList));
 
         /* does the creator wish notification */
         if (Entry->ItemFreeCallback)
@@ -687,8 +689,7 @@ KsAllocateObjectHeader(
         }
     }
     /* store the object in the file object */
-    ASSERT(IoStack->FileObject->FsContext == NULL);
-    IoStack->FileObject->FsContext = ObjectHeader;
+    IoStack->FileObject->FsContext2 = ObjectHeader;
 
     /* store parent device */
     ObjectHeader->ParentDeviceObject = IoGetRelatedDeviceObject(IoStack->FileObject);
@@ -720,6 +721,8 @@ KsFreeObjectHeader(
 {
     PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER) Header;
 
+    DPRINT("KsFreeObjectHeader Header %p Class %wZ\n", Header, &ObjectHeader->ObjectClass);
+
     if (ObjectHeader->ObjectClass.Buffer)
     {
         /* release object class buffer */
@@ -803,7 +806,7 @@ KsAddObjectCreateItemToDeviceHeader(
 
     Header = (PKSIDEVICE_HEADER)DevHeader;
 
-    DPRINT1("KsAddObjectCreateItemToDeviceHeader entered\n");
+    DPRINT("KsAddObjectCreateItemToDeviceHeader entered\n");
 
      /* check if a device header has been provided */
     if (!DevHeader)
@@ -825,7 +828,7 @@ KsAddObjectCreateItemToDeviceHeader(
         /* increment create item count */
         InterlockedIncrement(&Header->ItemListCount);
     }
-
+    DPRINT("KsAddObjectCreateItemToDeviceHeader Status %x\n", Status);
     return Status;
 }
 
@@ -847,7 +850,7 @@ KsAddObjectCreateItemToObjectHeader(
 
     Header = (PKSIOBJECT_HEADER)ObjectHeader;
 
-    DPRINT1("KsAddObjectCreateItemToDeviceHeader entered\n");
+    DPRINT("KsAddObjectCreateItemToDeviceHeader entered\n");
 
      /* check if a device header has been provided */
     if (!Header)
@@ -898,7 +901,7 @@ KsAllocateObjectCreateItem(
         return STATUS_INVALID_PARAMETER_2;
 
     /* first allocate a create entry */
-    CreateEntry = AllocateItem(NonPagedPool, sizeof(PCREATE_ITEM_ENTRY));
+    CreateEntry = AllocateItem(NonPagedPool, sizeof(CREATE_ITEM_ENTRY));
 
     /* check for allocation success */
     if (!CreateEntry)
@@ -1121,7 +1124,7 @@ KsSynchronousIoControlDevice(
 
 
     /* get object header */
-    ObjectHeader = (PKSIOBJECT_HEADER)FileObject->FsContext;
+    ObjectHeader = (PKSIOBJECT_HEADER)FileObject->FsContext2;
 
     /* check if there is fast device io function */
     if (ObjectHeader && ObjectHeader->DispatchTable.FastDeviceIoControl)
@@ -1129,7 +1132,7 @@ KsSynchronousIoControlDevice(
         IoStatusBlock.Status = STATUS_UNSUCCESSFUL;
         IoStatusBlock.Information = 0;
 
-        /* it is send the request */
+        /* send the request */
         Status = ObjectHeader->DispatchTable.FastDeviceIoControl(FileObject, TRUE, InBuffer, InSize, OutBuffer, OutSize, IoControl, &IoStatusBlock, DeviceObject);
         /* check if the request was handled */
         //DPRINT("Handled %u Status %x Length %u\n", Status, IoStatusBlock.Status, IoStatusBlock.Information);
@@ -1148,10 +1151,26 @@ KsSynchronousIoControlDevice(
     /* create the irp */
     Irp =  IoBuildDeviceIoControlRequest(IoControl, DeviceObject, InBuffer, InSize, OutBuffer, OutSize, FALSE, &Event, &IoStatusBlock);
 
-    /* HACK */
+    if (!Irp)
+    {
+        /* no memory to allocate the irp */
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+
+    /* Store Fileobject */
     IoStack = IoGetNextIrpStackLocation(Irp);
     IoStack->FileObject = FileObject;
 
+    if (IoControl == IOCTL_KS_WRITE_STREAM)
+    {
+        Irp->AssociatedIrp.SystemBuffer = OutBuffer;
+    }
+    else if (IoControl == IOCTL_KS_READ_STREAM)
+    {
+        Irp->AssociatedIrp.SystemBuffer = InBuffer;
+    }
+
     IoSetCompletionRoutine(Irp, KspSynchronousIoControlDeviceCompletion, (PVOID)&IoStatusBlock, TRUE, TRUE, TRUE);
 
     Status = IoCallDriver(DeviceObject, Irp);
@@ -1360,7 +1379,7 @@ KopDispatchCreate(
     DriverObjectExtension = (PKO_DRIVER_EXTENSION)IoGetDriverObjectExtension(DeviceObject->DriverObject, (PVOID)KoDriverInitialize);
     if (!DriverObjectExtension)
     {
-        DPRINT1("FileObject not attached!\n");
+        DPRINT1("No DriverObjectExtension!\n");
         Status = STATUS_UNSUCCESSFUL;
         goto cleanup;
     }
@@ -1572,7 +1591,7 @@ KsAcquireControl(
     /* sanity check */
     ASSERT(BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
 
-    KeWaitForSingleObject(&BasicHeader->ControlMutex, Executive, KernelMode, FALSE, NULL);
+    KeWaitForSingleObject(BasicHeader->ControlMutex, Executive, KernelMode, FALSE, NULL);
 
 }
 
@@ -1589,7 +1608,7 @@ KsReleaseControl(
     /* sanity check */
     ASSERT(BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
 
-    KeReleaseMutex(&BasicHeader->ControlMutex, FALSE);
+    KeReleaseMutex(BasicHeader->ControlMutex, FALSE);
 }
 
 
@@ -1604,10 +1623,13 @@ KsAcquireDevice(
     IN PKSDEVICE Device)
 {
     IKsDevice *KsDevice;
-    PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
+    PKSIDEVICE_HEADER DeviceHeader;
+
+    DPRINT("KsAcquireDevice\n");
+    DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
 
     /* get device interface*/
-    KsDevice = (IKsDevice*)&DeviceHeader->lpVtblIKsDevice;
+    KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
 
     /* acquire device mutex */
     KsDevice->lpVtbl->AcquireDevice(KsDevice);
@@ -1625,7 +1647,7 @@ KsReleaseDevice(
     PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
 
     /* get device interface*/
-    KsDevice = (IKsDevice*)&DeviceHeader->lpVtblIKsDevice;
+    KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
 
     /* release device mutex */
     KsDevice->lpVtbl->ReleaseDevice(KsDevice);
@@ -1648,7 +1670,7 @@ KsTerminateDevice(
     DeviceHeader = DeviceExtension->DeviceHeader;
 
     /* get device interface*/
-    KsDevice = (IKsDevice*)&DeviceHeader->lpVtblIKsDevice;
+    KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
 
     /* now free device header */
     KsFreeDeviceHeader((KSDEVICE_HEADER)DeviceHeader);
@@ -1702,7 +1724,7 @@ KsCompletePendingRequest(
 }
 
 /*
-    @unimplemented
+    @implemented
 */
 KSDDKAPI
 NTSTATUS
@@ -1715,8 +1737,118 @@ KsCreateBusEnumObject(
     IN REFGUID InterfaceGuid OPTIONAL,
     IN PWCHAR ServiceRelativePath OPTIONAL)
 {
-    UNIMPLEMENTED
-    return STATUS_UNSUCCESSFUL;
+    ULONG Length;
+    NTSTATUS Status = STATUS_SUCCESS;
+    UNICODE_STRING ServiceKeyPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\");
+    PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
+    PDEVICE_EXTENSION DeviceExtension;
+
+    /* calculate sizeof bus enum device extension */
+    Length = wcslen(BusIdentifier) * sizeof(WCHAR);
+    Length += sizeof(BUS_ENUM_DEVICE_EXTENSION);
+
+    BusDeviceExtension = ExAllocatePool(NonPagedPool, Length);
+    if (!BusDeviceExtension)
+    {
+        /* not enough memory */
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* zero device extension */
+    RtlZeroMemory(BusDeviceExtension, sizeof(BUS_ENUM_DEVICE_EXTENSION));
+
+    /* initialize bus device extension */
+    wcscpy(BusDeviceExtension->BusIdentifier, BusIdentifier);
+
+    /* allocate service path string */
+    Length = ServiceKeyPath.MaximumLength;
+    Length += BusDeviceObject->DriverObject->DriverExtension->ServiceKeyName.MaximumLength;
+
+    if (ServiceRelativePath)
+    {
+        /* relative path for devices */
+        Length += wcslen(ServiceRelativePath) + 2 * sizeof(WCHAR);
+    }
+
+    BusDeviceExtension->ServicePath.Length = 0;
+    BusDeviceExtension->ServicePath.MaximumLength = Length;
+    BusDeviceExtension->ServicePath.Buffer = ExAllocatePool(NonPagedPool, Length);
+
+    if (!BusDeviceExtension->ServicePath.Buffer)
+    {
+        /* not enough memory */
+        ExFreePool(BusDeviceExtension);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlAppendUnicodeStringToString(&BusDeviceExtension->ServicePath, &ServiceKeyPath);
+    RtlAppendUnicodeStringToString(&BusDeviceExtension->ServicePath, &BusDeviceObject->DriverObject->DriverExtension->ServiceKeyName);
+
+    if (ServiceRelativePath)
+    {
+        RtlAppendUnicodeToString(&BusDeviceExtension->ServicePath, L"\\");
+        RtlAppendUnicodeToString(&BusDeviceExtension->ServicePath, ServiceRelativePath);
+    }
+
+    if (InterfaceGuid)
+    {
+        /* register an device interface */
+        Status = IoRegisterDeviceInterface(PhysicalDeviceObject, InterfaceGuid, NULL, &BusDeviceExtension->SymbolicLinkName);
+
+        /* check for success */
+        if (!NT_SUCCESS(Status))
+        {
+            ExFreePool(BusDeviceExtension->ServicePath.Buffer);
+            ExFreePool(BusDeviceExtension);
+            return Status;
+        }
+
+        /* now enable device interface */
+        Status = IoSetDeviceInterfaceState(&BusDeviceExtension->SymbolicLinkName, TRUE);
+
+        if (!NT_SUCCESS(Status))
+        {
+            ExFreePool(BusDeviceExtension->ServicePath.Buffer);
+            ExFreePool(BusDeviceExtension);
+            return Status;
+        }
+
+        /* set state enabled */
+        BusDeviceExtension->Enabled = TRUE;
+    }
+
+    /* store device objects */
+    BusDeviceExtension->BusDeviceObject = BusDeviceObject;
+    BusDeviceExtension->PnpDeviceObject = PnpDeviceObject;
+    BusDeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
+
+    if (!PnpDeviceObject)
+    {
+        BusDeviceExtension->PnpDeviceObject = IoAttachDeviceToDeviceStack(BusDeviceObject, PhysicalDeviceObject);
+
+        if (!BusDeviceExtension->PnpDeviceObject)
+        {
+            /* failed to attach device */
+            if (BusDeviceExtension->Enabled)
+            {
+                IoSetDeviceInterfaceState(&BusDeviceExtension->SymbolicLinkName, FALSE);
+                RtlFreeUnicodeString(&BusDeviceExtension->SymbolicLinkName);
+            }
+
+            /* free device extension */
+            ExFreePool(BusDeviceExtension->ServicePath.Buffer);
+            ExFreePool(BusDeviceExtension);
+
+            return STATUS_DEVICE_REMOVED;
+        }
+    }
+
+    /* attach device extension */
+    DeviceExtension = (PDEVICE_EXTENSION)BusDeviceObject->DeviceExtension;
+    DeviceExtension->DeviceHeader = (PKSIDEVICE_HEADER)BusDeviceExtension;
+
+    /* FIXME scan bus and invalidate device relations */
+    return Status;
 }
 
  NTSTATUS
@@ -1828,7 +1960,7 @@ KsDeviceGetBusData(
 }
 
 /*
-    @unimplemented
+    @implemented
 */
 KSDDKAPI
 void
@@ -1839,7 +1971,12 @@ KsDeviceRegisterAdapterObject(
     IN ULONG MaxMappingsByteCount,
     IN ULONG MappingTableStride)
 {
-    UNIMPLEMENTED
+    PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
+
+    DeviceHeader->AdapterObject = AdapterObject;
+    DeviceHeader->MaxMappingsByteCount = MaxMappingsByteCount;
+    DeviceHeader->MappingTableStride = MappingTableStride;
+
 }
 
 /*
@@ -1852,6 +1989,7 @@ KsGetBusEnumIdentifier(
     IN PIRP Irp)
 {
     UNIMPLEMENTED
+
     return STATUS_UNSUCCESSFUL;
 }
 
@@ -1884,7 +2022,7 @@ KsGetBusEnumPnpDeviceObject(
 }
 
 /*
-    @unimplemented
+    @implemented
 */
 KSDDKAPI
 PVOID
@@ -1892,12 +2030,19 @@ NTAPI
 KsGetFirstChild(
     IN PVOID Object)
 {
-    UNIMPLEMENTED
-    return NULL;
+    PKSBASIC_HEADER BasicHeader;
+
+    /* get the basic header */
+    BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
+
+    /* type has to be either a device or a filter factory */
+    ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory);
+
+    return (PVOID)BasicHeader->FirstChild.Filter;
 }
 
 /*
-    @unimplemented
+    @implemented
 */
 KSDDKAPI
 PVOID
@@ -1905,8 +2050,15 @@ NTAPI
 KsGetNextSibling(
     IN PVOID Object)
 {
-    UNIMPLEMENTED
-    return NULL;
+    PKSBASIC_HEADER BasicHeader;
+
+    /* get the basic header */
+    BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
+
+    ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory || 
+           BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
+
+    return (PVOID)BasicHeader->Next.Pin;
 }
 
 /*
@@ -1950,8 +2102,15 @@ KspCountMethodSets(
     if (!AutomationTableB)
         return AutomationTableA->MethodSetsCount;
 
-    /* sanity check */
-    ASSERT(AutomationTableA->MethodItemSize  == AutomationTableB->MethodItemSize);
+
+    DPRINT("AutomationTableA MethodItemSize %lu MethodSetsCount %lu\n", AutomationTableA->MethodItemSize, AutomationTableA->MethodSetsCount);
+    DPRINT("AutomationTableB MethodItemSize %lu MethodSetsCount %lu\n", AutomationTableB->MethodItemSize, AutomationTableB->MethodSetsCount);
+
+    if (AutomationTableA->MethodItemSize && AutomationTableB->MethodItemSize)
+    {
+        /* sanity check */
+        ASSERT(AutomationTableA->MethodItemSize  == AutomationTableB->MethodItemSize);
+    }
 
     /* now iterate all property sets and compare their guids */
     Count = AutomationTableA->MethodSetsCount;
@@ -1992,8 +2151,14 @@ KspCountEventSets(
     if (!AutomationTableB)
         return AutomationTableA->EventSetsCount;
 
-    /* sanity check */
-    ASSERT(AutomationTableA->EventItemSize == AutomationTableB->EventItemSize);
+    DPRINT("AutomationTableA EventItemSize %lu EventSetsCount %lu\n", AutomationTableA->EventItemSize, AutomationTableA->EventSetsCount);
+    DPRINT("AutomationTableB EventItemSize %lu EventSetsCount %lu\n", AutomationTableB->EventItemSize, AutomationTableB->EventSetsCount);
+
+    if (AutomationTableA->EventItemSize && AutomationTableB->EventItemSize)
+    {
+        /* sanity check */
+        ASSERT(AutomationTableA->EventItemSize == AutomationTableB->EventItemSize);
+    }
 
     /* now iterate all Event sets and compare their guids */
     Count = AutomationTableA->EventSetsCount;
@@ -2036,6 +2201,8 @@ KspCountPropertySets(
         return AutomationTableA->PropertySetsCount;
 
     /* sanity check */
+    DPRINT("AutomationTableA PropertyItemSize %lu PropertySetsCount %lu\n", AutomationTableA->PropertyItemSize, AutomationTableA->PropertySetsCount);
+    DPRINT("AutomationTableB PropertyItemSize %lu PropertySetsCount %lu\n", AutomationTableB->PropertyItemSize, AutomationTableB->PropertySetsCount);
     ASSERT(AutomationTableA->PropertyItemSize == AutomationTableB->PropertyItemSize);
 
     /* now iterate all property sets and compare their guids */
@@ -2075,18 +2242,18 @@ KspCopyMethodSets(
     if (!AutomationTableA)
     {
         /* copy of property set */
-        RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableB->MethodSets, Table->MethodItemSize * AutomationTableB->MethodSetsCount);
+        RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableB->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableB->MethodSetsCount);
         return STATUS_SUCCESS;
     }
     else if (!AutomationTableB)
     {
         /* copy of property set */
-        RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, Table->MethodItemSize * AutomationTableA->MethodSetsCount);
+        RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableA->MethodSetsCount);
         return STATUS_SUCCESS;
     }
 
     /* first copy all property items from dominant table */
-    RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, Table->MethodItemSize * AutomationTableA->MethodSetsCount);
+    RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableA->MethodSetsCount);
     /* set counter */
     Count = AutomationTableA->MethodSetsCount;
 
@@ -2109,7 +2276,7 @@ KspCopyMethodSets(
         if (!bFound)
         {
             /* copy new property item set */
-            RtlMoveMemory((PVOID)&Table->MethodSets[Count], &AutomationTableB->MethodSets[Index], Table->MethodItemSize);
+            RtlMoveMemory((PVOID)&Table->MethodSets[Count], &AutomationTableB->MethodSets[Index], sizeof(KSMETHOD_SET));
             Count++;
         }
     }
@@ -2130,18 +2297,18 @@ KspCopyPropertySets(
     if (!AutomationTableA)
     {
         /* copy of property set */
-        RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableB->PropertySets, Table->PropertyItemSize * AutomationTableB->PropertySetsCount);
+        RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableB->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableB->PropertySetsCount);
         return STATUS_SUCCESS;
     }
     else if (!AutomationTableB)
     {
         /* copy of property set */
-        RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, Table->PropertyItemSize * AutomationTableA->PropertySetsCount);
+        RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableA->PropertySetsCount);
         return STATUS_SUCCESS;
     }
 
     /* first copy all property items from dominant table */
-    RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, Table->PropertyItemSize * AutomationTableA->PropertySetsCount);
+    RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableA->PropertySetsCount);
     /* set counter */
     Count = AutomationTableA->PropertySetsCount;
 
@@ -2164,7 +2331,7 @@ KspCopyPropertySets(
         if (!bFound)
         {
             /* copy new property item set */
-            RtlMoveMemory((PVOID)&Table->PropertySets[Count], &AutomationTableB->PropertySets[Index], Table->PropertyItemSize);
+            RtlMoveMemory((PVOID)&Table->PropertySets[Count], &AutomationTableB->PropertySets[Index], sizeof(KSPROPERTY_SET));
             Count++;
         }
     }
@@ -2184,18 +2351,18 @@ KspCopyEventSets(
     if (!AutomationTableA)
     {
         /* copy of Event set */
-        RtlMoveMemory((PVOID)Table->EventSets, AutomationTableB->EventSets, Table->EventItemSize * AutomationTableB->EventSetsCount);
+        RtlMoveMemory((PVOID)Table->EventSets, AutomationTableB->EventSets, sizeof(KSEVENT_SET) * AutomationTableB->EventSetsCount);
         return STATUS_SUCCESS;
     }
     else if (!AutomationTableB)
     {
         /* copy of Event set */
-        RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, Table->EventItemSize * AutomationTableA->EventSetsCount);
+        RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, sizeof(KSEVENT_SET) * AutomationTableA->EventSetsCount);
         return STATUS_SUCCESS;
     }
 
     /* first copy all Event items from dominant table */
-    RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, Table->EventItemSize * AutomationTableA->EventSetsCount);
+    RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, sizeof(KSEVENT_SET) * AutomationTableA->EventSetsCount);
     /* set counter */
     Count = AutomationTableA->EventSetsCount;
 
@@ -2218,7 +2385,7 @@ KspCopyEventSets(
         if (!bFound)
         {
             /* copy new Event item set */
-            RtlMoveMemory((PVOID)&Table->EventSets[Count], &AutomationTableB->EventSets[Index], Table->EventItemSize);
+            RtlMoveMemory((PVOID)&Table->EventSets[Count], &AutomationTableB->EventSets[Index], sizeof(KSEVENT_SET));
             Count++;
         }
     }
@@ -2282,7 +2449,7 @@ KsMergeAutomationTables(
         }
 
         /* now allocate the property sets */
-        Table->PropertySets = AllocateItem(NonPagedPool, Table->PropertyItemSize * Table->PropertySetsCount);
+        Table->PropertySets = AllocateItem(NonPagedPool, sizeof(KSPROPERTY_SET) * Table->PropertySetsCount);
 
         if (!Table->PropertySets)
         {
@@ -2325,7 +2492,7 @@ KsMergeAutomationTables(
         }
 
         /* now allocate the property sets */
-        Table->MethodSets = AllocateItem(NonPagedPool, Table->MethodItemSize * Table->MethodSetsCount);
+        Table->MethodSets = AllocateItem(NonPagedPool, sizeof(KSMETHOD_SET) * Table->MethodSetsCount);
 
         if (!Table->MethodSets)
         {
@@ -2368,7 +2535,7 @@ KsMergeAutomationTables(
         }
 
         /* now allocate the property sets */
-        Table->EventSets = AllocateItem(NonPagedPool, Table->EventItemSize * Table->EventSetsCount);
+        Table->EventSets = AllocateItem(NonPagedPool, sizeof(KSEVENT_SET) * Table->EventSetsCount);
 
         if (!Table->EventSets)
         {
@@ -2539,8 +2706,26 @@ KsRegisterAggregatedClientUnknown(
     IN PVOID  Object,
     IN PUNKNOWN  ClientUnknown)
 {
-    UNIMPLEMENTED
-    return NULL;
+    PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
+
+    /* sanity check */
+    ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory || 
+           BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
+
+    if (BasicHeader->ClientAggregate)
+    {
+        /* release existing aggregate */
+        BasicHeader->ClientAggregate->lpVtbl->Release(BasicHeader->ClientAggregate);
+    }
+
+    /* increment reference count */
+    ClientUnknown->lpVtbl->AddRef(ClientUnknown);
+
+    /* store client aggregate */
+    BasicHeader->ClientAggregate = ClientUnknown;
+
+    /* return objects outer unknown */
+    return BasicHeader->OuterUnknown;
 }
 
 /*