- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
在使用 MSI Interop API 时,我遇到了一些导致我的应用程序崩溃的异常行为。 “处理”问题很简单,但我想更多地了解“为什么”会发生这种情况。
我对 MSIEnumRelatedProducts 的第一次调用返回值 0,并将我的字符串缓冲区正确设置为产品代码。我的理解是,只有当给定的升级代码(作为参数传递给方法)当前安装了“相关系列产品”时才会发生这种情况,否则它将返回 259 ERROR_NO_MORE_ITEMS。
但是,当我随后使用相同的产品代码调用 MSIGetProductInfo 时,我得到返回值 1605,“此操作仅对当前安装的产品有效。”。
有人知道在什么情况下会发生这种情况吗?它在一台机器上 100% 可重复,但我还没有设法在另一台机器上获得复制步骤。
我们所有的产品都是使用 Wix 属性“AllUsers=1”构建的,因此应该为所有用户安装产品,而不仅仅是一个用户。
任何想法/建议表示赞赏。
谢谢本
更新:我注意到在运行带有日志记录的问题 msi 包时,会显示以下行:
MSI (s) (88:68) [12:15:50:235]:FindRelatedProducts:无法读取产品“{840C...etc.....96}”的 ASSIGNMENTTYPE 信息。跳过...
有人知道这可能意味着什么吗?
更新:代码示例。
do
{
result = _MSIApi.EnumRelatedProducts(upgradeCode.ToString("B"), 0,
productIndex, productCode);
if (result == MSIApi.ERROR_BAD_CONFIGURATION ||
result == MSIApi.ERROR_INVALID_PARAMETER ||
result == MSIApi.ERROR_NOT_ENOUGH_MEMORY)
{
throw new MSIInteropException("Failed to check for related products",
new Win32Exception((Int32)result));
}
if(!String.IsNullOrEmpty(productCode.ToString()))
{
Int32 size = 255;
StringBuilder buffer = new StringBuilder(size);
Int32 result = (Int32)_MSIApi.GetProductInfo(productCode,
MSIApi.INSTALLPROPERTY_VERSIONSTRING,
buffer,
ref size);
if (result != MSIApi.ERROR_SUCCESS)
{
throw new MSIInteropException("Failed to get installed version",
new Win32Exception(result));
}
version = new Version(buffer.ToString());
}
productCode = new StringBuilder(39);
productIndex++;
}
while (result == MSIApi.ERROR_SUCCESS);
最佳答案
我想您尝试使用 MsiGetProductInfo获得文档中描述的其他属性。例如,您可以毫无问题地获取 "PackageCode"
属性 (INSTALLPROPERTY_PACKAGECODE
) 的值,但您无法获取 的值关于 MsiGetProductInfo 的“UpgradeCode”
属性并收到错误 1605 (ERROR_UNKNOWN_PRODUCT
)。
已更新:好的,现在我明白你的问题了。您如何在互联网上找到 MsiGetProductInfo 中的错误? ,所以它并不总是有效。有时它会返回 1605 (ERROR_UNKNOWN_PRODUCT
) 或 1608 (ERROR_UNKNOWN_PROPERTY
)。在这种情况下,唯一的解决方法是手动获取版本属性。我可以使用 Microsoft Office Outlook 2010 MUI (UpgradeCode = "{00140000-001A-0000-0000-0000000FF1CE}") 重现您在我的计算机上描述的问题,并编写了一个解决方法,从注册表中获取产品版本。在示例中,我仅从 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products
获取信息。如果您不仅对为所有用户安装的产品感兴趣,您还必须修改程序。这是代码
using System;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace EnumInstalledMsiProducts {
internal static class NativeMethods {
internal const int MaxGuidChars = 38;
internal const int NoError = 0;
internal const int ErrorNoMoreItems = 259;
internal const int ErrorUnknownProduct = 1605;
internal const int ErrorUnknownProperty = 1608;
internal const int ErrorMoreData = 234;
[DllImport ("msi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int MsiEnumRelatedProducts (string lpUpgradeCode, int dwReserved,
int iProductIndex, //The zero-based index into the registered products.
StringBuilder lpProductBuf); // A buffer to receive the product code GUID.
// This buffer must be 39 characters long.
// The first 38 characters are for the GUID, and the last character is for
// the terminating null character.
[DllImport ("msi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern Int32 MsiGetProductInfo (string product, string property,
StringBuilder valueBuf, ref Int32 cchValueBuf);
}
class Program {
static int GetProperty(string productCode, string propertyName, StringBuilder sbBuffer) {
int len = sbBuffer.Capacity;
sbBuffer.Length = 0;
int status = NativeMethods.MsiGetProductInfo (productCode,
propertyName,
sbBuffer, ref len);
if (status == NativeMethods.ErrorMoreData) {
len++;
sbBuffer.EnsureCapacity (len);
status = NativeMethods.MsiGetProductInfo (productCode, propertyName, sbBuffer, ref len);
}
if ((status == NativeMethods.ErrorUnknownProduct ||
status == NativeMethods.ErrorUnknownProperty)
&& (String.Compare (propertyName, "ProductVersion", StringComparison.Ordinal) == 0 ||
String.Compare (propertyName, "ProductName", StringComparison.Ordinal) == 0)) {
// try to get vesrion manually
StringBuilder sbKeyName = new StringBuilder ();
sbKeyName.Append ("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Products\\");
Guid guid = new Guid (productCode);
byte[] buidAsBytes = guid.ToByteArray ();
foreach (byte b in buidAsBytes) {
int by = ((b & 0xf) << 4) + ((b & 0xf0) >> 4); // swap hex digits in the byte
sbKeyName.AppendFormat ("{0:X2}", by);
}
sbKeyName.Append ("\\InstallProperties");
RegistryKey key = Registry.LocalMachine.OpenSubKey (sbKeyName.ToString ());
if (key != null) {
string valueName = "DisplayName";
if (String.Compare (propertyName, "ProductVersion", StringComparison.Ordinal) == 0)
valueName = "DisplayVersion";
string val = key.GetValue (valueName) as string;
if (!String.IsNullOrEmpty (val)) {
sbBuffer.Length = 0;
sbBuffer.Append (val);
status = NativeMethods.NoError;
}
}
}
return status;
}
static void Main () {
string upgradeCode = "{00140000-001A-0000-0000-0000000FF1CE}";
StringBuilder sbProductCode = new StringBuilder (39);
StringBuilder sbProductName = new StringBuilder ();
StringBuilder sbProductVersion = new StringBuilder (1024);
for (int iProductIndex = 0; ; iProductIndex++) {
int iRes = NativeMethods.MsiEnumRelatedProducts (upgradeCode, 0, iProductIndex, sbProductCode);
if (iRes != NativeMethods.NoError) {
// NativeMethods.ErrorNoMoreItems=259
break;
}
string productCode = sbProductCode.ToString();
int status = GetProperty (productCode, "ProductVersion", sbProductVersion);
if (status != NativeMethods.NoError) {
Console.WriteLine ("Can't get 'ProductVersion' for {0}", productCode);
}
status = GetProperty (productCode, "ProductName", sbProductName);
if (status != NativeMethods.NoError) {
Console.WriteLine ("Can't get 'ProductName' for {0}", productCode);
}
Console.WriteLine ("ProductCode: {0}{3}ProductName:'{1}'{3}ProductVersion:'{2}'{3}",
productCode, sbProductName, sbProductVersion, Environment.NewLine);
}
}
}
}
在我的电脑上产生正确的输出
ProductCode: {90140000-001A-0407-0000-0000000FF1CE}
ProductName:'Microsoft Office Outlook MUI (German) 2010'
ProductVersion:'14.0.4763.1000'
ProductCode: {90140000-001A-0419-0000-0000000FF1CE}
ProductName:'Microsoft Office Outlook MUI (Russian) 2010'
ProductVersion:'14.0.4763.1000'
而不是之前 ProductVersion
中的错误。
关于c# - 使用 MSIEnumRelatedProducts 和 MSIGetProductInfo 的 MSI Interop,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4013425/
尝试将 MsiEnumRelatedProducts 与各种输入一起使用时,我总是只返回 ERROR_INVALID_PARAMETERS。该文档没有提供有关无效参数来源的任何详细信息,但我尝试了许多
我在从 C# 调用 MsiEnumRelatedProducts 时遇到了无穷无尽的麻烦。我在 p/invoke 定义上尝试了几个变体,但没有成功(out 和 ref)。我认为问题是最后一个参数,它是
在使用 MSI Interop API 时,我遇到了一些导致我的应用程序崩溃的异常行为。 “处理”问题很简单,但我想更多地了解“为什么”会发生这种情况。 我对 MSIEnumRelatedProduc
我是一名优秀的程序员,十分优秀!