SCardEstablishContext 内存泄漏

2024-03-30

我们在某些 Windows 安装上突然出现智能卡 API 问题。 调用 SCardEstablishContext 函数时似乎存在内存泄漏。 可以在控制台应用程序中重现该问题,代码示例位于http://www.pinvoke.net/default.aspx/winscard.scardbuiltcontext http://www.pinvoke.net/default.aspx/winscard.scardestablishcontext

class Program
{
    #region Win32
    // WinSCard APIs to be imported.
    [DllImport("WinScard.dll")]
    static extern int SCardEstablishContext(uint dwScope,
        IntPtr notUsed1,
        IntPtr notUsed2,
        out IntPtr phContext);

    [DllImport("WinScard.dll")]
    static extern int SCardReleaseContext(IntPtr phContext);

    [DllImport("WinScard.dll")]
    static extern int SCardConnect(IntPtr hContext,
        string cReaderName,
        uint dwShareMode,
        uint dwPrefProtocol,
        ref IntPtr phCard,
        ref IntPtr ActiveProtocol);

    [DllImport("WinScard.dll")]
    static extern int SCardDisconnect(IntPtr hCard, int Disposition);

    [DllImport("WinScard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)]
    static extern int SCardListReaders(
      IntPtr hContext,
      byte[] mszGroups,
      byte[] mszReaders,
      ref UInt32 pcchReaders);
    #endregion

    static void Main(string[] args)
    {
        while (true)
        {
            SmartCardInserted();
            System.Threading.Thread.Sleep(10);
        }
    }

    internal static bool SmartCardInserted()
    {
        bool cardInserted = false;
        IntPtr hContext = IntPtr.Zero;

        try
        {
            List<string> readersList = new List<string>();

            int ret = 0;
            uint pcchReaders = 0;
            int nullindex = -1;
            char nullchar = (char)0;

            // Establish context.
            ret = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out hContext);

            // First call with 3rd parameter set to null gets readers buffer length.
            ret = SCardListReaders(hContext, null, null, ref pcchReaders);

            byte[] mszReaders = new byte[pcchReaders];

            // Fill readers buffer with second call.
            ret = SCardListReaders(hContext, null, mszReaders, ref pcchReaders);

            // Populate List with readers.
            ASCIIEncoding ascii = new ASCIIEncoding();

            string currbuff = ascii.GetString(mszReaders);

            int len = (int)pcchReaders;

            if (len > 0)
            {
                while (currbuff[0] != nullchar)
                {
                    nullindex = currbuff.IndexOf(nullchar);   // Get null end character.
                    string reader = currbuff.Substring(0, nullindex);
                    readersList.Add(reader);
                    len = len - (reader.Length + 1);
                    currbuff = currbuff.Substring(nullindex + 1, len);
                }
            }

            // We have list of readers, check for cards.
            IntPtr phCard = IntPtr.Zero;
            IntPtr ActiveProtocol = IntPtr.Zero;
            int result = 0;

            foreach (string readerName in readersList)
            {
                try
                {
                    result = SCardConnect(hContext, readerName, 2, 3, ref phCard, ref ActiveProtocol);
                    if (result == 0)
                    {
                        cardInserted = true;
                        break;
                    }
                }
                finally
                {
                    SCardDisconnect(phCard, 0);
                }
            }
        }
        finally
        {
            SCardReleaseContext(hContext);
        }

        return cardInserted;

    }
}

为了进行测试,我们在无限循环中调用 SmartCard Inserted() 方法,并有很小的延迟 => 内存不断增长并分配新的句柄。

我们在运行 Windows 10 或 Windows Server 2012 的系统上看到此问题,但在 Windows Server 2008 上则没有。

任何想法都将不胜感激!


该问题似乎已在 Windows 10 v1709 中发布。重现该错误的最短代码量是

while(true) {
    ret = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out hContext);
    SCardReleaseContext(hContext);
}

每次建立和释放上下文时,它都会泄漏约 264 字节的内存。

如果您在循环之外维护 hContext 并且仅创建 IntPtr.Zero 的上下文,则应该能够避免泄漏。然后,当您调用 SCardListReaders 时,检查是否返回 SCARD_E_INVALID_HANDLE 并使您的 hContext 无效。

class Program
{
    #region Win32
    // WinSCard APIs to be imported.
    [DllImport("WinScard.dll")]
    static extern int SCardEstablishContext(uint dwScope,
        IntPtr notUsed1,
        IntPtr notUsed2,
        out IntPtr phContext);

