本帖最后由 bcrun 于 2011-02-25 21:45:48 编辑

解决方案 »

  1.   

    Win32_Product 实际是通过 Windows Installer 取得的,如果没安装、停用服务等都会不成功。
      

  2.   

    正常的电脑应该都会安装 Windows Installer 吧。我们不是一台电脑出问题,而是我试的几台电脑都是这个问题。
      

  3.   

    看看你的服务列表中 Windows Installer 启动了没有。
    或者到目标机器上本地调用一下,看能否成功。
      

  4.   

    你们 Windows Installer 服务启动后,能让代码成功吗?我这边仍然不行。一样的错误。
      

  5.   

    很可能就是权限问题了,用不同的用户试试。
    服务器是什么系统?Windows Server 系列的默认设置对好多访问都加了限制,需要通过系统策略设置进行调整。
      

  6.   

    我都怀疑微软是否有这个功能。按WMI的代码生成器生成出来的代码,一样出错。用户权限方面,我使用的已是远程电脑的超级用户,实在想不出其它更好的用户或权限了。WMI的权限,我也是对EveryOne全部开放。我访问的远程电脑有服务器版的,也有XP专业版的。其中有加域的电脑,也有没有加域的电脑。结果都是出错。
      

  7.   

    是不是返回的不是一个集合?如果不是集合的话用foreach应该不行的吧
      

  8.   

    根据微软论坛的建议的链接:我检查了一台电脑,全部可以调成文章中的要求(这里罗列如下):1。首先确保使用的用户名和密码正确,且用户有管理员权限。用户的密码不能为空。
    2。检查目标机上DCOM是否可用。 检查注册表中键值 HKLM\Software\Microsoft\OLE\EnableDCOM的键值设为Y
    3。检查WMI是否已经安装。 在运行窗口中输入 wbemtest。wbemtest是一个wmi的测试工具,可以远程连接计算机。用法:\\<ip>\root\cimv2,连接。此连接等同于net use \\<ip>\C$ /u:<username> <password>命令。如果目标加入了域,则在域服务器不可用的情况下会报“当前没有可用的登录服务器处理请求”的错误,此时局域网共享也将失效。局域网访问通过NetBiOS或者一种直连的方式访问,所以确认端口135,139,或者445是否正常。
    4。确保WMI的权限设置正确。需要设置的有DCOM的访问权限。运行DCOMCNFG。在“组件服务”对话框中,依次展开“组件服务”、“计算机”,“我的电脑”。在“我的电脑”右键属性对话框中,单击“COM 安全”选项卡。在“启动和激活权限”下,单击“编辑限制”。在“启动权限”对话框中,将你要访问的用户或组添加到“组或用户名称”列表中。在“启动权限”对话框中,在“组或用户名称”框内选择您的用户和组。在“用户权限”下的“允许”栏中,选择“远程启动”,然后单击“确定”。
    5。 如果访问的目标机运行的是Windows XP Pro 系统,需要确保远程登录方式不是来宾帐户的方式。方法如下:在本地安全设置中(可以在控制面板的管理工具中找到,或在运行框中输入命令 secpol.msc)。打开本地策略-〉安全选项,把 网络访问:本地帐户的共享和安全模式 中设置为 经典-本地帐户以自己的身份验证。
    6。 在XP SP2 中确保防火墙允许远程的登录。命令:netsh firewall set service RemoteAdmin enable(禁用为disable)。
    7。 注意系统安装其他防火墙或杀毒软件的设置是否允许访问。
    8。 确保WMI或相关服务正在运行。XP中可能涉及到的服务有:
        COM+ Event System
        Remote Access Auto Connection Manager
        Remote Access Connetion Manager
        Remote Procedure Call(RPC)
        Remote Procedure Call(RPC)Locator
        Remote Registry
        Server
        Windows Management Instrumentation
        Windows Management Instrumentation Driver Extensions
        WMI Performance Adapter
        Workstation但结果还是不行。
      

  9.   

    我现在已经放弃了用WMI的Select * from Products方法了,使用访问注册表的方法。参考文档:
    WMI 获得已安装应用程序列表
    文章分类:.net编程 
    问题 13:如何列出特定计算机上已经安装的所有应用? 
    转载http://www.microsoft.com/china/technet/community/scriptcenter/resources/wmifaq.mspx#EXEAE
    Win32_Product WMI 类代表通过 Windows Installer 安装的所有应用程序。但是,这个 WMI 类可能不会列出所有出现在‘添加/删除程序’中的程序。 解决该问题的一种方法是从注册表中搜集已安装程序的信息(注意:并不是所有程序在安装的时候都会向注册表写入信息)。本主题给出了达到此目的的两种方法:使用脚本直接读取注册表中的信息,使用 MOF 文件和脚本从 WMI 中获取该信息。
    1.以下脚本用于列出计算机上已经安装的应用程序。使用 WMI System Registry Provider 直接从注册表中搜集信息的脚本:
    strHost = "."
    Const HKLM = &H80000002
    Set objReg = GetObject("winmgmts://" & strHost & _
        "/root/default:StdRegProv")
    Const strBaseKey = _
        "Software\Microsoft\Windows\CurrentVersion\Uninstall\"
    objReg.EnumKey HKLM, strBaseKey, arrSubKeys
     
    For Each strSubKey In arrSubKeys
        intRet = objReg.GetStringValue(HKLM, strBaseKey & strSubKey, _
            "DisplayName", strValue)
        If intRet <> 0 Then
            intRet = objReg.GetStringValue(HKLM, strBaseKey & strSubKey, _
            "QuietDisplayName", strValue)
        End If
        If (strValue <> "") and (intRet = 0) Then
            WScript.Echo strValue
        End If
    Next
     
    2.以下 MOF 文件和它的配套脚本展示了另外一种从注册表中获取已安装应用的方法。如果使用 MOF 文件,请按以下步骤操作:
    步骤 1:复制以下 MOF 语法到记事本并保存为一个 .MOF 文件(例如 products.mof)。
    qualifier dynamic:ToInstance;
    qualifier ProviderClsid:ToInstance;
    qualifier ClassContext:ToInstance;
    qualifier propertycontext:ToInstance; 
     
    [dynamic, provider("RegProv"),
    ProviderClsid("{fe9af5c0-d3b6-11ce-a5b6-00aa00680c3f}"),
    ClassContext
    ("local|HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall")

    class Products {
       [key] string KeyName;
       [read, propertycontext("DisplayName")]      string DisplayName;
       [read, propertycontext("DisplayVersion")]      string  DisplayVersion;
       [read, propertycontext("InstallLocation")]      string InstallLocation;
    };
    步骤 2:在命令提示行键入 mofcomp products.mof.该命令将 MOF 文件存入 WMI 存储库。
    步骤 3:MOF 存入存储库之后,使用以下脚本获取数据。
    strComputer = "." 
    Set WMI = GetObject("winmgmts:\\" & strComputer & _
        "\root\default")
    Set colItems = WMI.ExecQuery("Select * from Products")
    For Each objItem In colItems
        WScript.Echo "DisplayName: "  & objItem.DisplayName
        WScript.Echo "DisplayVersion: " & objItem.DisplayVersion
        WScript.Echo "InstallLocation: " & objItem.InstallLocation
        WScript.Echo "KeyName: " & objItem.KeyName
    Next
    =======================
    最终代码:
    Const HKLM = &H80000002
    Const BASE_KEY = "Software\Microsoft\Windows\CurrentVersion\Uninstall\"
    Dim sComputer As String
    Dim sUser As String
    Dim sPwd As String
    Dim sNameSpace As StringDim oSWbL As SWbemLocator
    Dim oSWbS As SWbemServices
    Dim oRegEx As SWbemObjectEx
    Dim arrSubKeys As Variant '不能用 SWbemObjectSet 否则会出错
    Dim strSubKey As Variant '不能用 SWbemObject 否则会出错
    Dim lRet As Long
    Dim vValue As Variant  '不能用 string 否则第二次会出错
    Dim i As Long  sComputer = "C715"
      
      If sUser = "" Then
        sUser = "C715\administrator"
      End If
      
      If sPwd = "" Then
        sPwd = "filemon.239"
      End If
      
      sNameSpace = "default" '赋予命名空间
      Set oSWbL = CreateObject("WbemScripting.SWbemLocator")
      Set oSWbS = oSWbL.ConnectServer(sComputer, "root\" & sNameSpace, sUser, sPwd)
      Set oRegEx = oSWbS.Get("StdRegProv")  oRegEx.EnumKey HKLM, BASE_KEY, arrSubKeys
     
      For i = 0 To UBound(arrSubKeys)
        lRet = oRegEx.GetStringValue(HKLM, BASE_KEY & arrSubKeys(i), "DisplayName", vValue)
        If lRet <> 0 Then
          lRet = oRegEx.GetStringValue(HKLM, BASE_KEY & arrSubKeys(i), "QuietDisplayName", vValue)
        End If
        
        If (vValue <> "") And (lRet = 0) Then
          Debug.Print arrSubKeys(i) & " - " & vValue
        Else
          Debug.Print arrSubKeys(i) & " - ???"
        End If
      Next