修改数据库时 WiX 工具集自定义操作失败

Posted

技术标签:

【中文标题】修改数据库时 WiX 工具集自定义操作失败【英文标题】:WiX Toolset Custom Action Fails When Modifying Database 【发布时间】:2016-03-02 19:58:51 【问题描述】:

我一直在疯狂地试图弄清楚为什么视图没有更新。从我在网上看到的所有帖子中,我认为我做得对,但我不断收到 Null 错误。如果我尝试使用 session.Database.FilePath 以这种方式加载数据库,则表明 FilePath 为空。视图本身正在返回 Dummy Row,因此数据库就在那里。真是奇怪。

下面是属性

<Property Id="IIS_SITE" />

二进制和自定义操作

<CustomAction Id="UpdateComboBoxes" DllEntry="UpdateComboBoxes" BinaryKey="UpdateComboBoxes" Execute="immediate" Return="check" />
<Binary Id="UpdateComboBoxes" SourceFile="..\ProjectName.CustomActions\bin\Release\ProjectName.CustomActions.CA.dll"/>

安装 UI 序列

<InstallUISequence>
  <Custom Action="UpdateComboBoxes" Before="CostFinalize"></Custom>
</InstallUISequence>

控制

   <Control Id="IisSite" Type="ComboBox" Sorted="yes" ComboList="yes" Property="IIS_SITE" X="45" Y="85" Width="220" Height="18" >
      <ComboBox Property="IIS_SITE" >
        <ListItem Text="Dummy" Value="Dummy"/>
      </ComboBox>
    </Control>

自定义操作

     [CustomAction]
    public static ActionResult UpdateComboBoxes(Session session)
    
        session.Log("Begin Custom Action UpdateComboBoxes");
        try
        
            session.Log(string.Format("Database Location is: 0", session.Database.FilePath));
            var database = session.Database;
                using (var view = database.OpenView("SELECT * FROM ComboBox WHERE Property = 'IIS_SITE'"))
                

                    view.Execute();
                    session.Log("Executed view");

                    var isReadOnly = database.IsReadOnly;

                    session.Log(string.Format("Database is read only: 0", isReadOnly));
                    session.Log(string.Format("# of rows in ComboBox Table: 0",
                        view.Database.CountRows("ComboBox", "Property = 'IIS_SITE'")));

                    using (var serverManager = new ServerManager())
                    
                        session.Log("Accessed Server Manager");
                        var index = 1;
                        var rowIndex = 1;
                        session.Log(string.Format("Going through 0 sites", serverManager.Sites.Count));
                        foreach (var site in serverManager.Sites)
                        
                            if (!string.IsNullOrEmpty(site.Name))
                            
                                session.Log(string.Format("Site # 0 1", index, site.Name));
                                var record = session.Database.CreateRecord(4);
                                //Property
                                record.SetString(1, "IIS_SITE");
                                //Order
                                record.SetString(2, rowIndex.ToString());
                                //Value
                                record.SetString(3, site.Name);
                                //Text
                                record.SetString(4, site.Name);

                                session.Log(string.Format("Modifying the view for site # 0", index));
                                view.Modify(ViewModifyMode.InsertTemporary, record);
                            
                            session.Log("Incrementing index");
                            index++;
                            rowIndex++;
                        
                    

                    session.Log("Closing the view");
                
        
        catch (Exception e)
        

            session.Log(string.Format("ERROR in UpdateComboBoxes: 0", e.Message));
            session.Log(e.StackTrace);
            var inner = e.InnerException;
            if(inner != null)
            
                session.Log(string.Format("01", "\t", inner.Message));
                session.Log(string.Format("01", "\t", inner.StackTrace));
            
            while ((inner = inner.InnerException) != null)
            
                session.Log(string.Format("01", "\t", inner.Message));
                session.Log(string.Format("01", "\t", inner.StackTrace));
            
            return ActionResult.Failure;
        
        return ActionResult.Success;
    

我得到的错误:

