调用Marshal.StructureToPtr时抛出“类型库未注册”异常求助
异常解决方法:Typelib export: Type library is not registered (0x80131165)
问题根源
该异常是因为直接用Marshal.SizeOf和Marshal.StructureToPtr处理包含托管数组和未明确序列化规则的字符串的结构体时,.NET无法自动完成托管到非托管内存的转换,触发类型库导出失败(这类复杂嵌套的引用类型结构体无法通过默认类型库机制处理)。此外原结构体存在字段拼写错误,会导致参数长度赋值无效,加剧问题。
具体修复步骤
1. 修正结构体定义,添加非托管序列化规则
修改结构体为非托管兼容形式:用IntPtr替代托管数组,给字符串字段明确指定非托管类型:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct PLUGIN_PARAMETER_DATA { // 指定字符串转换为Unicode非托管字符串 [MarshalAs(UnmanagedType.LPWStr)] public string version; [MarshalAs(UnmanagedType.LPWStr)] public string name; [MarshalAs(UnmanagedType.LPWStr)] public string data; } [StructLayout(LayoutKind.Sequential)] public struct PLUGIN_DATA { // 修正原拼写错误(paramter → parameter) public int parameterDataLength; // 用IntPtr指向非托管内存中的参数数组 public IntPtr pluginParameterData; }
2. 手动分配非托管内存并复制数据
不能直接依赖Marshal自动处理数组,需要手动分配数组内存并逐个复制结构体:
// 初始化参数数组(修正JSON字符串的引号转义) var paramList = new[] { new PLUGIN_PARAMETER_DATA { Name = "StartingPlugin", Version = "1", Data = "BD9B5012-4B81-4DBA-876E-DD6829208F3A" }, new PLUGIN_PARAMETER_DATA { Name = "StartingPluginParameter", Version = "1", Data = "{ \"parameterModelVersion\":1,\"parameterModelJson\":\"{\\\"parameterData\\\":{\\\"star-rating\\\":5}}\"}" }, new PLUGIN_PARAMETER_DATA { Name = "StartingPluginPriority", Version = "1", Data = "1" } }; // 构建PLUGIN_DATA对象 PLUGIN_DATA pluginData = new PLUGIN_DATA(); pluginData.parameterDataLength = paramList.Length; // 分配参数数组的非托管内存:单个参数大小 × 参数数量 int singleParamSize = Marshal.SizeOf(typeof(PLUGIN_PARAMETER_DATA)); pluginData.pluginParameterData = Marshal.AllocHGlobal(singleParamSize * paramList.Length); // 逐个复制参数到非托管内存 IntPtr currentParamPtr = pluginData.pluginParameterData; foreach (var param in paramList) { Marshal.StructureToPtr(param, currentParamPtr, false); currentParamPtr = IntPtr.Add(currentParamPtr, singleParamSize); } // 分配PLUGIN_DATA的非托管内存并复制 int pluginDataSize = Marshal.SizeOf(typeof(PLUGIN_DATA)); IntPtr pluginDataBuff = Marshal.AllocHGlobal(pluginDataSize); Marshal.StructureToPtr(pluginData, pluginDataBuff, false);
3. 完善内存释放逻辑,避免泄漏
在finally块中释放所有分配的非托管内存,注意先释放数组内的字符串资源,再释放数组和结构体内存:
finally { // 释放参数数组的内存 if (pluginData.pluginParameterData != IntPtr.Zero) { int singleParamSize = Marshal.SizeOf(typeof(PLUGIN_PARAMETER_DATA)); IntPtr currentParamPtr = pluginData.pluginParameterData; for (int i = 0; i < pluginData.parameterDataLength; i++) { // 销毁结构体中的字符串非托管资源 Marshal.DestroyStructure(currentParamPtr, typeof(PLUGIN_PARAMETER_DATA)); currentParamPtr = IntPtr.Add(currentParamPtr, singleParamSize); } Marshal.FreeHGlobal(pluginData.pluginParameterData); } // 释放PLUGIN_DATA的内存 if (pluginDataBuff != IntPtr.Zero) { Marshal.FreeHGlobal(pluginDataBuff); } // 若有COPYDATASTRUCT的内存也需同步释放 if (copyDataBuff != IntPtr.Zero) { Marshal.FreeHGlobal(copyDataBuff); } }
内容的提问来源于stack exchange,提问作者cpdev
相关产品推荐
相关产品推荐

