10

シナリオ

Microsoft Office には 2 つのラッパーがあり、1 つは 2003 用、もう 1 つは 2007 用です。Microsoft Office の 2 つのバージョンを並べて実行することは「公式には不可能」であり、Microsoft によっても推奨されていないため、1 つは Office 2003 用で、もう 1 つは 2 つのボックスがあります。 Office 2007 を使用します。ラッパーは個別にコンパイルします。DLL はソリューションに含まれています。各ボックスには同じチェックアウトがありますが、Office 2003 または 2007 が「アンロード」されているため、その特定の DLL をコンパイルしようとしません。そうしないと、Office COM DLL が利用できないため、コンパイル時にエラーがスローされます。

.NET 2.0 と Visual Studio 2008 を使用しています。

事実

Microsoft は 2007 年に Office 2003 API を不思議なことに変更し、いくつかのメソッドの名前を変更したり変更したりして (ため息)、後方互換性をなくしたため、2 つのラッパーが必要です。各ビルド マシンには、ソリューションと 1 つの Office DLL がアクティブ化されています。例: Office 2003 を搭載したマシンでは、「Office 2007」DLL がアンロードされているため、コンパイルされていません。もう一方のボックスも同じアイデアですが、逆です。これはすべて、プログラミング目的で同じボックスに 2 つの異なる Office を入れることができないためです。(Microsoft によれば、技術的には 2 つの Office を一緒に使用できます) が、プログラミング用ではなく、いくつかの問題がないわけではありません。

問題

アプリケーションのバージョンを (たとえば 1.5.0.1 から 1.5.0.2 に) 変更する場合、DLL を再コンパイルしてアプリケーションの新しいバージョンに一致させる必要があります。Office ラッパーがソリューションに含まれているため、これは自動的に行われます。ラッパーはソリューションに含まれているため、APP バージョンを継承しますが、それを 2 回行ってから、他の DLL をインストーラーを作成するマシンに「コピー」する必要があります。(痛み…)

質問

「古い」にもかかわらず、どのバージョンのアプリケーションでも動作する DLL をコンパイルすることは可能ですか? マニフェストについて何か読んだことがありますが、マニフェストとやり取りする必要はありませんでした。任意のポインタをいただければ幸いです。

これの秘密の理由は、私たちが「何年にもわたって」ラッパーを変更しておらず、Microsoft の古い API も変更していないためです。それでも、リリースごとにアプリのバージョンに一致するように DLL を再コンパイルしています。2台のマシンに頼る代わりに、このプロセスを自動化したいと考えています。

依存関係があるため、プロジェクトから DLL を削除できません (どちらも削除できません)。

3 番目の「マスター ラッパー」を作成できますが、まだ考えていません。

何か案は?同じ要件を持つ他の誰か?

アップデート

明確化:

N 個のプロジェクトで 1 つのソリューションがあります。

「アプリケーション」+ Office11Wrapper.dll + Office12Wrapper.dll。

両方の「ラッパー」は、ソリューション内のアプリケーション + 他のライブラリ (データレイヤー、ビジネスレイヤー、フレームワークなど) の依存関係を使用します。

各ラッパーには、それぞれの Office パッケージ (2003 および 2007) の参照があります。

Office 12 がインストールされていない状態でコンパイルすると、Office12Wrapper.dll から Office 2007 ライブラリが見つからないというエラーが発生します。したがって、私が持っているのは、Office 2003 と Office 2007 の 2 つのビルド マシンです。完全な SVN の更新と各マシンでのコンパイルの後、「インストーラー」で office12.dll を使用して、ラッパーを「同じ」に対してコンパイルします。コード、同じバージョン".

注: Office 2007 ビルド マシンには、Office 2003 用のラッパーが「アンロード」されており、その逆もあります。

前もって感謝します。

4

5 に答える 5

19

.NET アセンブリ リゾルバーが実行時に参照アセンブリを見つけることができない場合 (この場合、アプリケーションがリンクされた特定のラッパー DLL バージョンを見つけることができません)、既定の動作は失敗し、基本的にアプリケーションをクラッシュさせます。ただし、この動作は AppDomain.AssemblyResolve イベントをフックすることでオーバーライドできます。このイベントは、参照されているアセンブリが見つからない場合に発生し、欠落しているアセンブリの代わりに別のアセンブリを使用する機会を提供します (互換性がある場合)。したがって、たとえば、自分でロードした古いバージョンのラッパー DLL に置き換えることができます。

これを行うために私が見つけた最良の方法は、イベントをフックするアプリケーションのメイン クラスに静的コンストラクターを追加することです。

