0

我需要将调试/测试 App.config 文件中的几个路径更改为最终用户计算机上的最终主页。通过 Visual Studio 编辑安装程序项目时,我看到了 XML File Changes 选项,并且帮助表明我应该导入要更改的 xml 文件。

但...

有没有办法为 XML 文件导入项目的输出?如果我直接浏览到文件本身,我必须使用 Debug 或 Release 配置文件,这似乎很烦人。否则我可以使用基本的 App.config 但如果在构建时应用了任何转换,它们就会丢失。

那么我是坚持只浏览一个文件,还是可以像获取 .exe 文件一样获取“项目输出”?

4

3 回答 3

1

XML 文件更改是相当弱的茶。要执行您正在寻找的内容,您必须创建一个自定义操作来加载 .config 文件并在 InstallShield 之外对其进行更新。

如果您使用的是 2012 C# Wizard 项目类型,则选项应该是创建一个 .rul,以在 After Move Data 中捕获 OnEnd() 事件。通过 UseDLL 从 .rul 调用到 dll 并调用一个方法,该方法接受配置的目标路径和将值更新到的值。

以下是我正在测试的代码...使用 C# Wizard 项目类型,我添加了以下 InstallScript 规则来调用 C# dll:

function OnEnd()
string basePath;
BOOL bResult;
string dllPath;
OBJECT oAppConfig;
begin

dllPath = TARGETDIR ^ APPCONFIG_DLL;
try
    set oAppConfig = DotNetCoCreateObject(dllPath, "AppConfig.ConfigMgr", "");
catch
    MessageBox("Error Loading" + dllPath + ": "  + Err.Description, INFORMATION); 
    abort;
endcatch;

try
    basePath = "C:\\Program Files (x86)\\MyCompany\\Config Test\\";
    bResult = oAppConfig.ConfigureSettings(basePath + "appsettings.xml", basePath + "app.config", "someAppSection");
catch
    MessageBox("Error calling ConfigureSettings " + dllPath + " " + Err.Number + " " + Err.Description, INFORMATION);
endcatch;

end;

C#测试代码: public bool ConfigureSettings(string configFilePath, string targetAppConfigPath, string targetAppName) { bool completed = true;

        try
        {
            XmlDocument configFileDoc = new XmlDocument();
            configFileDoc.Load(configFilePath);

            string installerTargetFileDoc = targetAppConfigPath; // InstallShield's build process for Visual Studio solutions does not rename the app.config file - Awesome!
            System.IO.FileInfo fi = new System.IO.FileInfo(installerTargetFileDoc);
            if (fi.Exists == false) installerTargetFileDoc = "app.config";
            XmlDocument targetAppConfigDoc = new XmlDocument();
            targetAppConfigDoc.Load(installerTargetFileDoc);

            // ensure all required keys exist in the target .config file
            AddRequiredKeys(configFileDoc.SelectSingleNode("configuration/" + targetAppName + "/requiredKeys"), ref targetAppConfigDoc);

            // loop through each key in the common section of the configuration file
            AddKeyValues(configFileDoc.SelectSingleNode("configuration/common/appSettings"), ref targetAppConfigDoc);

            // loop through each key in the app specific section of the configuration file - it will override the standard configuration
            AddKeyValues(configFileDoc.SelectSingleNode("configuration/" + targetAppName + "/appSettings"), ref targetAppConfigDoc);

            // save it off
            targetAppConfigDoc.Save(targetAppConfigPath);
        }
        catch (Exception ex)
        {
            completed = false;
            throw ex;
        }
        return completed;
    }
    private void AddKeyValues(XmlNode configAppNodeSet, ref XmlDocument targetAppConfigDoc)
    {
        foreach (XmlNode configNode in configAppNodeSet.SelectNodes("add"))
        {
            XmlNode targetNode = targetAppConfigDoc.SelectSingleNode("configuration/appSettings/add[@key='" + configNode.Attributes["key"].Value + "']");
            if (targetNode != null)
            {
                targetNode.Attributes["value"].Value = configNode.Attributes["value"].Value;
            }
        }
    }
    private void AddRequiredKeys(XmlNode targetAppNodeSet, ref XmlDocument targetAppConfigDoc)
    {
        foreach (XmlNode targetNode in targetAppNodeSet.SelectNodes("key"))
        {
            // add the key if it doesn't already exist
            XmlNode appNode = targetAppConfigDoc.SelectSingleNode("configuration/appSettings/add[@key='" + targetNode.Attributes["value"].Value + "']");
            if (appNode == null)
            {
                appNode = targetAppConfigDoc.SelectSingleNode("configuration/appSettings");
                XmlNode newAddNode = targetAppConfigDoc.CreateNode(XmlNodeType.Element, "add", null);
                XmlAttribute newAddNodeKey = targetAppConfigDoc.CreateAttribute("key");
                newAddNodeKey.Value = targetNode.Attributes["value"].Value;
                XmlAttribute newAddNodeValue = targetAppConfigDoc.CreateAttribute("value");
                newAddNodeValue.Value = "NotSet";
                newAddNode.Attributes.Append(newAddNodeKey);
                newAddNode.Attributes.Append(newAddNodeValue);
                appNode.AppendChild(newAddNode);
            }
        }
    }

于 2012-06-21T00:34:53.637 回答
1

虽然它看起来应该可以工作,但 Installshield 无法正确理解项目输出(依赖项经常丢失,合并模块即使在它们不适用时也会重复),或者为您提供一种处理项目输出中单个文件的方法。

我有不少于 5 个关于使用项目输出的问题与他们一起打开的错误,他们的解决方法始终是“手动添加文件”。

如果您刚刚开始使用 install shield,我建议您尝试另一种选择。如果您必须使用它,要么向他们的支持团队抱怨这不起作用,并使用建议的解决方法,直到他们把它放在一起。

这可能不是您问题的“答案”,但希望在处理此产品中的损坏功能集时能帮助您保持理智。

于 2012-08-10T15:30:32.613 回答
0

您可以导入您想要的任何文件(通过浏览),并在您喜欢的任何运行时位置对其进行更改。我建议只投入您进行更改所需的最少金额;毕竟它是 XML 文件更改视图。这样,对文件的大多数更新都不会导致或需要对您的 XML 文件更改设置进行任何更改,无论它是如何包含的。

于 2012-05-03T23:54:30.803 回答