pywin32 icon indicating copy to clipboard operation
pywin32 copied to clipboard

SAFEARRAY Leaks IUnknown References

Open sean-moore3 opened this issue 2 years ago • 0 comments

  • Expected behavior and actual behavior.

When calling a COM method that returns a SAFEARRAY of newly created IUnknown pointers, I expect the reference count of the interfaces to be 1. Instead, the reference count of each element is 3. When the objects are garbage collected, the reference counts are reduced to 2. Unless the user manually calls Release() twice on each element, the references are leaked. I believe this issue is related to #640.

  • Steps to reproduce the problem.

I built and registered the following simple interface and class:

using System;
using System.Runtime.InteropServices;

namespace Example
{
    [ComVisible(true)]
    [Guid("E69FBDC1-6ADE-47CE-A642-F3795FE95ADD")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IExample
    {
        void GetNew(out IExample[] obj);
    }

    [ComVisible(true)]
    [Guid("E3A22792-2109-4086-AB1E-49AEEDF2EDF9")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Example : IExample
    {
        public void GetNew(out IExample[] obj)
        {
            obj = new[] { new Example() };
        }
    }
}

Then ran this script in Python 3.6:

import win32com.client

import ctypes.wintypes

import pythoncom



example = win32com.client.dynamic.DumbDispatch("Example.Example")

variant = win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_ARRAY | pythoncom.VT_UNKNOWN, [])

example.GetNew(variant)

unknown = variant.value[0]

address = ctypes.c_void_p(int(repr(unknown).split()[-1][:-1], 16))

add_ref = ctypes.WINFUNCTYPE(ctypes.wintypes.ULONG)(1, "AddRef")

release = ctypes.WINFUNCTYPE(ctypes.wintypes.ULONG)(2, "Release")

add_ref(address)

count = release(address)

print(count)


Here is the result:

3

Process finished with exit code 0
  • Version of Python and pywin32

Python 3.6 & pywin32 303

sean-moore3 avatar Apr 21 '22 18:04 sean-moore3