    [DllImport("WinScard.dll")]
    static extern int SCardReleaseContext(IntPtr phContext);

    [DllImport("WinScard.dll")]
    static extern int SCardConnect(IntPtr hContext,
        string cReaderName,
        uint dwShareMode,
        uint dwPrefProtocol,
        ref IntPtr phCard,
        ref IntPtr ActiveProtocol);

    [DllImport("WinScard.dll")]
    static extern int SCardDisconnect(IntPtr hCard, int Disposition);

    [DllImport("WinScard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)]
    static extern int SCardListReaders(
      IntPtr hContext,
      byte[] mszGroups,
      byte[] mszReaders,
      ref UInt32 pcchReaders);
    #endregion

    static void Main(string[] args)
    {
        IntPtr hContext = IntPtr.Zero;
        while (true)
        {
            SmartCardInserted(hContext);
            System.Threading.Thread.Sleep(10);
        }
        SCardReleaseContext(hContext);
    }

    internal static bool SmartCardInserted(IntPtr hContext)
    {
        bool cardInserted = false;

        try
        {
            List<string> readersList = new List<string>();

            int ret = 0;
            uint pcchReaders = 0;
            int nullindex = -1;
            char nullchar = (char)0;

            // Establish context.
            if(hContext == IntPtr.Zero)
                ret = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out hContext);

            // First call with 3rd parameter set to null gets readers buffer length.
            ret = SCardListReaders(hContext, null, null, ref pcchReaders);

            if(ret == 0x80100003) // SCARD_E_INVALID_HANDLE = 0x80100003, // The supplied handle was invalid
            {
                try
                {
                    SCardReleaseContext(hContext);
                }
                catch {}
                finally
                {
                    hContext = IntPtr.Zero;
                }
                return false;
            }

            byte[] mszReaders = new byte[pcchReaders];

            // Fill readers buffer with second call.
            ret = SCardListReaders(hContext, null, mszReaders, ref pcchReaders);

            // Populate List with readers.
            ASCIIEncoding ascii = new ASCIIEncoding();

            string currbuff = ascii.GetString(mszReaders);

            int len = (int)pcchReaders;

            if (len > 0)
            {
                while (currbuff[0] != nullchar)
                {
                    nullindex = currbuff.IndexOf(nullchar);   // Get null end character.
                    string reader = currbuff.Substring(0, nullindex);
                    readersList.Add(reader);
                    len = len - (reader.Length + 1);
                    currbuff = currbuff.Substring(nullindex + 1, len);
                }
            }

            // We have list of readers, check for cards.
            IntPtr phCard = IntPtr.Zero;
            IntPtr ActiveProtocol = IntPtr.Zero;
            int result = 0;

            foreach (string readerName in readersList)
            {
                try
                {
                    result = SCardConnect(hContext, readerName, 2, 3, ref phCard, ref ActiveProtocol);
                    if (result == 0)
                    {
                        cardInserted = true;
                        break;
                    }
                }
                finally
                {
                    SCardDisconnect(phCard, 0);
                }
            }
        }

        return cardInserted;
    }
}

在 Winscard.dll API 修复之前,这是一种解决方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SCardEstablishContext 内存泄漏 的相关文章

随机推荐

  • 预提交钩子文件暂存以进行提交

    如果您在 Git 中有一个用于创建 或修改 文件的预提交挂钩 那么该文件是否需要暂存才能提交 例如 如果我有一个预提交挂钩来创建某些代码的缩小版本 我是否需要git add那个缩小版本可以包含在提交中吗 是的 您必须自己将文件添加到索引中
  • 是否可以通过 Pip 安装部分 Python 包?

    我有一个被许多项目使用的内部实用程序库 从实用程序库中提取的代码中的项目之间有相当多的重叠 但随着库的增长 任何单个项目获得的不会使用的额外内容也会增加 如果该库仅包含 python 那么这不会成为问题 但该库也捆绑在二进制文件中 Exam
  • 一行中两个等号?

    有人可以解释一下这是做什么的以及它如何是合法的 C 代码吗 我在这段代码中找到了这一行 http code google com p compression code downloads list http code google com
  • 如何在一台服务器上部署nodejs api和vuejs应用程序

    我开发了 Node Rest api 和 vuejs Web 应用程序 我正在尝试将这两个项目部署到一台运行 ubuntu 的 aws 服务器上 两个应用程序都有不同的端口 我尝试为 api 配置 api example com 为 vue
  • XML-RPC 方法可以在 Python 中按名称(作为字符串)调用吗?

