6

Excel 用の VSTO リボン アドインを作成しており、視覚的なボタンを有効にするために使用するアプリケーションにワークブックの状態情報を保存しています。複数のワークブックが存在する可能性があることを考慮して、この状態オブジェクトを ThisAddIn クラスの辞書に格納しています。私の問題は、ハッシュを継続的に変更する COM ラッパーしか得られないため、ワークブックの一意のハッシュ/キー/Guid を取得する方法がわからないことです。十分に公平です、私はそれを完全に理解しています。

私が長い間使用してきた 1 つの解決策は、GUID を作成してワークブックの CustomDocumentProperties に格納し、それに基づいて状態をキーとしてマップすることでした。これは少なくとも機能しますが、ワークブックのコピーを作成して同じ Application インスタンスで開き、同じ GUID を持つワークブックが複数あると失敗します。

Workbook_Open イベントでこの Guid を更新できると思いました。しかし、それでもこれは危険な解決策のようです。

ここで見つけた 2 番目のソリューション: http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/04efa74d-83bd-434d-ab07-36742fd8410e/

だから私はその男のコードを使用して、これを作成しました:

public static class WorkbookExtensions
{
    public static IntPtr GetHashery(this msExcel.Workbook workbook)
    {
        IntPtr punk = IntPtr.Zero;
        try
        {
            punk = Marshal.GetIUnknownForObject(workbook);
            return punk;
        }
        finally
        {
            //Release to decrease ref count
            Marshal.Release(punk);
        }
    }
}

Application.ActiveWorkbook.

これは Workbook COM オブジェクトを参照する安全な方法ですか? 2 つのリボン アプリケーションが両方ともこのメソッドを使用して 1 つのブック GUID を取得するとしたらどうなるでしょうか。それらのアプリケーションの 1 つが状態オブジェクトでガベージ コレクターを実行し、ファイナライザーを呼び出して Marshal.FinalReleaseComObject(workbook) を呼び出したらどうなるでしょうか。他のリボン アプリが終了する前に FinalRelease を呼び出さないように、ワークブックの参照カウントを取得する方法はありますか? VSTO で Workbook COM オブジェクトをクリーンアップして、これらの他のアプリとの公平な関係を維持するためのベスト プラクティスは何ですか?

確かに、ワークブックの状態に基づいてボタンを有効にしたいと思ったのは私が初めてではありません。ここで Stack Overflow に関する他のいくつかの記事を見てきましたが、Workbook Guid ソリューションの助けになるものはありません。

私はリボン デザイナーを使用しており、Workbook Load および Deactivate イベントに接続しています。

事前に感謝します。すべての詳細が含まれていることを願っています。

4

2 に答える 2

6

IntPtr を long にキャストするだけでこれを解決しましたが、IntPtr の処分は私には影響しません。IntPtr を保存する必要はありません。本当に必要なのは、ブックに固有のものだけだからです。

次のコードを使用すると、ワークブック固有の状態情報を保存できるため、カスタム オブジェクト ワークブックの状態に基づいて、リボンのボタンの表示状態を更新できます。任意の情報をカスタム WorkbookState クラスに格納できますが、通常は、スプレッドシート自体に保持したくないセッション固有の情報になります。

別のワークブック拡張子:

public static class WorkbookExtensions
{
    public static long GetHashery(this msExcel.Workbook workbook)
    {
        if (workbook == null)
        {
            throw new ArgumentNullException("workbook");
        }

        IntPtr pUnknown = IntPtr.Zero;
        try
        {
            pUnknown = Marshal.GetIUnknownForObject(workbook);
            return pUnknown.ToInt64();
        }
        finally
        {
            // GetIUnknownForObject causes AddRef.
            if (pUnknown != IntPtr.Zero)
            {
                Marshal.Release(pUnknown);
            }
        }
    }
}

次に、VSTO/ExcelDna ThisAddIn クラスで、上記のメソッドを使用してすべてのブックの状態のマップを保存し、一意のブック ハッシュ キーを見つけます。

private Dictionary<long, WorkbookState> _workbookStates = new Dictionary<long, WorkbookState>();
public WorkbookState WorkbookState
{
    get
    {
        long hash = Application.ActiveWorkbook.GetHashery();
        WorkbookState state;
        if (!_workbookStates.TryGetValue(hash, out state))
        {
            state = _workbookStates[hash] = new WorkbookState();
        }
        return state;
    }
}

そしてもちろん、リボン アプリケーションのどこからでも WorkbookState にアクセスできるようになりました。ThisAddIn.WorkbookState

于 2014-02-06T16:32:29.687 に答える