C# 如何将Excel VSTO的程序集位置分配给安装?

C# 如何将Excel VSTO的程序集位置分配给安装?,c#,installation,vsto,C#,Installation,Vsto,我正在创建一个用C#编写的文档级工作簿/模板,并使用VSTO安装程序部署代码。安装项目后,我拥有电子表格的全部功能,但是,当我将已安装的工作表保存或复制到安装文件夹外的另一个路径时,我收到以下错误: 详情如下: Name: From: file:///C:/Users/Kronos/Desktop/ExcelTemplate1.vsto ************** Exception Text ************** System.Deployment.Application.De

我正在创建一个用C#编写的文档级工作簿/模板,并使用VSTO安装程序部署代码。安装项目后,我拥有电子表格的全部功能,但是,当我将已安装的工作表保存或复制到安装文件夹外的另一个路径时,我收到以下错误:

详情如下:

Name: 
From: file:///C:/Users/Kronos/Desktop/ExcelTemplate1.vsto

************** Exception Text **************
System.Deployment.Application.DeploymentDownloadException: Downloading file:///C:/Users/Kronos/Desktop/ExcelTemplate1.vsto did not succeed. ---> System.Net.WebException: Could not find file 'C:\Users\Kronos\Desktop\ExcelTemplate1.vsto'. ---> System.Net.WebException: Could not find file 'C:\Users\Kronos\Desktop\ExcelTemplate1.vsto'. ---> System.IO.FileNotFoundException: Could not find file 'C:\Users\Kronos\Desktop\ExcelTemplate1.vsto'.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean useAsync)
   at System.Net.FileWebStream..ctor(FileWebRequest request, String path, FileMode mode, FileAccess access, FileShare sharing, Int32 length, Boolean async)
   at System.Net.FileWebResponse..ctor(FileWebRequest request, Uri uri, FileAccess access, Boolean asyncHint)
   --- End of inner exception stack trace ---
   at System.Net.FileWebResponse..ctor(FileWebRequest request, Uri uri, FileAccess access, Boolean asyncHint)
   at System.Net.FileWebRequest.GetResponseCallback(Object state)
   --- End of inner exception stack trace ---
   at System.Net.FileWebRequest.EndGetResponse(IAsyncResult asyncResult)
   at System.Net.FileWebRequest.GetResponse()
   at System.Deployment.Application.SystemNetDownloader.DownloadSingleFile(DownloadQueueItem next)
   --- End of inner exception stack trace ---
   at Microsoft.VisualStudio.Tools.Applications.Deployment.ClickOnceAddInDeploymentManager.GetManifests(TimeSpan timeout)
   at Microsoft.VisualStudio.Tools.Applications.Deployment.ClickOnceAddInDeploymentManager.InstallAddIn()
我意识到这是由于未正确引用
.VSTO
.manifest
&
.DLL
文件,因为Excel电子表格不再位于安装路径中。执行此操作后,我可以通过更改
.xlsx
文件中复制/保存的Excels
custom.xml
文件来手动修复此问题:

name="_AssemblyLocation"><vt:lpwstr>ExcelTemplate1.vsto|ca022788-e7c0-41d8-b8ae-2c0ba9edbbf8|vstolocal

没用。

您需要按照您参考的中概述的说明进行操作,只需稍微多做一点。然而,这有点混乱,文章中有一个错误。希望这将有助于澄清:

您需要定义一个与本文提供的类似的用户脚本 在本文中有一个包含项目示例的文件。从那里,您可以针对该cs项目的输出引用您的
自定义操作。创建一个新的CS类库项目,复制以下特定于解决问题的用户脚本:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using Microsoft.VisualStudio.Tools.Applications;
using Microsoft.VisualStudio.Tools.Applications.Runtime;
using System.IO;
using System.Windows.Forms;

namespace AddCustomizationCustomAction
{
    [RunInstaller(true)]
    public partial class AddCustomization : System.Configuration.Install.Installer
    {
        //Note: you'll have to get the Guid from your specific project in order for it to work.  The MSDN article show you how.
        static readonly Guid SolutionID = new Guid("20cb4d1d-3d14-43c9-93a8-7ebf98f50da5");

