.NET7传递UDT类型SAFEARRAY至COM函数时触发TLBX_E_LIBNOTREGISTERED异常原因
异常详情
System.Runtime.InteropServices.COMException
HResult=0x80131165
Message=Typelib export: Type library is not registered. (0x80131165)
Source=System.Private.CoreLib
StackTrace:
at System.StubHelpers.MngdSafeArrayMarshaler.ConvertSpaceToNative(IntPtr pMarshalState, Object& pManagedHome, IntPtr pNativeHome)
at IServer.ComputePi(ExampleStruct[] param)
at ManagedClient.Program.Main(String[] _)
异常场景特征
- 仅在.NET 7环境下触发,.NET Framework或原生客户端无此问题
- 结构体不用于SAFEARRAY或VARIANT时,不会出现该异常
- 目标类型库已注册,但通过ProcMon观察到客户端在查找非目标类型库
相关定义
IDL中的结构体定义
typedef [uuid(7C88E088-A91F-4AE0-B7BA-B1594CCFCD7E), version(1.0)] struct ExampleStruct { long x; } ExampleStruct;
COM函数参数定义
HRESULT ComputePi([in] SAFEARRAY(ExampleStruct) param);
问题
请问该异常出现的原因是什么?
这个问题的核心是**.NET 7的SAFEARRAY封送逻辑处理VT_RECORD类型UDT时,未正确复用已注册的目标类型库,反而尝试导出临时类型库导致路径错误**,具体细节如下:
.NET版本间的封送逻辑差异
- .NET Framework处理UDT的SAFEARRAY时,直接调用已注册的COM类型库信息完成封送
- .NET 7的
MngdSafeArrayMarshaler在处理VT_RECORD类型时,会尝试将托管结构体导出为临时类型库,但未关联IDL中定义的结构体UUID(7C88E088-A91F-4AE0-B7BA-B1594CCFCD7E)和版本信息
注册表访问异常的根源
程序查找非目标类型库,是因为.NET 7导出临时类型库时生成了新的临时GUID,而非使用IDL中指定的结构体标识,导致注册表查询路径错误,触发“类型库未注册”的异常触发条件的关联性
当结构体不用于SAFEARRAY或VARIANT时,.NET 7使用常规结构体封送逻辑,无需导出临时类型库,因此不会触发该异常
内容的提问来源于stack exchange,提问作者Mitch

