调用GetZoneMappings后IEnumString.Next()始终返回0项,如何修正?
解决IEnumString.Next()返回项数始终为0的问题
问题根源
你的代码存在两个核心问题导致nItemsFetched始终为0:
- 输出参数传递错误:
GetZoneMappings的枚举对象参数、Next方法的项数参数均为COM输出参数,需用ByRef传递,否则COM无法修改托管代码中的变量值。 - 数据类型不匹配:
nItemsFetched使用了ULong,但COM接口定义中对应类型是ULONG(即VB中的UInteger),类型不匹配会导致参数传递异常。
修正后的完整代码
Imports System Imports System.Collections.Generic Imports System.Runtime.InteropServices Public Class Test Private Shared ReadOnly CLSID_InternetSecurityManager As New Guid("7b8a2d94-0ac9-11d1-896c-00c04fb6bfc4") Private ReadOnly InternetSecurityManager As IInternetSecurityManager Private Const URLZONE_LOCAL_MACHINE As UInteger = &H0 Private Const URLZONE_INTRANET As UInteger = URLZONE_LOCAL_MACHINE + 1 Private Const URLZONE_TRUSTED As UInteger = URLZONE_INTRANET + 1 Private Const URLZONE_INTERNET As UInteger = URLZONE_TRUSTED + 1 Private Const URLZONE_UNTRUSTED As UInteger = URLZONE_INTERNET + 1 Public Sub New() Dim secManagerType = Type.GetTypeFromCLSID(CLSID_InternetSecurityManager) InternetSecurityManager = CType(Activator.CreateInstance(secManagerType), IInternetSecurityManager) Dim sites = GetSites() End Sub Private Function GetSites() As List(Of String) Dim enumString As IEnumString = Nothing Dim sites As New List(Of String)() Dim items As String() = New String(0) {} Dim fetched As UInteger InternetSecurityManager.GetZoneMappings(URLZONE_INTRANET, enumString, 0) Do ' Next返回S_OK(0)表示成功获取项,S_FALSE(1)表示无更多项 Dim hr = enumString.Next(1, items, fetched) If hr <> 0 OrElse fetched = 0 Then Exit Do End If sites.Add(items(0)) Loop Return sites End Function ' 正确定义IInternetSecurityManager接口,仅保留用到的GetZoneMappings方法 <ComImport> <Guid("79eac9ee-baf9-11ce-8c82-00aa004ba90b")> <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> Private Interface IInternetSecurityManager Sub GetZoneMappings(<[In]> dwZone As UInteger, <Out> ByRef ppenumString As IEnumString, <[In]> dwFlags As UInteger) ' 若需要其他方法,可根据MSDN文档补充签名 End Interface ' 正确定义IEnumString接口,匹配COM规范 <ComImport> <Guid("00000101-0000-0000-C000-000000000046")> <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> Private Interface IEnumString Function Next(<[In]> celt As UInteger, <Out()> rgelt As String(), <Out> ByRef pceltFetched As UInteger) As Integer Sub Skip(<[In]> celt As UInteger) Sub Reset() Sub Clone(<Out> ByRef ppenum As IEnumString) End Interface End Class
关键修正说明
- 接口定义修正
- 手动定义
IInternetSecurityManager和IEnumString接口,确保参数传递符合COM规范:GetZoneMappings的ppenumString用ByRef声明,让COM能返回枚举对象。IEnumString.Next的pceltFetched用ByRef声明,让COM能写入实际获取的项数。
- 手动定义
- 循环逻辑优化
- 通过
Next方法的返回值(S_OK/S_FALSE)结合fetched值判断循环终止条件,无需再检查字符串是否为Nothing。
- 通过
- 数据类型对齐
- 将
fetched改为UInteger,匹配COM接口的ULONG类型,避免类型转换错误。
- 将
内容的提问来源于stack exchange,提问作者InteXX
相关产品推荐
相关产品推荐