        public override void Install(IDictionary stateSaver)
        {
            string[] nonpublicCachedDataMembers = null;


            // Use the following for debugging during the install
            //string parameters = "Parameters in Context.Paramters:";
            //foreach (DictionaryEntry parameter in Context.Parameters)
            //{
            //    parameters = parameters + "\n" + parameter.Key + ":" + parameter.Value;
            //}

            //MessageBox.Show(parameters);

            //MessageBox.Show("total items in parameters: " + Context.Parameters.Count);
            //MessageBox.Show("Document Manifest Location:" + Context.Parameters["deploymentManifestLocation"]);

            Uri deploymentManifestLocation = null;
            if (Uri.TryCreate(
                Context.Parameters["deploymentManifestLocation"],
                UriKind.RelativeOrAbsolute,
                out deploymentManifestLocation) == false)
            {
                throw new InstallException(
                    "The location of the deployment manifest " +
                    "is missing or invalid.");
            }
            string documentLocation =
                Context.Parameters["documentLocation"];
            if (String.IsNullOrEmpty(documentLocation))
            {
                throw new InstallException(
                    "The location of the document is missing.");
            }
            string assemblyLocation =
                Context.Parameters["assemblyLocation"];
            if (String.IsNullOrEmpty(assemblyLocation))
            {
                throw new InstallException(
                    "The location of the assembly is missing.");
            }

            // use the following for debugging
            MessageBox.Show(documentLocation);

            if (ServerDocument.IsCustomized(documentLocation))
            {
                ServerDocument.RemoveCustomization(documentLocation);
            }
            ServerDocument.AddCustomization(
                documentLocation,
                assemblyLocation,
                SolutionID,
                deploymentManifestLocation,
                false,
                out nonpublicCachedDataMembers);
            stateSaver.Add("documentlocation", documentLocation);
            base.Install(stateSaver);
        }

        public override void Commit(IDictionary savedState)
        {
            base.Commit(savedState);
        }

        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);
        }

        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);
        }

    }
}
这将覆盖安装程序的安装过程。
base.Install(stateSaver)
调用代码的其余部分继续正常安装

MSDN文章中的错误: 文章说,在安装自定义操作的
CustomActionData
中使用以下内容:

/assemblyLocation="[TARGETDIR]<YourProjectName>.dll"/deploymentManifestLocation="[TARGETDIR]<YourProjectName>.vsto"/documentLocation="[TARGETDIR]<YourProjectName>.xltx"
/assemblyLocation=“[TARGETDIR].dll”/deploymentManifestLocation=“[TARGETDIR].vsto”/documentLocation=“[TARGETDIR].xltx”
但是,应该是这样的(注意参数之间的空格):

/assemblyLocation=“[TARGETDIR].dll”/deploymentManifestLocation=“[TARGETDIR].vsto”/documentLocation=“[TARGETDIR].xltx”

这应该可以解决您的问题,但是在重新构建安装程序之前,请确保将对Excel项目的任何更改重新构建到发布版本,因为它指向的是发布版本,而不是调试版本。

虽然James Mertz的答案很正确,但它也有点过时(尽管它只是在我拔了一天头发后救了我一命)。对于较新版本的Visual Studio,此部分应用程序构建的说明已移至。我建议你去读,或者你可以读我的《悬崖笔记》版本如下:

应在现有解决方案中作为新项目构建的新控制台应用程序。
Program.cs
应该如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Tools.Applications.Runtime;
using Microsoft.VisualStudio.Tools.Applications;

namespace SetExcelDocumentProperties
{
    class Program
    {
        static void Main(string[] args)
        {
            string assemblyLocation = "";
            Guid solutionID = new Guid();
            Uri deploymentManifestLocation = null;
            string documentLocation = "";
            string[] nonpublicCachedDataMembers = null;

            for (int i = 0; i <= args.Count() - 1; i++)
            {
                Console.WriteLine(args[i]);
                string[] oArugment = args[i].Split('=');

                switch (oArugment[0])
                {
                    case "/assemblyLocation":
                        assemblyLocation = oArugment[1];
                        break;
                    case "/deploymentManifestLocation":
                        if (!Uri.TryCreate(oArugment[1], UriKind.Absolute, out deploymentManifestLocation))
                        {
                            Console.WriteLine("Error creating URI");
                        }
                        break;
                    case "/documentLocation":
                        documentLocation = oArugment[1];
                        break;
                    case "/solutionID":
                        solutionID = Guid.Parse(oArugment[1]);
                        break;
                }
            }
            try
            {
                ServerDocument.RemoveCustomization(documentLocation);
                ServerDocument.AddCustomization(documentLocation, assemblyLocation,
                                            solutionID, deploymentManifestLocation,
                                            true, out nonpublicCachedDataMembers);

            }
            catch (System.IO.FileNotFoundException)
            {
                Console.WriteLine("The specified document does not exist.");
            }
            catch (System.IO.IOException)
            {
                Console.WriteLine("The specified document is read-only.");
            }
            catch (InvalidOperationException ex)
            {
                Console.WriteLine("The customization could not be removed.\n" +
                    ex.Message);
            }
            catch (DocumentNotCustomizedException ex)
            {
                Console.WriteLine("The document could not be customized.\n" +
                    ex.Message);
            }
        }
    }
}
必须更改dll、vsto、工作簿和解决方案id的设置。解决方案ID可以在
.csproj
文件中找到(在文件资源管理器中找到并在记事本中打开)

