UE的Slate模块
一、使用SWindow时NativeWindow未初始化
遇到的问题
在使用FSlateApplication::Get()将SWindow添加到窗口之前(类似调用FSlateApplication::Get().AddWindow(NewWindow);)不能调用使用NativeWindow的函数,因为这个时候NativeWindow还没有初始化只有调用了类AddWindow函数通过MakeWindow调用InSlateWindow->SetNativeWindow(NewWindow);后
void FChoseAssetWindow::CreateChooseAssetWindow(const TArray<UObject*>& InObjects, UObject* SelectedItem)
{
//...
NewWidget->RefreshSelectableObjects(InObjects);
FSlateApplication::Get().AddModalWindow(NewWindow, FGlobalTabmanager::Get()->GetRootWindow());
//...
}
void SChoseAssetWindow::RefreshSelectableObjects(const TArray<UObject*>& InObjects)
{
if(ParentWindowPtr.IsValid() && !ParentWindowPtr.Pin()->IsVisible()) ParentWindowPtr.Pin()->ShowWindow();
//...
}
Error LogOutputDevice === Handled ensure: ===
Error LogOutputDevice Ensure condition failed: NativeWindow.IsValid() [File:D:\build\++UE5\Sync\Engine\Source\Runtime\SlateCore\Private\Widgets\SWindow.cpp] [Line: 1409]
Error LogOutputDevice Stack:
Error LogOutputDevice [Callstack] 0x00007ffe6c345f9d UnrealEditor-SlateCore.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe3119f59d UnrealEditor-StandalonTest.dll!SChoseAssetWindow::RefreshSelectableObjects() [D:\UEProjects\ATM\ATM\Plugins\StandalonTest\Source\StandalonTest\Private\ChoseAssetWindow.cpp:313]
Error LogOutputDevice [Callstack] 0x00007ffe3118bbc8 UnrealEditor-StandalonTest.dll!FChoseAssetWindow::CreateChooseAssetWindow() [D:\UEProjects\ATM\ATM\Plugins\StandalonTest\Source\StandalonTest\Private\ChoseAssetWindow.cpp:196]
Error LogOutputDevice [Callstack] 0x00007ffe311f6a7d UnrealEditor-StandalonTest.dll!StandalonTestUtils::ReplaceReferences() [D:\UEProjects\ATM\ATM\Plugins\StandalonTest\Source\StandalonTest\Private\StandalonTestUtils.cpp:557]
Error LogOutputDevice [Callstack] 0x00007ffe311eae97 UnrealEditor-StandalonTest.dll!TBaseRawMethodDelegateInstance<0,FStandalonTestModule,void __cdecl(void),FDefaultDelegateUserPolicy>::ExecuteIfSafe() [D:\UE_5.4\Engine\Source\Runtime\Core\Public\Delegates\DelegateInstancesImpl.h:534]
Error LogOutputDevice [Callstack] 0x00007ffe6c80d0f5 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c80d271 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c938ef5 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c90c6aa UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c9aa05c UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c9c8368 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c733975 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c791187 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c77e8f1 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c771aa6 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffeff9cd54f UnrealEditor-ApplicationCore.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffeff9b6f16 UnrealEditor-ApplicationCore.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffeff9cff93 UnrealEditor-ApplicationCore.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffeff9b0e51 UnrealEditor-ApplicationCore.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007fff45ccef5c USER32.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007fff45cce684 USER32.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffeff9d0a96 UnrealEditor-ApplicationCore.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7a780a UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7ce33c UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7ce42a UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7d18a4 UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7e70c4 UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7ea37a UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007fff45997374 KERNEL32.DLL!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007fff46cbcc91 ntdll.dll!UnknownFunction []
Log LogStats SubmitErrorReport - 0.000 s
Log LogStats SendNewReport - 1.108 s
Log LogStats FDebug::EnsureFailed - 1.163 s
Warning LogOutputDevice Script Stack (0 frames) :
Log LogStats FPlatformStackWalk::StackWalkAndDump - 0.026 s
Error LogOutputDevice === Handled ensure: ===
Error LogOutputDevice Ensure condition failed: FoundViewInfo [File:D:\build\++UE5\Sync\Engine\Source\Runtime\SlateRHIRenderer\Private\SlateRHIRenderer.cpp] [Line: 1721]
Error LogOutputDevice Stack:
Error LogOutputDevice [Callstack] 0x00007ffe5d75bc33 UnrealEditor-SlateRHIRenderer.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c77859a UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c75a061 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c799583 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c74f3e4 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe3118bdbd UnrealEditor-StandalonTest.dll!FChoseAssetWindow::CreateChooseAssetWindow() [D:\UEProjects\ATM\ATM\Plugins\StandalonTest\Source\StandalonTest\Private\ChoseAssetWindow.cpp:201]
Error LogOutputDevice [Callstack] 0x00007ffe311f6a7d UnrealEditor-StandalonTest.dll!StandalonTestUtils::ReplaceReferences() [D:\UEProjects\ATM\ATM\Plugins\StandalonTest\Source\StandalonTest\Private\StandalonTestUtils.cpp:557]
Error LogOutputDevice [Callstack] 0x00007ffe311eae97 UnrealEditor-StandalonTest.dll!TBaseRawMethodDelegateInstance<0,FStandalonTestModule,void __cdecl(void),FDefaultDelegateUserPolicy>::ExecuteIfSafe() [D:\UE_5.4\Engine\Source\Runtime\Core\Public\Delegates\DelegateInstancesImpl.h:534]
Error LogOutputDevice [Callstack] 0x00007ffe6c80d0f5 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c80d271 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c938ef5 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c90c6aa UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c9aa05c UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c9c8368 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c733975 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c791187 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c77e8f1 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffe6c771aa6 UnrealEditor-Slate.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffeff9cd54f UnrealEditor-ApplicationCore.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffeff9b6f16 UnrealEditor-ApplicationCore.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffeff9cff93 UnrealEditor-ApplicationCore.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffeff9b0e51 UnrealEditor-ApplicationCore.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007fff45ccef5c USER32.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007fff45cce684 USER32.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ffeff9d0a96 UnrealEditor-ApplicationCore.dll!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7a780a UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7ce33c UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7ce42a UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7d18a4 UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7e70c4 UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007ff6cc7ea37a UnrealEditor.exe!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007fff45997374 KERNEL32.DLL!UnknownFunction []
Error LogOutputDevice [Callstack] 0x00007fff46cbcc91 ntdll.dll!UnknownFunction []
Log LogStats SubmitErrorReport - 0.000 s
The ViewportInfo could not be found for Window.
Error LogSlate The ViewportInfo could not be found for Window.
二、使用TSharedPtr管理Slate造成多次释放同一内存
#pragma once
DECLARE_LOG_CATEGORY_EXTERN(LogChoseAssetWindow, Log, Log);
class SChoseAssetWindow;
class FChoseAssetWindow
{
public:
static void CreateChooseAssetWindow( const TArray<UObject*>& InObjects, UObject* SelectedItem = nullptr );
static void GetChoseResult(UObject*& Result, TArray<UObject*>& OutNotSelected, bool& bIsBreak);
private:
static TSharedPtr<SChoseAssetWindow> WidgetInstance;
};
#include "ChoseAssetWindow.h"
DEFINE_LOG_CATEGORY(LogChoseAssetWindow)
#define LOCTEXT_NAMESPACE "LogChoseAssetWindow"
class SChoseAssetWindow : public SBorder
{
public:
SLATE_BEGIN_ARGS(SChoseAssetWindow)
: _ParentWindow()
{}
SLATE_ARGUMENT(TSharedPtr<SWindow>, ParentWindow)
SLATE_END_ARGS()
private:
TWeakPtr<SWindow> ParentWindowPtr;
};
TSharedPtr<SChoseAssetWindow> FChoseAssetWindow::WidgetInstance;
void FChoseAssetWindow::CreateChooseAssetWindow(const TArray<UObject*>& InObjects, UObject* SelectedItem)
{
TSharedRef<SWindow> NewWindow = SNew(SWindow)
.Title(LOCTEXT("Choose_Title", "Replace References"))
.ClientSize( FVector2D(768,300) );
TSharedPtr<SChoseAssetWindow> NewWidget;
if(WidgetInstance.IsValid())
{
NewWidget = MoveTemp(WidgetInstance);
}else
{
SAssignNew(NewWidget, SChoseAssetWindow)
.ParentWindow(NewWindow);
}
NewWindow->SetContent(NewWidget.ToSharedRef());
FSlateApplication::Get().AddModalWindow(NewWindow, FGlobalTabmanager::Get()->GetRootWindow());
WidgetInstance = NewWidget;
}
void FChoseAssetWindow::GetChoseResult(UObject*& Result, TArray<UObject*>& OutNotSelected, bool& bIsBreak)
{
Result = nullptr;
OutNotSelected.Empty();
if(WidgetInstance.IsValid())
{
WidgetInstance->GetChoseObjects(Result, OutNotSelected);
bIsBreak = WidgetInstance->GetIsCancelAll();
WidgetInstance->ClearSelectableObjects();
}
}
问题在于静态智能指针 WidgetInstance 的生命周期管理和引用计数处理不当,导致对象被多次释放。
问题原因分析
- 静态指针的生命周期问题:
static TSharedPtr<SChoseAssetWindow> WidgetInstance是静态变量,其生命周期持续到程序结束- 当程序退出时,静态对象会按不确定的顺序析构(可能早于Slate系统)
- 双重所有权问题:
if(WidgetInstance.IsValid()) { NewWidget = MoveTemp(WidgetInstance); // 转移所有权到局部变量 // ... } // ... WidgetInstance = NewWidget; // 所有权移回静态变量- 当窗口关闭时,Slate系统会尝试释放窗口内容(
NewWidget) - 但静态指针
WidgetInstance仍然持有该对象的引用 - 程序结束时静态指针析构时再次尝试释放已释放对象
- 当窗口关闭时,Slate系统会尝试释放窗口内容(
解决方案
推荐方案:移除静态实例重用(推荐)
直接每次创建新实例,避免静态指针:
void FChoseAssetWindow::CreateChooseAssetWindow(const TArray<UObject*>& InObjects, UObject* SelectedItem)
{
TSharedRef<SWindow> NewWindow = SNew(SWindow)
.Title(LOCTEXT("Choose_Title", "Replace References"))
.ClientSize(FVector2D(768, 300));
// 始终创建新实例
TSharedRef<SChoseAssetWindow> NewWidget = SNew(SChoseAssetWindow)
.ParentWindow(NewWindow)
.Note(LOCTEXT("Asset_Select", "Select an asset."));
NewWindow->SetContent(NewWidget);
NewWidget->RefreshSelectableObjects(InObjects);
if (SelectedItem) {
NewWidget->SetSelectedItem(SelectedItem);
}
FSlateApplication::Get().AddModalWindow(NewWindow, FGlobalTabmanager::Get()->GetRootWindow());
}
替代方案:正确管理静态实例(若必须重用)
如果必须重用实例,需确保:
- 在窗口关闭时重置静态指针
- 正确处理所有权
// 修改后的实现
void FChoseAssetWindow::CreateChooseAssetWindow(...)
{
...
TSharedPtr<SChoseAssetWindow> NewWidget;
if (WidgetInstance.IsValid() && WidgetInstance->GetParentWindow().IsValid())
{
NewWidget = WidgetInstance;
}
else
{
SAssignNew(NewWidget, SChoseAssetWindow)
.ParentWindow(NewWindow)
.Note(...);
// 监听窗口关闭事件
NewWindow->SetOnWindowClosed(FOnWindowClosed::CreateLambda(
[](const TSharedRef<SWindow>&) {
WidgetInstance.Reset(); // 窗口关闭时重置静态指针
}));
}
... // 其余逻辑
WidgetInstance = NewWidget;
}
崩溃原理示意图
程序启动
|
├─ 创建 WindowInstance (ref=1)
├─ 窗口关闭:Slate释放对象 (ref=0) → 实际删除
└─ 程序结束:静态变量析构 → 再次尝试释放 → 访问野指针 → 崩溃
建议采用每次创建新窗口的方案,这是最安全且符合Slate设计理念的做法。静态实例重用往往带来复杂的生命周期问题,除非有严格的性能需求,否则应避免。