SColorPicker with NativeWidgetHost cannot be packaged with an error related to TSharedPtr.

SColorPicker with NativeWidgetHost in (at least) Unreal Engine 4.19. cannot be packaged, while there is no problem during Play in Editor.

I’d like to use SColorPicker as UMG, so I tried a very simple implementation using UNativeWidgetHost like the followings.

NativeWidgetHostColorPicker.h

#pragma once

#include "CoreMinimal.h"
#include "Components/NativeWidgetHost.h"
#include "NativeWidgetHostColorPicker.generated.h"

UCLASS()
class COLORPICKERTEST419_API UNativeWidgetHostColorPicker : public UNativeWidgetHost
{
  GENERATED_BODY()

public:
  UNativeWidgetHostColorPicker(const FObjectInitializer& ObjectInitializer);
};

NativeWidgetHostColorPicker.cpp

#include "NativeWidgetHostColorPicker.h"
#include "SColorPicker.h"

UNativeWidgetHostColorPicker::UNativeWidgetHostColorPicker(const FObjectInitializer& ObjectInitializer) : UNativeWidgetHost(ObjectInitializer) {
  TSharedRef<SColorPicker> color_picker = SNew(SColorPicker);

  SetContent(color_picker);
}

Widget Blueprint

It works fine during Play in Editor.

However, when I try to package the project (Windows(64 bit)), it causes an error.
The error seems to say

TSharedRef<SColorPicker> color_picker = SNew(SColorPicker);

in NativeWidgetHostColorPicker.cpp causes an error. And when I replace SColorPicker by other SWidget inherited class like SColorSpectrum,

TSharedRef<SColorSpectrum> color_picker = SNew(SColorSpectrum);

it works fine during Playing in Editor, and it can be packaged with no error.

I’ve uploaded both SColorPicker project [here (GitHub - HSeo/ColorPickerTest419: SColorPicker with NativeWidgetHost.)][3], and SColorSpectrum project [here (GitHub - HSeo/ColorSpectrumTest419: SColorSpectrum with NativeWidgetHost.)][4].

I know the above setups are not enough at all for practical use, but I tried to make the projects as simple as possible.

Is this a specific bug about SColorPicker? Or maybe my implementation is somehow incorrect?