MSI (c) (B0!F4) [14:46:40:369]:注:1:2259 2:3:4: UpdateComboBoxes 中的错误:函数在执行期间失败。 在 Microsoft.Deployment.WindowsInstaller.View.Modify(ViewModifyMode 模式,记录记录) 在 VideoQuestionInstaller.CustomActions.CustomActions.UpdateComboBoxes(会话会话) 自定义操作引发的异常: System.Reflection.TargetInvocationException:调用的目标已引发异常。 ---> System.NullReferenceException:对象引用未设置为对象的实例。 在 VideoQuestionInstaller.CustomActions.CustomActions.UpdateComboBoxes(会话会话) --- 内部异常堆栈跟踪结束 --- 在 System.RuntimeMethodHandle.InvokeMethod(对象目标,对象参数,签名 sig,布尔构造函数) 在 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(对象 obj,对象参数,对象参数) 在 System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags invokeAttr,Binder binder,Object 参数,CultureInfo 文化) 在 Microsoft.Deployment.WindowsInstaller.CustomActionProxy.InvokeCustomAction(Int32 sessionHandle, String entryPoint, IntPtr remotingDelegatePtr)

我查了一下,错误2259表示数据库更新失败,这很清楚,因为错误之前的最后一条日志是:修改站点#1的视图。

有没有人知道我做错了什么,以及为什么 ComboBox 数据库没有更新?

提前致谢!

【问题讨论】:

【参考方案1】:

没关系,我找到了问题所在。这是我修复它的方法:

我添加了另一个隐藏的控件,以便创建组合框表,而无需将假值放入我将要使用的实际组合框

    <Property Id="HIDDEN_IIS_SITE" />

    <Control Id="DummyComboBox" Hidden="yes" Type="ComboBox" Sorted="yes" ComboList="yes" Property="HIDDEN_IIS_SITE" X="45" Y="85" Width="220" Height="18" >
      <ComboBox Property="HIDDEN_IIS_SITE" >
        <ListItem Text="Dummy" Value="Dummy"/>
      </ComboBox>
    </Control>

然后我更改了自定义操作,使其获得现有行的实际数量,然后在添加记录时添加到数字中,以便使用订单的正确数字

    [CustomAction]
    public static ActionResult UpdateComboBoxes(Session session)
    
        session.Log("Begin Custom Action UpdateComboBoxes");
        try
        
            var database = session.Database;
                using (var view = database.OpenView("SELECT * FROM ComboBox WHERE Property = 'IIS_SITE'"))
                

                    view.Execute();
                    session.Log("Executed view");

                    var index = view.Database.CountRows("ComboBox", "Property = 'IIS_SITE'");

                    using (var serverManager = new ServerManager())
                    
                        foreach (var site in serverManager.Sites)
                        
                            if (!string.IsNullOrEmpty(site.Name))
                            
                                var record = session.Database.CreateRecord(4);
                                //Property
                                record.SetString(1, "IIS_SITE");
                                //Order
                                record.SetString(2, (++index).ToString());
                                //Value
                                record.SetString(3, site.Name);
                                //Text
                                record.SetString(4, site.Name);

                                view.InsertTemporary(record);

                                session.Log("Inserted new record");
                            
                        
                    
                    session.Log("Closing the view");
                
        
        catch (Exception e)
        

            session.Log(string.Format("ERROR in UpdateComboBoxes: 0", e.Message));
            session.Log(e.StackTrace);
            var inner = e.InnerException;
            if(inner != null)
            
                session.Log(string.Format("01", "\t", inner.Message));
                session.Log(string.Format("01", "\t", inner.StackTrace));
            
            while (inner != null && (inner = inner.InnerException) != null)
            
                session.Log(string.Format("01", "\t", inner.Message));
                session.Log(string.Format("01", "\t", inner.StackTrace));
            
            return ActionResult.Failure;
        
        return ActionResult.Success;
    

【讨论】:

以上是关于修改数据库时 WiX 工具集自定义操作失败的主要内容,如果未能解决你的问题,请参考以下文章

Wix Remove 自定义操作失败

WIX 自定义卸载操作失败

Wix 的 VC++ 自定义操作

Wix静默安装MSI我们可以停止创建目录吗

Wix - 自定义操作返回代码 - 处理

使用 WiX C#/.NET 4 自定义操作时出现错误 2896