MsiGetSummaryInformation 始终返回无效参数错误

发布于 2024-09-16 16:24:48 字数 2514 浏览 1 评论 0原文

我正在尝试设置 模板摘要信息流中的属性,但无论我做什么,它都会失败。我可以从句柄读取该属性,但无法将其写回。

我想生成 MSI 的多语言副本,该副本是用英语构建的(烛光和灯光)。我能够替换所有表中所有相应的翻译数据;我唯一无法更改的是上面的 Template 属性。

我已经尝试了所有可以用来传递新字符串值的方法,但它总是说参数无效。 这是我用来执行相同操作的函数 (C#):

public Boolean ChangeTemplateSummaryProperty(String strLangID) {
IntPtr hSIHandle;
if (MsiError.Success == MsiInterop.MsiGetSummaryInformation(IntPtr.Zero, m_strMSIPath, 1, out hSIHandle))
{
    VariantType vtType = VariantType.LPStr;
    int iVal = 0;
    FILETIME oFileTime;
    oFileTime.HighDateTime = 0;
    oFileTime.LowDateTime = 0;

    int iValSz = 0;
    MsiError err = MsiInterop.MsiSummaryInfoGetProperty(hSIHandle, (uint)(SummaryInformationStreamProperty.Template),
                            out vtType, out iVal, out oFileTime, String.Empty, ref iValSz);
    String strValue = new String('l', ++iValSz);

    if (err == MsiError.MoreData)
    {
        err = MsiInterop.MsiSummaryInfoGetProperty(hSIHandle, (uint)(SummaryInformationStreamProperty.Template),
                                out vtType, out iVal, out oFileTime, strValue, ref iValSz);

    }
    else
    {
        Logger.LogError("Failed to get SummaryInformationStreamProperty.Template... err = " + err);
    }
    //I get the correct value here. as ";1033\0"
    Logger.LogInfo("SummaryInformationStreamProperty.Template: " + strValue);

    char[] arrNV = new char[strLangID.Length+2];
    arrNV[0] = ';';
    for (int i = 1; i < strLangID.Length + 1; i++) {
        arrNV[i] = strLangID[i-1];
    }
    arrNV[strLangID.Length+1] = '\0';
    String strNewVal = new String(arrNV);

    //tried this, but fails.
    //string strNV = ";";
    //string strNV2 = strNV.Insert(1, strLangID);
    //strNV2 = strNV2.Insert(strLangID.Length + 1, "\0");

    err = MsiInterop.MsiSummaryInfoSetProperty(hSIHandle, (uint)(SummaryInformationStreamProperty.Template),
                                vtType, iVal, oFileTime, strNewVal);
    if (err != MsiError.NoError)
    {
        Logger.LogError("Failed to set SummaryInformationStreamProperty.Template... err = " + err);
        MsiInterop.MsiSummaryInfoPersist(hSIHandle);
        MsiInterop.MsiCloseHandle(hSIHandle);
        return false;
    }
    MsiInterop.MsiSummaryInfoPersist(hSIHandle);
    MsiInterop.MsiCloseHandle(hSIHandle);
}
else
{
    Logger.LogError("Failed to MsiGetSummaryInformation...");
    return false;
}
return true;
}

I am trying to set the Template property in the Summary Information Stram but whatever I do, it fails. I can read the property from the handle but can't write it back.

I want to generate multilingual copies of the MSI which is built (candled and light) in English. I am able to replace all the respective translated data in all the tables; the only thing I can not change is the Template property above.

I have tried all the ways I can use to pass the new String value, but it always says invalid parameter.
Here's the function I am using to do the same (C#):

public Boolean ChangeTemplateSummaryProperty(String strLangID) {
IntPtr hSIHandle;
if (MsiError.Success == MsiInterop.MsiGetSummaryInformation(IntPtr.Zero, m_strMSIPath, 1, out hSIHandle))
{
    VariantType vtType = VariantType.LPStr;
    int iVal = 0;
    FILETIME oFileTime;
    oFileTime.HighDateTime = 0;
    oFileTime.LowDateTime = 0;

    int iValSz = 0;
    MsiError err = MsiInterop.MsiSummaryInfoGetProperty(hSIHandle, (uint)(SummaryInformationStreamProperty.Template),
                            out vtType, out iVal, out oFileTime, String.Empty, ref iValSz);
    String strValue = new String('l', ++iValSz);

    if (err == MsiError.MoreData)
    {
        err = MsiInterop.MsiSummaryInfoGetProperty(hSIHandle, (uint)(SummaryInformationStreamProperty.Template),
                                out vtType, out iVal, out oFileTime, strValue, ref iValSz);

    }
    else
    {
        Logger.LogError("Failed to get SummaryInformationStreamProperty.Template... err = " + err);
    }
    //I get the correct value here. as ";1033\0"
    Logger.LogInfo("SummaryInformationStreamProperty.Template: " + strValue);

    char[] arrNV = new char[strLangID.Length+2];
    arrNV[0] = ';';
    for (int i = 1; i < strLangID.Length + 1; i++) {
        arrNV[i] = strLangID[i-1];
    }
    arrNV[strLangID.Length+1] = '\0';
    String strNewVal = new String(arrNV);

    //tried this, but fails.
    //string strNV = ";";
    //string strNV2 = strNV.Insert(1, strLangID);
    //strNV2 = strNV2.Insert(strLangID.Length + 1, "\0");

    err = MsiInterop.MsiSummaryInfoSetProperty(hSIHandle, (uint)(SummaryInformationStreamProperty.Template),
                                vtType, iVal, oFileTime, strNewVal);
    if (err != MsiError.NoError)
    {
        Logger.LogError("Failed to set SummaryInformationStreamProperty.Template... err = " + err);
        MsiInterop.MsiSummaryInfoPersist(hSIHandle);
        MsiInterop.MsiCloseHandle(hSIHandle);
        return false;
    }
    MsiInterop.MsiSummaryInfoPersist(hSIHandle);
    MsiInterop.MsiCloseHandle(hSIHandle);
}
else
{
    Logger.LogError("Failed to MsiGetSummaryInformation...");
    return false;
}
return true;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

指尖上的星空 2024-09-23 16:24:48

摆脱您正在使用的 MsiInterop,并使用 WiX 的 DTF 中的互操作。 Microsoft.Deploymnet.WindowsInstaller 命名空间有一个 SummaryInformation 类,该类公开读/写字符串 Template 属性。更好的对象模型和互操作,无需担心当前互操作让您处理的所有 P/Invoke 细节。

我现在在家,所以这里有一个代码片段:

using Microsoft.Deployment.WindowsInstaller;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            using( var database = new Database(@"C:\orca.msi", DatabaseOpenMode.Direct  ))
            {
                database.SummaryInfo.Template = "Intel;666";
            }            
        }
    }
}