PackagingResults: Error: === Critical error: ===
PackagingResults: Error: Assertion failed: IsValid() [File:D:\Build\++UE4+Release-4.19+Compile\Sync\Engine\Source\Runtime\Core\Public\Templates/SharedPointer.h] [Line: 824]
PackagingResults: Error: [Callstack] 0x000000000143A388 KERNELBASE.dll!UnknownFunction []
PackagingResults: Error: [Callstack] 0x00000000DE247884 UE4Editor-ApplicationCore.dll!FWindowsErrorOutputDevice::Serialize() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\applicationcore\private\windows\windowserroroutputdevice.cpp:65]
PackagingResults: Error: [Callstack] 0x0000000023636D9B UE4Editor-Core.dll!FOutputDevice::LogfImpl() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\core\private\misc\outputdevice.cpp:70]
PackagingResults: Error: [Callstack] 0x0000000023571949 UE4Editor-Core.dll!FDebug::AssertFailed() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\core\private\misc\assertionmacros.cpp:419]
PackagingResults: Error: [Callstack] 0x0000000078F43B0F UE4Editor-SlateCore.dll!FSlateApplicationBase::Get() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\slatecore\public\application\slateapplicationbase.h:428]
PackagingResults: Error: [Callstack] 0x0000000078F8A897 UE4Editor-SlateCore.dll!SWidget::RegisterActiveTimer() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\slatecore\private\widgets\swidget.cpp:984]
PackagingResults: Error: [Callstack] 0x0000000069A67204 UE4Editor-AppFramework.dll!SColorPicker::Construct() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\appframework\private\widgets\colors\scolorpicker.cpp:90]
PackagingResults: Error: [Callstack] 0x000000000D3D2516 UE4Editor-ColorPickerTest419.dll!UNativeWidgetHostColorPicker::UNativeWidgetHostColorPicker() [c:\users\xxxx\documents\unreal projects\colorpickertest419\source\colorpickertest419\nativewidgethostcolorpicker.cpp:5]
PackagingResults: Error: [Callstack] 0x00000000AE0654F8 UE4Editor-CoreUObject.dll!UClass::CreateDefaultObject() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\coreuobject\private\uobject\class.cpp:2749]
PackagingResults: Error: [Callstack] 0x00000000AE2F7D30 UE4Editor-CoreUObject.dll!UObjectLoadAllCompiledInDefaultProperties() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\coreuobject\private\uobject\uobjectbase.cpp:821]
PackagingResults: Error: [Callstack] 0x00000000AE2D94A2 UE4Editor-CoreUObject.dll!ProcessNewlyLoadedUObjects() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\coreuobject\private\uobject\uobjectbase.cpp:895]
PackagingResults: Error: [Callstack] 0x00000000AE06A7F7 UE4Editor-CoreUObject.dll!TBaseStaticDelegateInstance::ExecuteIfSafe() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\core\public\delegates\delegateinstancesimpl.h:788]
PackagingResults: Error: [Callstack] 0x0000000023424190 UE4Editor-Core.dll!TBaseMulticastDelegate::Broadcast() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\core\public\delegates\delegatesignatureimpl.inl:937]
PackagingResults: Error: [Callstack] 0x0000000023635E91 UE4Editor-Core.dll!FModuleManager::LoadModuleWithFailureReason() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\core\private\modules\modulemanager.cpp:487]
PackagingResults: Error: [Callstack] 0x00000000DE7FFC7A UE4Editor-Projects.dll!FModuleDescriptor::LoadModulesForPhase() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\projects\private\moduledescriptor.cpp:484]
PackagingResults: Error: [Callstack] 0x00000000DE7FFFC2 UE4Editor-Projects.dll!FProjectManager::LoadModulesForProject() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\projects\private\projectmanager.cpp:69]
PackagingResults: Error: [Callstack] 0x00000000D1109731 UE4Editor-Cmd.exe!FEngineLoop::LoadStartupModules() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\launch\private\launchengineloop.cpp:2610]
PackagingResults: Error: [Callstack] 0x00000000D110DD83 UE4Editor-Cmd.exe!FEngineLoop::PreInit() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\launch\private\launchengineloop.cpp:2027]
PackagingResults: Error: [Callstack] 0x00000000D11069FA UE4Editor-Cmd.exe!GuardedMain() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\launch\private\launch.cpp:127]
PackagingResults: Error: [Callstack] 0x00000000D1106C4A UE4Editor-Cmd.exe!GuardedMainWrapper() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:144]
PackagingResults: Error: [Callstack] 0x00000000D1114177 UE4Editor-Cmd.exe!WinMain() [d:\build\++ue4+release-4.19+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:223]
PackagingResults: Error: [Callstack] 0x00000000D1114FBF UE4Editor-Cmd.exe!__scrt_common_main_seh() [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:253]
PackagingResults: Error: [Callstack] 0x00000000026B3034 KERNEL32.DLL!UnknownFunction []
PackagingResults: Error: [Callstack] 0x00000000050A3691 ntdll.dll!UnknownFunction []
PackagingResults: Error: [Callstack] 0x00000000050A3691 ntdll.dll!UnknownFunction []

こんにちは、日本語で失礼いたします。

##対策について

RebuildWidget()をoverrideして、その中でColorPickerを作ると問題が発生しなくなりました。

// .h
UCLASS()
class COLORPICKERTEST419_API UNativeWidgetHostColorPicker : public UNativeWidgetHost
{
  GENERATED_BODY()

public:
  UNativeWidgetHostColorPicker(const FObjectInitializer& ObjectInitializer);
  virtual TSharedRef<SWidget> RebuildWidget() override;
};

// .cpp
UNativeWidgetHostColorPicker::UNativeWidgetHostColorPicker(const FObjectInitializer& ObjectInitializer) : UNativeWidgetHost(ObjectInitializer) 
{
}

TSharedRef<SWidget> UNativeWidgetHostColorPicker::RebuildWidget()
{
  this->SetContent( SNew(SColorPicker) );
  return this->GetContent().ToSharedRef();
}

下記の記事を参考にしています。

また、UButtonなど既存のUWidget派生オブジェクトの作り方を見る限り、Constructorでは固有パラメータの初期化のみ行って、SWidget派生オブジェクトはやはりRebuildWidget内でSNewするのが良いようです。
(このあたりの作法に言及しているドキュメントが見つけられませんでした…)

##エラーの原因について
SColorPickerのインスタンス生成中、FSlateApplicationBaseの実体がない段階でShared参照を得ようとして死んでいたようです。
Packaging処理の中でそのようなタイミングがあるのだと思います。
SColorSpectrumは構築処理でFSlateApplicationBaseにアクセスしないのでセーフだった様です。

※Slateにあまり詳しくないので、勘違いなどあるかもしれません。ご容赦ください。

ご不明な点などありましたらお知らせください。
以上です。

It’s asserting because your wrapper CDO (Class Default Object) is trying to use Slate before it’s been initialized. This will be different in a packaged game since they’re monolithic, whereas in the editor you’re getting away with it because Slate is initialized before your game module loads.

