我有一个旧版 VB 6 应用程序,WriteProfileString
它仅用于与 16 位版本的 Windows 兼容。
我正在将其迁移到功能等效(即完全克隆)的.NET 应用程序中。这需要我使用TlbImp.exeWriteProfileString
从COM 对象的 TLB 文件生成一个 Interop 程序集。这是一项要求,不能使用 P/Invoke。
当我这样做时,TlbImp.exe 会生成一个空程序集。
WriteProfileString
具有以下 IDL:
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: WriteProfileString.tlb
[
uuid(13C9AF40-856A-101B-B9C2-04021C007003),
version(0.0),
helpstring("WritePrivateProfileStringW API Type Library")
]
library igrWriteProfileStringW
{
// TLib : // Forward declare all types defined in this typelib
[
dllname("KERNEL32"),
helpstring("KERNEL API Calls")
]
module KernelAPI {
[entry("WritePrivateProfileStringW"), helpstring("Sets the value of a .ini file setting.")]
long _stdcall WritePrivateProfileStringW(
[in] BSTR lpApplicationName,
[in] BSTR lpKeyName,
[in] BSTR lpString,
[in] BSTR lpFileName);
};
};
幸运的是,微软已经开源了名为 TlbImp2.exe 的下一个版本的 TlbImp.exe。
我能够通过代码进行调试,发现 TlbImp.exe 和 TlbImp2.exe 都没有从模块中导入方法。为了让 TlbImp2.exe 导出模块的静态方法,我不得不修改代码。
我不得不更改ConvModule.cs文件:
public override void OnCreate()
{
//
// Avoid duplicate creation
//
if (m_type != null)
return;
// Create constant fields for the module
ConvCommon.CreateConstantFields(m_info, RefNonAliasedTypeInfo, m_typeBuilder, ConvType.Module);
ConvCommon.CreateMethodsForModule(m_info, RefNonAliasedTypeInfo, m_typeBuilder, ConvType.Module);
m_type = m_typeBuilder.CreateType();
}
并将以下方法添加到ConvCommon.cs:
public static void CreateMethodsForModule(ConverterInfo info, TypeInfo type, TypeBuilder typeBuilder, ConvType convType)
{
using (TypeAttr attr = type.GetTypeAttr())
{
int cVars = attr.cFuncs;
for (int n = 0; n < cVars; ++n)
{
using (var func = type.GetFuncDesc(n))
{
string methodName = type.GetDocumentation(func.memid);
CreateMethod(new InterfaceInfo(info, typeBuilder, true, type, attr, false), new InterfaceMemberInfo(info, type, n, methodName, methodName, InterfaceMemberType.Method, TypeLibTypes.Interop.INVOKEKIND.INVOKE_FUNC, func.memid, func, null), CreateMethodMode.InterfaceMethodMode);
}
}
}
}
所以现在它正确地导出了方法,但我仍然想知道为什么它没有首先导出这些方法。
这是导出程序集的代码:
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace igrWriteProfileStringW
{
public static class KernelAPI
{
[DispId(1610612736)]
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
public abstract int WritePrivateProfileStringW([MarshalAs(UnmanagedType.BStr), In] string lpApplicationName, [MarshalAs(UnmanagedType.BStr), In] string lpKeyName, [MarshalAs(UnmanagedType.BStr), In] string lpString, [MarshalAs(UnmanagedType.BStr), In] string lpFileName);
}
}
它生成一个带有抽象成员的静态类。这没有任何意义。当然,我可以更改代码以不同方式导出它,但为什么 TlbImp2.exe 首先要这样做?
我假设它以这种方式导出它,因为它导出了模块的常量。我对吗?我应该对该方法应用哪些修饰符WriteProfileString
以确保它可以与互操作一起使用?