JeffreySu/WeiXinMPSDK · critical · DllNotFoundException
无法加载企业微信 Finance 原生库:
Error message
无法加载企业微信 Finance 原生库:{path}。{detail} What it means
On Linux, dlopen failed to load the WeChat Work Finance shared library: both libdl.so.2 and the legacy libdl.so attempts returned IntPtr.Zero. The wrapper throws DllNotFoundException with the path plus the dlerror() detail string, which names the actual OS-level cause.
Solutions
- Read the dlerror detail in the message — 'No such file or directory' = fix path/publish the .so, 'cannot open shared object file: libssl.so.1.1' = install that dependency.
- Verify the .so was published (RuntimeIdentifier linux-x64, native lib copied to output) and use an absolute path.
- Check architecture: the .so must match the process (x64). Run `file libWeWorkFinanceSdk.so`.
- On alpine/musl images, switch to a glibc-based image (e.g. mcr.microsoft.com/dotnet/aspnet:8.0) or add gcompat.
Example fix
// before
var api = MsgAuditFinanceNativeApi.Create("libWeWorkFinanceSdk.so"); // dlopen fails, path not in search dirs
// after
var path = Path.Combine(AppContext.BaseDirectory, "runtimes", "linux-x64", "native", "libWeWorkFinanceSdk.so");
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", Path.GetDirectoryName(path));
var api = MsgAuditFinanceNativeApi.Create(path); Defensive patterns
Strategy: try-catch
Validate before calling
if (!File.Exists(soPath)) throw new FileNotFoundException("Finance .so not published", soPath);
if (!RuntimeInformation.ProcessArchitecture.ToString().Contains("X64")) throw new PlatformNotSupportedException("x64 required"); Type guard
static bool LinuxLibraryReady(string path) => File.Exists(path) && RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
Try / catch
try { return FinanceLibraryHandle.Load(path); }
catch (DllNotFoundException ex) { logger.LogCritical(ex, "dlopen failed: {Detail}", ex.Message); throw; } Prevention
- Read the dlerror detail appended to the message — it names the missing dependency.
- Publish with RuntimeIdentifier linux-x64 so the .so ships in runtimes/linux-x64/native.
- Install the SDK's dependency chain (OpenSSL 1.1, libcurl) in Docker images.
- Prefer glibc-based images over alpine for this SDK.
When it happens
Trigger: Loading the finance .so with a wrong or relative path; the .so has unresolved dependencies (missing libssl/libcrypto versions, missing libcurl); attempting to load an x86 .so into an x64 process; glibc/dl implementation too old.
Common situations: Docker linux containers missing the SDK's dependency chain (e.g. OpenSSL 1.1 not installed); publishing only managed dlls without the native .so; alpine/musl images where the glibc-built .so cannot load.
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
Related errors
- 企业微信官方未提供当前操作系统可用的 Finance 会话内容存档原生库。请在 Windows 或 Linux…
- 无法加载企业微信 Finance 原生库:
- 企业微信 Finance 会话内容存档原生库仅支持 Windows 和 Linux。
- 企业微信 Finance 原生库缺少导出函数:
- ObjectDisposedException (FinanceLibraryHandle)
AI-assisted analysis of JeffreySu/WeiXinMPSDK@be573f6f94 (2026-09-12).
Data as JSON: /api/errors/764da9a2e6a93678.
Report an issue: GitHub.
Appendix: source
Thrown at src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/MsgAudit/MsgAuditFinanceNativeApi.cs:380
"企业微信 Finance 会话内容存档原生库仅支持 Windows 和 Linux。");
}
IntPtr linuxHandle;
var useLegacy = false;
try
{
linuxHandle = LinuxNative.DlOpen(path, RtldNow);
}
catch (DllNotFoundException)
{
useLegacy = true;
linuxHandle = LinuxLegacyNative.DlOpen(path, RtldNow);
}
if (linuxHandle == IntPtr.Zero)
{
var detail = useLegacy ? LinuxLegacyNative.GetError() : LinuxNative.GetError();
throw new DllNotFoundException(
$"无法加载企业微信 Finance 原生库:{path}。{detail}");
}
return new FinanceLibraryHandle(linuxHandle, false, useLegacy);
}
/// <summary>
/// 获取动态库导出函数并转换为指定的 Cdecl 委托。
/// </summary>
/// <typeparam name="TDelegate">带有 <see cref="UnmanagedFunctionPointerAttribute"/> 的委托类型。</typeparam>
/// <param name="exportName">官方 C ABI 导出函数名称。</param>
/// <returns>绑定到导出函数的托管委托。</returns>
public TDelegate GetDelegate<TDelegate>(string exportName) where TDelegate : Delegate
{
ThrowIfDisposed();
IntPtr symbol;
if (_isWindows)
{View on GitHub (pinned to be573f6f94)