WriteProfileString
16 ビット バージョンの Windows との互換性のためにのみ提供され ている を使用する従来の VB 6 アプリケーションがあります。
私はそれを機能的に同等の (正確なクローンを意味する) .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);
};
};
幸いなことに、Microsoft は、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
相互運用で確実に使用できるようにするには、メソッドにどの修飾子を適用する必要がありますか?