.NET 9混合程序中同时初始化tbbmalloc_proxy与保证AppDomain.BaseDirectory有效的实现方案咨询
我目前正在把一个混合代码库从.NET Framework 4.7.2迁移到.NET 9。在4.7.2中,我们用C++/CLI EXE作为程序入口,这样可以很方便地在主文件中引入tbbmalloc_proxy.h初始化TBB内存分配器,之后再调用C#代码。但.NET 9不再支持C++/CLI EXE,所以我只能选择原生C++ EXE或者C# EXE作为入口,不过两种方案各有问题,想请教大家有没有解决办法。
方案一:原生C++ EXE作为入口,通过C++/CLI DLL启动WPF App
这个方案能成功初始化tbbmalloc_proxy,但System.AppDomain.CurrentDomain.BaseDirectory为空,导致WPF的MediaElement组件报错。
代码实现
原生C++ EXE(Main.cpp)
#include "Launcher/Launcher.h" #include <objbase.h> #include <tbb/tbbmalloc_proxy.h> int WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow ) { // 对应托管代码中的[System::STAThreadAttribute] HRESULT lResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (FAILED(lResult)) { return -1; } Launch(); return 0; }
C++/CLI DLL(Launcher.h)
#pragma once #if defined( LAUNCHER_BUILD ) #define LAUNCHER_DLL __declspec(dllexport) #else #define LAUNCHER_DLL __declspec(dllimport) #endif LAUNCHER_DLL void Launch();
C++/CLI DLL(Launcher.cpp)
#include "Launcher.h" #include <tbb/tbbmalloc_proxy.h> void LogTbbMalloc() { char** func_replacement_log; int func_replacement_status = TBB_malloc_replacement_log(&func_replacement_log); if (func_replacement_status != 0) { System::Diagnostics::Debug::WriteLine("tbbmalloc replace failed!"); } System::Diagnostics::Debug::WriteLine("tbbmalloc status:"); for (char** log_string = func_replacement_log; *log_string != 0; log_string++) { System::Diagnostics::Debug::WriteLine(gcnew System::String(*log_string)); } } LAUNCHER_DLL void Launch() { LogTbbMalloc(); // LauncherCore.App是C# DLL中的类,继承自System.Windows.Application LauncherCore::App^ lpApp = gcnew LauncherCore::App(); lpApp->InitializeComponent(); lpApp->Run(); }
方案一的结果
tbbmalloc_proxy初始化成功,日志输出正常:
tbbmalloc status: Success: free (ucrtbase.dll), byte pattern: <C7442410000000008B4424> Success: _msize (ucrtbase.dll), byte pattern: <E9ABFFFFFFCCCCCCCCCCCC> Success: _aligned_free (ucrtbase.dll), byte pattern: <4883EC284885C9740D4883> Success: _aligned_msize (ucrtbase.dll), byte pattern: <48895C2408574883EC2049> Success: _o_free (ucrtbase.dll), byte pattern: <488BD1488D0DD604FBFFE9> Success: _free_base (ucrtbase.dll), byte pattern: <4883EC284885C974164C8B>
但System.AppDomain.CurrentDomain.BaseDirectory为空,WPF的MediaElement在调用System.Windows.Media.MediaPlayerState.OpenMedia(Uri)时,会用这个空路径创建Uri,最终抛出UriFormatException,错误信息是Invalid URI: The URI is empty.。
方案二:C# EXE作为入口,通过C++/CLI DLL启动WPF App
这个方案中System.AppDomain.CurrentDomain.BaseDirectory能正常设置,不会触发MediaElement的错误,但tbbmalloc_proxy初始化失败,性能受到影响。
代码实现
C# EXE(Main.cs)
using System; internal class Main { [STAThread] internal static void Main() { Launcher.Launch(); } }
C++/CLI DLL(Launcher.h)
#pragma once public ref class Launcher { public: static void Launch(); };
C++/CLI DLL(Launcher.cpp)
#include "Launcher.h" #include <tbb/tbbmalloc_proxy.h> void LogTbbMalloc() { char** func_replacement_log; int func_replacement_status = TBB_malloc_replacement_log(&func_replacement_log); if (func_replacement_status != 0) { System::Diagnostics::Debug::WriteLine("tbbmalloc replace failed!"); } System::Diagnostics::Debug::WriteLine("tbbmalloc status:"); for (char** log_string = func_replacement_log; *log_string != 0; log_string++) { System::Diagnostics::Debug::WriteLine(gcnew System::String(*log_string)); } } void Launcher::Launch() { LogTbbMalloc(); // LauncherCore.App是C# DLL中的类,继承自System.Windows.Application LauncherCore::App^ lpApp = gcnew LauncherCore::App(); lpApp->InitializeComponent(); lpApp->Run(); }
方案二的结果
System.AppDomain.CurrentDomain.BaseDirectory正常,但tbbmalloc_proxy初始化失败,日志输出:
tbbmalloc replace failed! tbbmalloc status:
补充背景
值得一提的是,在.NET Framework 4.7.2中,用原生C++ EXE作为入口的方案是完全正常的,BaseDirectory能正确设置,所以我怀疑这是.NET Framework和.NET 9(Core系列)之间的运行时差异导致的。
我现在的目标是找到一个可行的方案,既能:
- 正确初始化
tbbmalloc_proxy,替换标准C++内存分配函数; - 保证
System.AppDomain.CurrentDomain.BaseDirectory有有效的路径,避免WPF组件报错。
有没有大佬遇到过类似的问题,或者有什么思路可以解决这个矛盾?
内容来源于stack exchange

