MsiEnumRelatedProducts возвращает ERROR_INVALID_PARAMETER с iProductIndex › 0

Я пытаюсь написать сценарий AutoIt, который удаляет все пакеты MSI с определенным Код обновления. Это мой код до сих пор:

$i = 0
Do
  $buffer = DllStructCreate("wchar[39]")
  $ret = DllCall("msi.dll", "UINT", "MsiEnumRelatedProductsW", _
    "wstr", "{a1b6bfda-45b6-43cc-88de-d9d29dcafdca}", _ ; lpUpgradeCode
    "dword", 0, _ ; dwReserved
    "dword", $i, _ ; iProductIndex
    "ptr", DllStructGetPtr($buffer)) ; lpProductBuf
  $i = $i + 1
  MsgBox(0, "", $ret[0] & " " & DllStructGetData($buffer, 1))
Until($ret[0] <> 0)

Это работает безупречно, чтобы определить код продукта для первого установленного продукта, но возвращает 87 (ERROR_INVALID_PARAMETER), как только iProductIndex увеличивается до 1. Обычно эта ошибка возвращается, когда входной идентификатор GUID имеет неверный формат, но в этом случае он также не должен работать с iProductIndex = 0...

Что я ожидал от этого кода (когда установлены 2 пакета с одинаковым кодом обновления):

  1. Выведите «0 ‹первый код продукта›»
  2. Выведите «0 ‹второй код продукта›»
  3. Вывести "259" (ERROR_NO_MORE_ITEMS)

Что он делает в настоящее время:

  1. Выведите «0 ‹первый код продукта›»
  2. Вывести "87" (ERROR_INVALID_PARAMETER)

Любые идеи?

(Если вы хотите протестировать этот код на своем компьютере, вам понадобятся два пакета MSI с одним и тем же установленным UpgradeCode. Вот мои тестовые пакеты WiX: http://pastie.org/3022676 )


person Martin von Wittich    schedule 15.12.2011    source источник


Ответы (1)


Хорошо, я нашел простой обходной путь: я просто удаляю каждый продукт, который я могу найти с iProductIndex = 0 в цикле.

Func GetProduct($UpgradeCode)
  $buffer = DllStructCreate("wchar[39]")
  $ret = DllCall("msi.dll", "UINT", "MsiEnumRelatedProductsW", _
    "wstr", $UpgradeCode, _ ; lpUpgradeCode
    "dword", 0, _ ; dwReserved
    "dword", 0, _ ; iProductIndex
    "ptr", DllStructGetPtr($buffer)) ; lpProductBuf
  Return DllStructGetData($buffer, 1)
EndFunc

$Last = ""
$Product = ""
Do
  $Last = $Product
  $Product = GetProduct("{a1b6bfda-45b6-43cc-88de-d9d29dcafdca}")
  If $Product = "" Then Exit

  $Ret = RunWait("msiexec /qn /x " & $Product)
  ConsoleWrite($Ret & " " & $Product & @CRLF)
  If $Product = $Last Then Exit 1
Until($product = "")
person Martin von Wittich    schedule 19.12.2011