现在你是金色的。应用程序成功安装后,将启动此控制台应用程序,并将工作簿的
manifestLocation
更改为安装路径,而不是当前工作簿的相对路径


如果安装人员在其计算机上没有管理员权限,而您正在将其安装到Program Files目录中,您可能会发现,在执行此步骤之前,他们可以安装并运行,但在执行此步骤之后,他们无法安装并运行。这是因为工作簿在该位置是只读的。在这种情况下,您必须选择另一个位置安装应用程序(AppDataLocal是一个不错的选择)。

感谢您在此处分享信息,特别是MSDN文章中有关错误的信息。我正准备把我的脚穿过这个屏幕。(微软不会校对和检查他们的资料的准确性???)@StevenC.Britton欢迎您,但是我建议您使用install shield安装。它的使用和设置更容易一些。
/assemblyLocation="[TARGETDIR]<YourProjectName>.dll"/deploymentManifestLocation="[TARGETDIR]<YourProjectName>.vsto"/documentLocation="[TARGETDIR]<YourProjectName>.xltx"
/assemblyLocation="[TARGETDIR]<YourProjectName>.dll" /deploymentManifestLocation="[TARGETDIR]<YourProjectName>.vsto" /documentLocation="[TARGETDIR]<YourProejctName>.xltx"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Tools.Applications.Runtime;
using Microsoft.VisualStudio.Tools.Applications;

namespace SetExcelDocumentProperties
{
    class Program
    {
        static void Main(string[] args)
        {
            string assemblyLocation = "";
            Guid solutionID = new Guid();
            Uri deploymentManifestLocation = null;
            string documentLocation = "";
            string[] nonpublicCachedDataMembers = null;

            for (int i = 0; i <= args.Count() - 1; i++)
            {
                Console.WriteLine(args[i]);
                string[] oArugment = args[i].Split('=');

                switch (oArugment[0])
                {
                    case "/assemblyLocation":
                        assemblyLocation = oArugment[1];
                        break;
                    case "/deploymentManifestLocation":
                        if (!Uri.TryCreate(oArugment[1], UriKind.Absolute, out deploymentManifestLocation))
                        {
                            Console.WriteLine("Error creating URI");
                        }
                        break;
                    case "/documentLocation":
                        documentLocation = oArugment[1];
                        break;
                    case "/solutionID":
                        solutionID = Guid.Parse(oArugment[1]);
                        break;
                }
            }
            try
            {
                ServerDocument.RemoveCustomization(documentLocation);
                ServerDocument.AddCustomization(documentLocation, assemblyLocation,
                                            solutionID, deploymentManifestLocation,
                                            true, out nonpublicCachedDataMembers);

            }
            catch (System.IO.FileNotFoundException)
            {
                Console.WriteLine("The specified document does not exist.");
            }
            catch (System.IO.IOException)
            {
                Console.WriteLine("The specified document is read-only.");
            }
            catch (InvalidOperationException ex)
            {
                Console.WriteLine("The customization could not be removed.\n" +
                    ex.Message);
            }
            catch (DocumentNotCustomizedException ex)
            {
                Console.WriteLine("The document could not be customized.\n" +
                    ex.Message);
            }
        }
    }
}
/assemblyLocation="[INSTALLDIR]ExcelWorkbook.dll" /deploymentManifestLocation="[INSTALLDIR]ExcelWorkbook.vsto" /documentLocation="[INSTALLDIR]ExcelWorkbook.xlsx" /solutionID="Your Solution ID"