0

WriteProfileString16 ビット バージョンの 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相互運用で確実に使用できるようにするには、メソッドにどの修飾子を適用する必要がありますか?

4

2 に答える 2

1

すべての COM フープをジャンプするよりも、ネイティブ API を直接使用する方が簡単です。

pinovke.netから:

[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool WritePrivateProfileString(string lpAppName,
   string lpKeyName, string lpString, string lpFileName);
于 2013-08-11T11:11:20.287 に答える
0

タイプ ライブラリは、Tlbimp.exe がサポートする宣言のスーパー セットをサポートします。DLL からのエクスポートを宣言する機能はあまり使用されません。タイプ ライブラリは、COM 宣言をエクスポートするための最も重要な手段です。

この問題を解決するために Tlbimp でできることはほとんどありません。代替手段は非常に単純なので、解決しようとするべきでもありません。pinvoke 宣言を書くだけです。

次のステップを検討してください。Read/WritePrivateProfileString() は、Windows に組み込まれている重いレガシー appcompat により、実行時の動作が非常に悪くなります。1 つの INI パラメータの読み取りには、約 50 ミリ秒かかります。それらのうちの 20 を読んだら、何も役に立たずに起動時間を吹き飛ばしたことになります。また、非常に損失が多く、テキスト ファイルのエンコーディングに完全に依存しません。通常、組み込みの .NET サポートをライブラリの設定に使用することはできませんが、XML ファイルは優れた代替手段です。

于 2013-08-11T11:13:24.280 に答える