[Plugin] Proper way to use a class from an Unreal Plugin / Module ?

Hello,
I am trying to use the CineCameraSceneCapture Plugin in 5.3. I am trying to determine the proper way to utilize a class from this Plugin. For example, when i try to create a UCineCaptureComponent2D I get the following error…

Error LNK2019 unresolved external symbol private: static class UClass * __cdecl UCineCaptureComponent2D::GetPrivateStaticClass(void) (?GetPrivateStaticClass@UCineCaptureComponent2D@@CAPEAVUClass@@XZ) referenced in function public: __cdecl ATestActor::ATestActor(void) (??0ATestActor@@QEAA@XZ)|TestProject|D:\UnrealEngine\TestProject\Intermediate\ProjectFiles\TestActor.cpp.obj

I have added CineCameraSceneCapture to PrivateDependencyModuleNames and PublicDependencyModuleNames in the Build.cs file. I have pretty much tried to add it everywhere I can think of lol (UProject Modules, Target.cs, Editor.Target.cs, etc)

I have tried multiple ways of creating the component but all produce the same results…

ATestActor::ATestActor()
{
	CineCapture2D = Cast<UCineCaptureComponent2D>(AddComponentByClass(UCineCaptureComponent2D::StaticClass(), false, FTransform::Identity, false));
	//CineCapture2D = CreateDefaultSubobject<UCineCaptureComponent2D>(TEXT("CineCapture2D"));
	//CineCapture2D = NewObject<UCineCaptureComponent2D>(this, TEXT("CineCaptureComponent"));
	//CineCapture2D = ObjectInitializer.CreateDefaultSubobject<UCineCaptureComponent2D>(this, TEXT("CineCapture2D"));
}

I have tried this with other plugins too and get similar results. So my question is, what is the proper way to utilize a class from a plugin such as adding a component (defined in the plugin) to an actor? Thanks!

This looks like an issue with the CineCameraSceneCapture plugin; they did not export the UCineCaptureComponent2D API. If you are able to modify the plugin’s code, you can try adding ‘CINECAMERASCENECAPTURE_API’ to the file CineCameraSceneCaptureComponent.h, as shown in the following image.

2 Likes

BTW, this may require you compile the engine from source, i am not sure yet.

2 Likes

Yes, they didn’t export the class

1 Like

Understood, I will give that a try and report my findings… For my understanding, should exporting the class via API and importing the module to the build dependencies (.build.cs) “generally” be what is required to import a class described in a Plugin / Module ?

I guess i dont understand what the API aspect is doing “under the hood” but i will do some research. Thanks!

Yes, if you need to use a class based on UCLASS in other Plugin / Module, it must be exported. Adding module dependencies in the build.cs will link your module with the target module, but if that class is not exported, all of its non-INLINE methods are private, and you will not be able to access it outside the module. This will lead to a link failure.

On the Windows platform, UE compiles the modules into separate DLLs… This article provides some details about DLLs and exports: Exporting from a DLL | Microsoft Learn.

The XXX_API is a macro will finally be replaced into __declspec(dllexport) on the Windows platform and other symbols on other platforms during compile.

1 Like

Thanks for that info, very helpfull!

Maybe since this plugin is experimental and will likely require changes, it would be better to copy it into the project local plugin folder? That should then make it easier to build changes, but then i would have to get around having two of the same module in the build. Hmm…may end up needing the engine compiled from source for that anyways

Thanks again!

I just found a workaround to share with you:

  1. Declare the component with UPROPERTY, this is an important step to let reflection system to register the class of CineCameraSceneCapture before you use it.
UPROPERTY(EditAnywhere)
class UCineCaptureComponent2D* CineCaptureComponent2D;
  1. Create the component with the help of reflection system
// Load class via reflection system
UClass* CineCaptureComponent2DClass = LoadClass<USceneCaptureComponent2D>(nullptr, TEXT("/Script/CineCameraSceneCapture.CineCaptureComponent2D"));
// Create subobject with UClass
CineCaptureComponent2D = StaticCast<UCineCaptureComponent2D*>(CreateDefaultSubobject(TEXT("CineCapture2D"), CineCaptureComponent2DClass, CineCaptureComponent2DClass, true, false));
  1. Use the component like usual
// It's ok to use properties
CineCaptureComponent2D->RenderTargetHighestDimension = 2048;

// It's ok to call methods in it's parent class
CineCaptureComponent2D->HideComponent(nullptr);

// It's not ok to call methods defined by UCineCaptureComponent2D, but this component doesn't define any methods.
1 Like