    在 python 中 调用 XML RPC 方法涉及调用代理对象上的方法 from xmlrpclib import ServerProxy print ServerProxy https example com rpc api hello
  • 隐藏的 YouTube 播放器失去了方法

    我正在使用 javascript 控制嵌入式 youtube chromeless 播放器 并且我想偶尔通过设置 display none 来隐藏它 然而 当我再次向播放器展示时 它失去了 YouTube 方法 例如
  • .NET MVC3 Razor (VB!) 扩展未在视图中导入?

    我的扩展未导入到我的 vbhtml 视图中 我似乎在某个地方遗漏了一些东西 有人可以帮忙吗 模块 vb Imports System Runtime CompilerServices Namespace Areas Admin Models
  • Arel、联接和 Rails 查询

    我最近被一个问题困扰了一段时间 并找到了 Arel 的方法 它看起来应该允许我在查询中执行 OR 操作 作为起点 我需要将现有的 Rails 3 查询转换为 Arel 这就是我遇到问题的地方 以下范围和查询按我的预期工作 它向我提供与特定用
  • 如果 std::map 被清除,是否确保内存被释放

    If a std vector vec被清除vec clear 分配的内存不得立即释放 这size向量的值将为零 但capacity将 可以不变 这是一种非常有益的行为 因为可以清除一个大向量并为其分配新值 而不需要昂贵的内存解除 分配 内
  • 从 CGRect 中减去 CGRect——其中最大的一块不包含另一个

    我怎样才能减一CGRect来自另一个 我想要结果R1 R2是 R1 中不与 R2 相交的最大子矩形 实施例1 R2 R1
  • 括号中的 Console.log 错误

    每次我尝试使用 console log 时都会遇到这种错误 错误 意外的控制台语句 无控制台 console log 名称 is a 年龄 岁数 工作 谁已婚 isMarried 36 错误 控制台 未定义 no undef console
  • 新的 Voided Purchasing API 的用例是什么

    谷歌刚刚推出无效购买 API https developers google com android publisher voided purchases Google Play 作废购买 API 允许您撤销对与用户已作废的购买相关的应用内
  • 如何将 Thymeleaf 显示的字符串大写到页面中?

    我正在开发一个使用 Thymeleaf 作为模板引擎的 Spring MVC 应用程序 并且我正在尝试将页面中显示的一些字符串大写 在我的页面上有这样的内容 li class com nav item a href class com na
  • 如何将本地库加载到本地android代码中? (安卓工作室)

    我有一个 C 语言库 名为mylib在文件夹中jniLibs your architecture mylib so 在 Java 中 要加载库 您只需在源代码中键入该代码 static System loadLibrary mylib 但是
  • Python 推导式中是否需要局部变量? [复制]

    这个问题在这里已经有答案了 在 Python 3 x 中 我正在调用一个函数rand foo 每次被调用时都会返回一些随机的东西 我希望将随机结果序列存储到列表中 我正在使用以下构造 r rand foo for i in range 10
  • 如何保存 Extjs4 图表图像以在 pdf 报告中打印?

    我的 extjs4application 仪表板中有几个图表 我想使用这些图表的图像生成 pdf 报告 为此我使用 iTextSharp 有没有办法从图表中获取图像 以便将它们包含在我的报告中 对我来说理想的是像这样与 itextsharp
  • Cordova/Ionic - 为手机设置仅纵向模式并允许在平板电脑中定向

    如何将手机设置为仅纵向 并允许平板电脑在纵向和横向之间切换 我正在使用 Ionic Cordova 目前 我已使用以下属性在 config xml 中将应用程序设置为纵向模式
  • 维奥拉-琼斯算法 - “像素之和”?

    我看过很多关于 Viola Jones 算法如何真正工作的文章和问题的答案 我不断找到答案 说某个区域中的 像素总和 减去相邻区域中的 像素总和 我对 像素总和 的含义感到困惑 其价值依据是什么 是该区域的像素数吗 颜色的强度 提前致谢 这
  • 为多个属性设置相同的值 (CSS)

    有没有一种方法可以将多个 CSS 属性设置为一个值 border left border right 1px solid E2E2E2 你可以用选择器做些什么 wrapper maindiv 没有 但对于你的例子 你可以这样做 border
  • SCardEstablishContext 内存泄漏

    我们在某些 Windows 安装上突然出现智能卡 API 问题 调用 SCardEstablishContext 函数时似乎存在内存泄漏 可以在控制台应用程序中重现该问题 代码示例位于http www pinvoke net default