Link error when extending from APostProcessVolume class

Hello,

I auto generate a class that inherits from APostProcessVolume I get the following link errors on Visual Studio:

1>MyPostProcessVolume.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl APostProcessVolume::PostUnregisterAllComponents(void)" (?PostUnregisterAllComponents@APostProcessVolume@@UEAAXXZ)
1>test.generated.cpp.obj : error LNK2019: unresolved external symbol "public: virtual void __cdecl APostProcessVolume::PostUnregisterAllComponents(void)" (?PostUnregisterAllComponents@APostProcessVolume@@UEAAXXZ) referenced in function "class UClass * __cdecl Z_Construct_UClass_AtestProjectile(void)" (?Z_Construct_UClass_AtestProjectile@@YAPEAVUClass@@XZ)
1>MyPostProcessVolume.cpp.obj : error LNK2001: unresolved external symbol "protected: virtual void __cdecl APostProcessVolume::PostRegisterAllComponents(void)" (?PostRegisterAllComponents@APostProcessVolume@@MEAAXXZ)
1>test.generated.cpp.obj : error LNK2019: unresolved external symbol "protected: virtual void __cdecl APostProcessVolume::PostRegisterAllComponents(void)" (?PostRegisterAllComponents@APostProcessVolume@@MEAAXXZ) referenced in function "class UClass * __cdecl Z_Construct_UClass_AtestProjectile(void)" (?Z_Construct_UClass_AtestProjectile@@YAPEAVUClass@@XZ)
1>MyPostProcessVolume.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl APostProcessVolume::PostEditChangeProperty(struct FPropertyChangedEvent &)" (?PostEditChangeProperty@APostProcessVolume@@UEAAXAEAUFPropertyChangedEvent@@@Z)
1>test.generated.cpp.obj : error LNK2019: unresolved external symbol "public: virtual void __cdecl APostProcessVolume::PostEditChangeProperty(struct FPropertyChangedEvent &)" (?PostEditChangeProperty@APostProcessVolume@@UEAAXAEAUFPropertyChangedEvent@@@Z) referenced in function "class UClass * __cdecl Z_Construct_UClass_AtestProjectile(void)" (?Z_Construct_UClass_AtestProjectile@@YAPEAVUClass@@XZ)
1>MyPostProcessVolume.cpp.obj : error LNK2001: unresolved external symbol "public: virtual bool __cdecl APostProcessVolume::CanEditChange(class UProperty const *)const " (?CanEditChange@APostProcessVolume@@UEBA_NPEBVUProperty@@@Z)
1>test.generated.cpp.obj : error LNK2019: unresolved external symbol "public: virtual bool __cdecl APostProcessVolume::CanEditChange(class UProperty const *)const " (?CanEditChange@APostProcessVolume@@UEBA_NPEBVUProperty@@@Z) referenced in function "class UClass * __cdecl Z_Construct_UClass_AtestProjectile(void)" (?Z_Construct_UClass_AtestProjectile@@YAPEAVUClass@@XZ)
1>D:\Unreal Project\test\Binaries\Win64\UE4Editor-test.dll : fatal error LNK1120: 4 unresolved externals

I tested this on both 4.2.1 and 4.5.1 with the same result. Is there any solution to this?

Thank you.

Did you remember to include PostProcessVolume.h into your subclass’s .h file?

I don’t speak for UDGMohammed, but I included the file and I’m getting the exact same errors.

+1 .same error

Copy this code to .cpp file:

#if WITH_EDITOR
void APostProcessVolume::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	static const FName NAME_Blendables = FName(TEXT("Blendables"));

	if (PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == NAME_Blendables)
	{
		// remove unsupported types
		/*
		{
			uint32 Count = Settings.Blendables.Num();
			for (uint32 i = 0; i < Count; ++i)
			{
				UObject* Obj = Settings.Blendables[i];

				if (!Cast<IBlendableInterface>(Obj))
				{
					Settings.Blendables[i] = 0;
				}
			}
		}*/
	}
}

bool APostProcessVolume::CanEditChange(const UProperty* InProperty) const
{
	if (InProperty)
	{
		FString PropertyName = InProperty->GetName();

		if (PropertyName == GET_MEMBER_NAME_STRING_CHECKED(APostProcessVolume, bEnabled))
		{
			return true;
		}

		if (!bEnabled)
		{
			return false;
		}

		if (PropertyName == GET_MEMBER_NAME_STRING_CHECKED(APostProcessVolume, BlendRadius))
		{
			if (bUnbound)
			{
				return false;
			}
		}
	}

	return Super::CanEditChange(InProperty);
}

#endif // WITH_EDITOR

void InsertVolume(IInterface_PostProcessVolume* Volume, TArray< IInterface_PostProcessVolume* >& VolumeArray)
{
	const int32 NumVolumes = VolumeArray.Num();
	float TargetPriority = Volume->GetProperties().Priority;
	int32 InsertIndex = 0;
	// TODO: replace with binary search.
	for (; InsertIndex < NumVolumes; InsertIndex++)
	{
		IInterface_PostProcessVolume* CurrentVolume = VolumeArray[InsertIndex];
		float CurrentPriority = CurrentVolume->GetProperties().Priority;

		if (TargetPriority < CurrentPriority)
		{
			break;
		}
		if (CurrentVolume == Volume)
		{
			return;
		}
	}
	VolumeArray.Insert(Volume, InsertIndex);
}

void APostProcessVolume::PostUnregisterAllComponents()
{
	// Route clear to super first.
	Super::PostUnregisterAllComponents();
	// World will be NULL during exit purge.
	if (GetWorld())
	{
		GetWorld()->PostProcessVolumes.RemoveSingle(this);
	}
}

void APostProcessVolume::PostRegisterAllComponents()
{
	// Route update to super first.
	Super::PostRegisterAllComponents();
	InsertVolume(this, GetWorld()->PostProcessVolumes);
}

same problem. (4.12)

The PostProcessVolume class is marked with the MinimalAPI specifier in its UCLASS macro. To use the class without getting the error, you should be able to open the [ProjectName].h file for your project and change the include path from #include "EngineMinimal.h" to #include "Engine.h"

Cheers

my project header already includes Engine.h …

After further investigation, I was mistakenly confusing MinimalAPI with EngineAPI. If a class is marked as EngineAPI, having the include statement for Engine.h allows it to be used. For something that is marked as MinimalAPI, this means that it is not available outside of source code and can’t be extended. If you are using a source version of the engine you can change MinimalAPI to EngineAPI in the PostProcessVolume.h file.

Hmm. Yeah, I guess I can make that change. I have really been trying my hardest to avoid engine level changes as they increase the complexity of merges with future versions of the engine. Is this change something you guys could introduce yourselves with a future release ? Subclassing PostProcessVolume seems like it would be a fairly common thing to do in many projects …

MinimalAPI classes can still be cast to, but functions of the class can’t be called unless they are specifically exposed as inline functions. This is done to help improve compile times. Additionally, marking PostProcessVolume as EngineAPI would most likely also lead to cascading additional classes needing to be exposed as well which would further increase the compile time. Since the source code is available to make changes on a case by case basis, this feature is unlikely to change in the future.