【问题标题】:How to check if a software is only installed by other at user level when trying to install it for all users?尝试为所有用户安装软件时,如何检查软件是否仅由其他用户安装?
【发布时间】:2019-08-30 11:03:57
【问题描述】:

我正在尝试创建我的安装,它为每个用户和所有用户提供用户安装。

现在,如果假设 John 已在用户级别安装了软件,然后 Andy 尝试将其作为机器级别安装在同一系统上,我如何检测到它已在用户级别为 john 安装并卸载它或中止安装?

因为我在机器级别和用户级别安装时具有不同的功能。我不希望机器上出现冲突的情况。

理想情况下,我想检查软件是否在用户级别安装,然后在机器级别安装时从用户级别安装。

我正在使用 InstallShield 2016 创建安装程序。

【问题讨论】:

  • MSI API: MsiEnumProductsEx 可以列出已安装的产品。我还没有真正使用过它,我知道在为其他用户枚举所有安装时存在问题。当您使用较旧的 MsiEnumProducts 函数时,您将获得启动用户的每用户安装。对于较新的功能,我认为您必须指定用户 SID 以列出为该用户安装的所有软件包。不是100%确定。给github.com搜索一下?
  • 不确定NetUserEnum 是否为您提供了所有使用域帐户登录的用户。只需将其添加到此处以供参考,或许可以为您提供一些帮助。
  • @SteinÅsmul 感谢您的回复。 NetUserEnum 没有返回登录到特定机器的域用户。如果您查询域控制器,它要么返回本地系统的所有用户,要么返回域的所有用户。
  • 第三个参数:DWORD filter - 我使用了FILTER_NORMAL_ACCOUNT - 我现在无法测试域的东西。 NetUserEnum documentation。很快就会看看我的书签。
  • @SteinÅsmul 我使用以下注册表项来获取计算机上登录用户的所有 SID。 IT 既有本地用户,也有域用户。我已经在 windows 7 上测试过它工作正常。 HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList。

标签: windows-installer installation installshield


【解决方案1】:

管理员权限:您需要使用管理员权限运行以下命令才能正常工作。以管理员权限启动 Visual Studio(右键单击快捷方式 并以管理员身份运行)。


Retrieve Per-User Installations:没有时间正确清理这个,就混合各种字符串类型而言,这是相当“狗的早餐”我从 github.com sn-ps 将它涂抹在一起,但这似乎可以找到指定 user SID 的每个用户安装:

#include "pch.h"

#include <windows.h>
#include "msi.h" // Windows Installer
#include <atlstr.h> // ATL CString

#pragma comment (lib, "msi.lib")

int main()
{
    //
    // Admin rights required!
    //

    UINT result = 0;
    DWORD dwIndex = 0;
    TCHAR szInstalledProductCode[39] = { 0 };
    TCHAR szSid[128] = { 0 };
    DWORD cchSid;
    MSIINSTALLCONTEXT dwInstalledContext;
    DWORD cchProductName = MAX_PATH + 1;
    WCHAR* lpProductName = new WCHAR[cchProductName];

    // Fake, sample SID. Replace:
    CString userSID = _T("S-1-5-21-6780625448-452764730-4189743271-1542");

    while (ERROR_SUCCESS == (result = MsiEnumProductsEx(NULL, userSID, MSIINSTALLCONTEXT_USERMANAGED | MSIINSTALLCONTEXT_USERUNMANAGED, dwIndex, szInstalledProductCode, &dwInstalledContext, szSid, &cchSid)))
    {
        UINT uiReturn = MsiGetProductInfoEx(szInstalledProductCode, userSID, dwInstalledContext, INSTALLPROPERTY_INSTALLEDPRODUCTNAME, lpProductName, &cchProductName);
        MessageBox(NULL, _T("Product Code: ") + (CString)szInstalledProductCode + _T("\r\n\r\nProduct Name: ") + lpProductName, _T("Product Name:"), MB_OK);
        dwIndex++;
    }

    return 0;
}

程序:您需要做一些事情才能使上述操作有任何希望。

  • 只需创建一个 Visual C++ 控制台项目。我使用了 Visual Studio 2017。
  • 确定要检索其每用户软件包的帐户的用户 SID 是什么。您可以在命令行中使用 whoami /user,如下所述:How to get active session user SID?
  • 更改 CString userSID = "S-1-5-21-etc..." 行,以便从您的系统中检索有问题的用户 SID。

为了从系统中获取用户 SID 列表,我不知道该怎么做。如果您有好的方法,请分享。

我也尝试了一些可用于 VBScripting 的方法和属性,但我无法检索其他用户的包。我可能只是缺少一些参数,我不确定。

【讨论】:

  • 我发现的最佳方法是将 SID 作为 TCHAR * userSID = _T("s-1-1-0");这将枚举所有用户并返回结果。因此无需查找每个用户的 SID。
  • 我不确定您是否获得其他用户的安装,但当前用户的安装和每台计算机的安装。不是 100% 确定。
【解决方案2】:

这对我有用。感谢 Stein Åsmul。

#include <windows.h>
#include "msi.h" // Windows Installer
#include <tchar.h> // ATL CString

#pragma comment (lib, "msi.lib")
int main()
{
    //
    // Admin rights required!
    //

    TCHAR * userSID = _T("s-1-1-0");
    UINT result = 0;
    DWORD dwIndex = 0;
    MSIINSTALLCONTEXT dwInstalledContext;
    DWORD cchProductName = 2000;
    WCHAR lpProductName[2000] = { 0 };
    while (true)
    {
        TCHAR szInstalledProductCode[100] = { 0 };
        TCHAR szSid[1000] = { 0 };
        DWORD cchSid = 1000;

        if (ERROR_SUCCESS != (result = MsiEnumProductsEx(NULL, userSID, MSIINSTALLCONTEXT_USERMANAGED | MSIINSTALLCONTEXT_USERUNMANAGED, dwIndex, szInstalledProductCode, &dwInstalledContext, szSid, &cchSid)))
        {
            long lVal = GetLastError();
            _tprintf(_T("MsiEnumProductsEx LastError : %d, \r\n\r result: %d\n"), cchSid, result);
            break;
        }
        UINT uiReturn = MsiGetProductInfoEx(szInstalledProductCode, szSid, dwInstalledContext, INSTALLPROPERTY_INSTALLEDPRODUCTNAME, lpProductName, &cchProductName);
        _tprintf(_T("Product Code: %s, \r\n\r\nProduct Name: %s\n"), szInstalledProductCode, lpProductName);
        if (uiReturn != ERROR_SUCCESS)
        {
            long lVal = GetLastError();
            _tprintf(_T(" MsiGetProductInfoEx LastError : %d, \r\n\r result: %d\n"), cchProductName, uiReturn);
        }
        dwIndex++;
    }

    return 0;
}

【讨论】:

    猜你喜欢
    • 2013-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-09
    • 2020-05-19
    • 2021-01-22
    相关资源
    最近更新 更多