言語翻訳情報を格納する .NET アセンブリを開発しました。VB6 アプリケーションで使用する必要があります。
アプリケーションを再コンパイルせずに翻訳情報を変更できるようにしたいと考えています。
翻訳は、LanguageServices と呼ばれる 2 つのファイルの部分クラスによって提供されます。
1 つのファイルは不変のライブラリ メソッドで、もう 1 つはすべて resx ファイルから自動生成されたプロパティであり、regx は言語翻訳情報のデータベースから生成されます。
これはすべて、異なるアプリケーションのそれぞれで使用できる形式にプログラムで「フラット化」できる翻訳の中央データベースを持つ必要性から生じました。
これで、この問題をバイパスして別の方法で解決できます。実際、自動生成されたプロパティのリストを取り除くだけで、問題は解決します。
私が興味を持っているのは、この問題をどのように解決できるかということです。
新しい翻訳ラベルをデータベースに追加すると (THIS WORD 内の THIS WORD が THAT WORD になります)、新しいプロパティがクラスに追加され、新しい公開プロパティが COM インターフェイスに追加されます。
プロパティは COM インターフェイスの途中に追加されるため、バイナリ互換性が失われます。C# コンパイラが部分クラスの動的部分に部分クラスの静的部分を接尾辞として追加するため、それらは途中で追加されます。私がする必要があるのは、それらを逆に連結するか、C# ファイル自体で順序を明示的に指定することです。クラスの静的部分に DispID を明示的に設定すればできると思っていましたが、そうではありませんでした。
ビルド プロセスによって生成される IDL ファイルのペアを次に示します。
新しいプロパティを追加する前の IDL は次のとおりです。
新しいプロパティが追加され、互換性が失われた後の IDL は次のとおりです。
正確な違いは、このビットが真ん中に押し込まれていることです:
[id(0x60020039), propget]
HRESULT Jn_ExactCaseMatch([out, retval] VARIANT_BOOL* pRetVal);
[id(0x6002003a), propget]
HRESULT Jn_Regex([out, retval] VARIANT_BOOL* pRetVal);
[id(0x6002003b), propget]
HRESULT Jn([out, retval] BSTR* pRetVal);
それが問題だと思います。メソッドの順序を変更することです。DispID を明示的に定義することで、順序をオーバーライドできると思いました (HRESULT Culture([in] ICultureInfo* pRetVal);
以降のすべての ID が 0 から始まることがわかります。
作成/生成された C# コードは次のとおりです。 ILanguageServices.cs: 自動生成されたインターフェイス。
[Guid("547a7f6e-eeda-4f77-94d0-2dd24f38ba58")]
public partial interface ILanguageServices
{
/// <summary>
///
/// </summary>
System.Boolean Offence_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean Offence_Regex { get; }
/// <summary>
///
/// </summary>
string Offence { get; }
/// <summary>
///
/// </summary>
System.Boolean Colour_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean Colour_Regex { get; }
/// <summary>
///
/// </summary>
string Colour { get; }
/// <summary>
///
/// </summary>
System.Boolean DebtManagementSystem_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean DebtManagementSystem_Regex { get; }
/// <summary>
///
/// </summary>
string DebtManagementSystem { get; }
/// <summary>
///
/// </summary>
System.Boolean DateOfContravention_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean DateOfContravention_Regex { get; }
/// <summary>
///
/// </summary>
string DateOfContravention { get; }
/// <summary>
///
/// </summary>
System.Boolean ContraventionDetails_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean ContraventionDetails_Regex { get; }
/// <summary>
///
/// </summary>
string ContraventionDetails { get; }
/// <summary>
///
/// </summary>
System.Boolean Income_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean Income_Regex { get; }
/// <summary>
///
/// </summary>
string Income { get; }
/// <summary>
///
/// </summary>
System.Boolean Hold_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean Hold_Regex { get; }
/// <summary>
///
/// </summary>
string Hold { get; }
/// <summary>
///
/// </summary>
System.Boolean CivilEnforcementOfficer_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean CivilEnforcementOfficer_Regex { get; }
/// <summary>
///
/// </summary>
string CivilEnforcementOfficer { get; }
/// <summary>
///
/// </summary>
System.Boolean PCNDebt_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean PCNDebt_Regex { get; }
/// <summary>
///
/// </summary>
string PCNDebt { get; }
/// <summary>
///
/// </summary>
System.Boolean OnHold_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean OnHold_Regex { get; }
/// <summary>
///
/// </summary>
string OnHold { get; }
/// <summary>
///
/// </summary>
System.Boolean DatePutOnHold_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean DatePutOnHold_Regex { get; }
/// <summary>
///
/// </summary>
string DatePutOnHold { get; }
/// <summary>
///
/// </summary>
System.Boolean HoldCode_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean HoldCode_Regex { get; }
/// <summary>
///
/// </summary>
string HoldCode { get; }
/// <summary>
///
/// </summary>
System.Boolean DateHoldExpires_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean DateHoldExpires_Regex { get; }
/// <summary>
///
/// </summary>
string DateHoldExpires { get; }
/// <summary>
///
/// </summary>
System.Boolean PutOnHoldByUserName_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean PutOnHoldByUserName_Regex { get; }
/// <summary>
///
/// </summary>
string PutOnHoldByUserName { get; }
/// <summary>
///
/// </summary>
System.Boolean CurrentState_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean CurrentState_Regex { get; }
/// <summary>
///
/// </summary>
string CurrentState { get; }
/// <summary>
///
/// </summary>
System.Boolean Vrm_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean Vrm_Regex { get; }
/// <summary>
///
/// </summary>
string Vrm { get; }
/// <summary>
///
/// </summary>
System.Boolean State_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean State_Regex { get; }
/// <summary>
///
/// </summary>
string State { get; }
/// <summary>
///
/// </summary>
System.Boolean CurrentStatechangedd2d2d4_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean CurrentStatechangedd2d2d4_Regex { get; }
/// <summary>
///
/// </summary>
string CurrentStatechangedd2d2d4 { get; }
/// <summary>
///
/// </summary>
System.Boolean SimonTest_ExactCaseMatch { get; }
/// <summary>
///
/// </summary>
System.Boolean SimonTest_Regex { get; }
/// <summary>
///
/// </summary>
string SimonTest { get; }
}
ILanguageServices_Static.cs: インターフェイスの不変部分
public partial interface ILanguageServices
{
[DispId(0)]
ICultureInfo Culture { get; set; }
[DispId(1)]
IResourceManager ResourceManager { get; }
[DispId(2)]
ICultureInfo[] GetCultures(System.Globalization.CultureTypes enCultureTypes);
[DispId(3)]
ICultureInfo GetCultureInfo(int LCID);
[DispId(4)]
ICultureInfo CurrentCulture { get; }
[DispId(5)]
string TranslateString(string rawString, bool searchInsideString);
[DispId(6)]
string TranslateString(string rawString);
}
考えてみれば、部分クラスじゃなくてもいいんじゃないかな。自動生成された部分を生成した xslt を変更して、静的部分を含めるだけです。別々に保管するのはちょうどよかったです。
いずれにせよ、それが機能しない理由と、COM インターフェイスをより厳密に制御する方法を誰か教えてもらえますか? メソッドを厳密に順序付けすることは、とても... ひどいようです。
ありがとう、
J1M.