The simplest fix would be to avoid creating the actual Slate widget for the CDO instance. You can do this by checking whether the object has the RF_ClassDefaultObject flag set.

Thank you very much for your answer. Your solution is much easier than Jamie suggested.
As you told moving SNew or SAssignNew from the class’s constructor to RebuildWidget solved the problem.
I also added ReleaseSlateResources to prevent memory leaks ( sometimes Output Log says it found memory leaks without ReleaseSlateResources).

So the followings are the whole source codes.

NativeWidgetHostColorPicker.h

#pragma once

#include "CoreMinimal.h"
#include "Components/NativeWidgetHost.h"
#include "NativeWidgetHostColorPicker.generated.h"

class SColorPicker;

UCLASS()
class COLORPICKERTEST419_API UNativeWidgetHostColorPicker : public UNativeWidgetHost {
  GENERATED_BODY()

public:
  UNativeWidgetHostColorPicker(const FObjectInitializer& ObjectInitializer);
  virtual void ReleaseSlateResources(bool bReleaseChildren) override;

protected:
  virtual TSharedRef<SWidget> RebuildWidget() override;

private:
  TSharedPtr<SColorPicker> color_picker_;
};

NativeWidgetHostColorPicker.cpp

#include "NativeWidgetHostColorPicker.h"
#include "SColorPicker.h"

UNativeWidgetHostColorPicker::UNativeWidgetHostColorPicker(const FObjectInitializer& ObjectInitializer) : UNativeWidgetHost(ObjectInitializer) {}

void UNativeWidgetHostColorPicker::ReleaseSlateResources(bool bReleaseChildren) {
  Super::ReleaseSlateResources(bReleaseChildren);
  color_picker_.Reset();
}

TSharedRef<SWidget> UNativeWidgetHostColorPicker::RebuildWidget() {
  SAssignNew(color_picker_, SColorPicker);
  SetContent(color_picker_.ToSharedRef());

  //UNativeWidgetHost::RebuildWidget(); // Unnecessary?

  return GetContent().ToSharedRef();
}

One remaining question is that

UNativeWidgetHost::RebuildWidget();

in UNativeWidgetHostColorPicker::RebuildWidget() is necessary or not.

Anyway, now I can package SColorPicker with NativeWidgetHost to exe file!
Thank you so much.

I’ve updated the GitHub projects.
https://github.com/HSeo/ColorPickerTest419
https://github.com/HSeo/ColorSpectrumTest419

I’m sorry for my incorrect recognition of UNativeWidgetHost. My recognition now is as follows.

  • UNativeWidgetHostColorPicker does not need to have member "color_picker_”.

    • Instead of using UNativeWidgetHost::NativeWidget by call UNativeWidgetHost::SetContent().
  • There is no need to override ReleaseSlateResources():

    • UNativeWidgetHost::ReleaseSlateResources() will work.
  • There is no need to override RebuildWidget()

    • UNativeWidgetHost::RebuildWidget() will work.
    • Our content (In this case SColorPick) will wrapped in SBox automatically.

My new implementation is as follows.

NativeWidgetHostColorPicker.h

#pragma once

#include "CoreMinimal.h"
#include "Components/NativeWidgetHost.h"
#include "NativeWidgetHostColorPicker.generated.h"

UCLASS()
class COLORPICKERTEST419_API UNativeWidgetHostColorPicker : public UNativeWidgetHost
{
  GENERATED_BODY()

public:
  UNativeWidgetHostColorPicker(const FObjectInitializer& ObjectInitializer);
};

NativeWidgetHostColorPicker.cpp

#include "NativeWidgetHostColorPicker.h"
#include "SColorPicker.h"
#include "SlateApplicationBase.h"

UNativeWidgetHostColorPicker::UNativeWidgetHostColorPicker(const FObjectInitializer& ObjectInitializer) : UNativeWidgetHost(ObjectInitializer) {

    if (FSlateApplicationBase::IsInitialized()) {
        this->SetContent(SNew(SColorPicker));
    }
}

By checking with FSlateApplicationBase::IsInitialized(), avoid the crash matter.

I tried to check RF_ClassDefaultObject, but it couldnot avoid the cooking crash.

UNativeWidgetHostColorPicker::UNativeWidgetHostColorPicker(const FObjectInitializer& ObjectInitializer) : UNativeWidgetHost(ObjectInitializer) {
    if (!this->HasAnyFlags(RF_ClassDefaultObject)) {
        this->SetContent( SNew(SColorPicker) ); // still cause crash at cooking.
    }
}

How can we check by RF_ClassDefaultObject?