注意 using() 子句的使用。 Database 类实现 IDisposable 接口并自动处理(双关语)清理所有那些讨厌的非托管句柄。

Get rid of the MsiInterop that you are using and use the interop found in WiX's DTF. The Microsoft.Deploymnet.WindowsInstaller namespace has a SummaryInformation Class that exposes a read/write string Template property. Way better object model and interop without worrying about all the P/Invoke details that your current interop makes you deal with.

I'm home now so here's a code snippet:

using Microsoft.Deployment.WindowsInstaller;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            using( var database = new Database(@"C:\orca.msi", DatabaseOpenMode.Direct  ))
            {
                database.SummaryInfo.Template = "Intel;666";
            }            
        }
    }
}

Notice the use of the using() clause. The Database class implements the IDisposable interface and automatically handles ( pun intended ) cleaning up all those pesky unmanaged handles for you.

北笙凉宸 2024-09-23 16:24:48
Database msidb = objInstaller.OpenDatabase(MSIFileNameWithPath,MsiOpenDatabaseMode.msiOpenDatabaseModeTransact);
SummaryInfo info = msidb.get_SummaryInformation(1);
info.set_Property(2, (object)("sample title"));
info.Persist();
msidb.Commit();

详细回答这个问题的最佳参考是

https://learn.microsoft.com/en-us/archive/blogs/mwade/sail-away-with-me-to-another-world

Database msidb = objInstaller.OpenDatabase(MSIFileNameWithPath,MsiOpenDatabaseMode.msiOpenDatabaseModeTransact);
SummaryInfo info = msidb.get_SummaryInformation(1);
info.set_Property(2, (object)("sample title"));
info.Persist();
msidb.Commit();

The best reference to answer this is in detail is

https://learn.microsoft.com/en-us/archive/blogs/mwade/sail-away-with-me-to-another-world

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文