using System.Reflection;

static Program()
{
    AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e)
    {
        AssemblyName requestedName = new AssemblyName(e.Name);

        if (requestedName.Name == "Office11Wrapper")
        {
            // Put code here to load whatever version of the assembly you actually have

            return Assembly.LoadFile("Office11Wrapper.DLL");
        }
        else
        {
            return null;
        }
    }
}

これをメイン アプリケーション クラスの静的コンストラクターに配置することで、コードがラッパー DLL 内の何かにアクセスしようとする前に実行されることが保証され、フックが事前に配置されます。

ポリシー ファイルを使用してバージョンのリダイレクトを行うこともできますが、これはより複雑になる傾向があります。

于 2008-11-12T16:19:00.650 に答える
2

TlbExp を使用して 2 つの相互運用アセンブリ (名前とアセンブリが異なる) を作成し、インターフェイス/ファクトリを使用して、独自のインターフェイスを介して 2 つに対してコーディングできますか? 相互運用 dll を取得したら、COM 依存関係は必要ありません (もちろん、テストなどは除きます)。

TlbImp にはバージョンの /asmversion があるため、ビルド スクリプトの一部として実行できます。しかし、これも必要だと確信しています。参照(ソリューションエクスプローラー)で「特定のバージョン」がfalseであることを確認してください。

また、役に立たないことはわかっていますが、C# 4.0dynamicおよび/または「PIA なし」がここで役立つ可能性があります (将来的には、おそらく)。

于 2008-11-10T13:19:15.477 に答える
2

あなたが述べたすべてに完全に従っているかどうかはわかりませんが、試してみましょう:

2 つ (?) のプロジェクトで 1 つのソリューションがあるようです。1 つは実際のアプリケーションで、もう 1 つは Office API のラッパーです。アプリケーションには、Office API ラッパーへのプロジェクト参照があります。私はこれまでオフィス向けにプログラミングしたことはありませんが、プログラミング API は、1 つのマシンに 1 つのバージョン (つまり、2003 または 2007、両方ではなく) しか搭載できない一般的なコンポーネントのようです。おそらくこれが問題の場所ですが、プロジェクト参照があるため、ラッパーが最初にコンパイルされ、アプリケーションの bin ディレクトリにコピーされます。ここで、アプリケーションはラッパーのビルドにリンクされます。これにより、アプリケーションのマニフェストは、実行時にそのバージョンのラッパーを明確に要求します。

別のソリューションにラッパーがあり、プロジェクトではなくコンパイル済みライブラリへの参照を追加した場合、アプリケーションを常にそのバージョンのラッパーにリンクすると、問題を回避できます。

もう 1 つの選択肢は、アセンブリ バインディング リダイレクトです。これはより高度で、独自の一連の問題がありますが、ここで読むことができます。

または、Marc のアイデアと同様に、インターフェイスを抽出していくつかの共通オブジェクトをフレームワーク ライブラリに取り込み、インターフェイスと共通オブジェクトに対してアプリケーションをコーディングすることもできます。次に、実行時にリフレクションを使用してアセンブリをロードし、必要なラッパーをインスタンス化します。

可能であれば、プロジェクトの依存関係を削除することが重要だと思います。ラッパーはかなり安定しており、変更されていないようです。それ以外の場合は、以前のバージョンへのリンクを要求することはありません。

于 2008-11-10T13:50:58.750 に答える
1

Office 2003 と 2007 を同じマシンに並べてインストールすることは間違いなく可能です。私たちの組織では、エンド ユーザーの実稼働ワークステーションでも実行しています。

そのリンクされた記事では、Microsoft は実際の使用ではこれを行わないことを推奨しています。しかし、あなたの場合、それは単一のビルド マシン用のように見えます。つまり、実際にはそのマシンでどちらのバージョンの Office も使用するつもりはありません。このコンテキストでは、サイド バイ サイド インストールが機能するかどうかを確認してみます。

私の仮定は間違っている可能性があり、すべての開発者のマシンに対してこれを実行しようとしています。その場合、この回答は無視してください:-)

于 2008-11-10T14:16:14.643 に答える
0

素敵な探偵!上記のコンセプトに基づいた実装をまとめてみましたが、素晴らしく機能します。

static Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
{
     string partialName = args.Name.Substring(0, args.Name.IndexOf(','));
     return Assembly.Load(new AssemblyName(partialName));
}

もちろん、強化の余地はありますが、これは私にとってはうまくいきます!

于 2009-06-16T17:12:51.617 に答える