using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Security;
using Microsoft.VisualStudio.Tools.Applications.Runtime;

namespace CustomAction
{
    [RunInstaller( true )]
    public partial class ExcelImportInstaller1 : Installer
    {
        private string groupName = "ExcelImportTemplate";

        public ExcelImportInstaller1()
        {
            InitializeComponent();
        }

        // インストール処理のオーバーライト関数
        // マニフェストの設定処理を追加
        public override void Install( System.Collections.IDictionary stateSaver )
        {
            SetupManifest();               /* 独自に追加された処理*/
            AddCASecurityPolicy();
            base.Install( stateSaver );
        }

        // マニフェストの設定処理
        private void SetupManifest()
        {
            // インストールディレクトリの取得
            string targetDir = this.Context.Parameters["targetdir"];
            // ドキュメント名(Excelブック) の取得
            string documentName = this.Context.Parameters["documentname"];
            // アセンブリ名 (DLL) の取得
            string assemblyName = this.Context.Parameters["assemblyname"];

            // VSTO のサーバドキュメントオブジェクトを取得
            ServerDocument serverDocument = new ServerDocument( 
                System.IO.Path.Combine( targetDir, documentName ), 
                System.IO.FileAccess.ReadWrite );

            // マニフェストを取得し、AssemblyPath 属性を変更
            try {
                serverDocument.AppManifest.Dependency.AssemblyPath =
                    System.IO.Path.Combine( targetDir, assemblyName );
                serverDocument.Save();
            }
            finally {
                if ( serverDocument != null ) {
                    serverDocument.Close();
                }
            }
        }

        // コードアクセスセキュリティを追加する処理
        private void AddCASecurityPolicy()
        {
            string insdirTxt = this.Context.Parameters["targetdir"];
            string accessUrl = insdirTxt.Substring( 0, insdirTxt.Length - 1 ) + "*";

            // User レベルのコードグループのルート (All_Code) を取得
            System.Collections.IEnumerator polLevEnum = SecurityManager.PolicyHierarchy();
            while ( polLevEnum.MoveNext() ) {
                if ( ((System.Security.Policy.PolicyLevel)polLevEnum.Current).Label == "User" ) {
                    break;
                }
            }

            System.Security.Policy.PolicyLevel polLev = (System.Security.Policy.PolicyLevel)polLevEnum.Current;
            System.Security.Policy.UnionCodeGroup allGroup = (System.Security.Policy.UnionCodeGroup)polLev.RootCodeGroup;

            // 新しいコードグループ (Setup_Test) を追加
            PermissionSet permSet = polLev.GetNamedPermissionSet( "FullTrust" );
            System.Security.Policy.UrlMembershipCondition urlCond = new System.Security.Policy.UrlMembershipCondition( accessUrl );
            System.Security.Policy.UnionCodeGroup newGroup = new System.Security.Policy.UnionCodeGroup( urlCond, new System.Security.Policy.PolicyStatement( permSet ) );

            newGroup.Name = groupName;
            allGroup.AddChild( newGroup );

            // セキュリティポリシーを保存
            SecurityManager.SavePolicy();
        }

        // アンインストール処理のオーバーライト関数
        // インストール時に追加したコードグループを削除
        public override void Uninstall( System.Collections.IDictionary savedState )
        {
            RemoveCASecurityPolicy();
            base.Uninstall( savedState );
        }

        // コードグループを削除する処理
        private void RemoveCASecurityPolicy()
        {
            // “User”レベルのコードグループのルートを取得
            System.Collections.IEnumerator polLevEnum = SecurityManager.PolicyHierarchy();
            while ( polLevEnum.MoveNext() ) {
                if ( ((System.Security.Policy.PolicyLevel)polLevEnum.Current).Label == "User" )
                    break;
            }

            System.Security.Policy.PolicyLevel polLev = (System.Security.Policy.PolicyLevel)polLevEnum.Current;
            System.Security.Policy.UnionCodeGroup allGroup = (System.Security.Policy.UnionCodeGroup)polLev.RootCodeGroup;

            // 削除する対象のコードグループを取得して削除実行
            System.Collections.IEnumerator childGroupEnum = allGroup.Children.GetEnumerator();
            while ( childGroupEnum.MoveNext() ) {
                System.Security.Policy.CodeGroup childGroup;
                childGroup = (System.Security.Policy.CodeGroup)childGroupEnum.Current;
                if ( childGroup.Name == groupName ) {
                    allGroup.RemoveChild( childGroup );
                    SecurityManager.SavePolicy();
                    break;
                }
            }
        }
    }
}
