Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.Net 8 upgrade results in missing destructor call of ActiveXControl from interop assembly generated with AxImp.exe #12056

Closed
KL-Sven opened this issue Sep 5, 2024 · 10 comments · Fixed by #12281
Assignees
Milestone

Comments

@KL-Sven
Copy link

KL-Sven commented Sep 5, 2024

.NET version

net8.0-windows

Did it work in .NET Framework?

Yes

Did it work in any of the earlier releases of .NET Core or .NET 5+?

All versions before .Net 8

Issue description

I have an ActiveX control (OCX) that is integrated into a .NET application. To create the .NET interop assemblies, I use AxImp.exe, which generates a class that inherits from System.Windows.Forms.AxHost. In all versions of .NET prior to 8.0, the destructor of the OCX would be invoked upon calling the Dispose() method on the AxHost instance. However, with the introduction of .NET 8, the destructor is no longer called.

Specifically, in .NET 7, invoking Dispose() would lead to a call to Marshal.FinalReleaseComObject(_instance) within the method ReleaseAxControl() of class AxHost, which effectively triggered the OCX's destructor. But with .NET 8, the code has been changed to call Marshal.ReleaseComObject(_instance) instead, and as a result, the destructor of the OCX is not being executed anymore. This change in behavior is causing issues with resource management in the application.

Steps to reproduce

  1. Create a New MFC ActiveX Control Project:

    • Launch Visual Studio 2022.
    • Create a new project using the MFC ActiveX Control template.
    • Name the project MFCActiveXControl.
  2. Modify the Control's Constructor and Destructor:

    • Open the MFCActiveXControlCtrl.cpp file.
    • Update the constructor and destructor to include console output for logging purposes:
    #include <iostream>
    
    CMFCActiveXControlCtrl::CMFCActiveXControlCtrl()
    {
        std::cout << "constructor called";
    
        InitializeIIDs(&IID_DMFCActiveXControl, &IID_DMFCActiveXControlEvents);
        // TODO: Initialize your control's instance data here.
    }
    
    CMFCActiveXControlCtrl::~CMFCActiveXControlCtrl()
    {
        std::cout << "destructor called";
        // TODO: Cleanup your control's instance data here.
    }
  3. Compile the Project:

    • Set the build configuration to 'Release'.
    • Compile the project to generate the MFCActiveXControl.ocx file.
  4. Register the Compiled OCX:

    • Open PowerShell as an administrator.
    • Execute the following command to register the OCX file:
    . "$Env:WINDIR\SysWOW64\regsvr32.exe" MFCActiveXControl.ocx
    
  5. Generate .NET Interop Assemblies:

    • Use AxImp.exe to create the .NET interop assemblies from the OCX file:
    . "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\AxImp.exe" MFCActiveXControl.ocx
    
  6. Add a .Net 7 C# Console Application:

    • Name the application ConsoleClient.
    • Configure the project file with the following settings:
    <TargetFramework>net7.0-windows</TargetFramework>
    <PlatformTarget>x86</PlatformTarget>
    <UseWindowsForms>true</UseWindowsForms>
    
  7. Add References to the Generated DLLs:

    • Reference both MFCActiveXControlLib.dll and AxMFCActiveXControlLib.dll in your ConsoleClient project.
  8. Update the Main Program File:

    • Replace the contents of Program.cs with the following code:
     using System;
     using AxMFCActiveXControlLib;
     
     namespace ConsoleClient
     {
         internal class Program
         {
             [STAThread]
             static void Main(string[] args)
             {
                 var ocx = new AxMFCActiveXControl();
                 ocx.CreateControl();
                 ocx.Dispose();
             }
         }
     }
  9. Compile and Run the C# Application:

    • Build the ConsoleClient application.
    • Run the application and observe the console output: "Constructor called." followed by "Destructor called."
  10. Update to .NET 8:

    • Change the target framework to .NET 8 by updating the project file:
    <TargetFramework>net8.0-windows</TargetFramework>
    
    • Rebuild the ConsoleClient application.
  11. Re-run the Application:

    • Run the updated ConsoleClient application and observe that the console output displays only "Constructor called." This indicates that the destructor is not being invoked as expected.
@KL-Sven KL-Sven added the untriaged The team needs to look at this issue in the next triage label Sep 5, 2024
@merriemcgaw merriemcgaw removed the untriaged The team needs to look at this issue in the next triage label Sep 5, 2024
@merriemcgaw merriemcgaw added this to the .NET 10.0 milestone Sep 5, 2024
@JeremyKuhne
Copy link
Member

In general it is terrible form to keep calling release in a loop. @lonitra can you check what the ref counts are in ReleaseAxControl are in 8 and 9?

@jlyson
Copy link

jlyson commented Oct 1, 2024

Facing the same issue, is there any progress?

@dotnet-policy-service dotnet-policy-service bot added the 🚧 work in progress Work that is current in progress label Oct 8, 2024
@lonitra lonitra modified the milestones: .NET 10.0, 8.0.11 Oct 8, 2024
@lonitra
Copy link
Member

lonitra commented Oct 8, 2024

This fix will be available in 8.0.11 release, which I believe is November 5

@lonitra lonitra removed the 🚧 work in progress Work that is current in progress label Oct 8, 2024
@KL-Sven
Copy link
Author

KL-Sven commented Oct 8, 2024

This came unexpectedly fast after beeing labeled with .Net 10. Thank you.

@Nora-Zhou01
Copy link
Member

Verified this issue on .NET SDK 10.0.100-alpha.1.2459.21 + private dlls build from latest WinForms main repo, the issue has been fixed: Running the ConsoleClient application will display "Constructor called." and "Destructor called."

issue.verification.mp4

@John-Qiao
Copy link
Member

John-Qiao commented Oct 12, 2024

Verified this issue on .NET SDK 8.0.10 + private dlls build from latest WinForms Release/8.0 repo, the issue has been fixed: Running the ConsoleClient application will display "Constructor called." and "Destructor called."

MFCActiveXControl.zip

Image

@chaowendy
Copy link

chaowendy commented Oct 12, 2024

Verified this issue on .NET 9.0.100 - rtm.24509.30 + private dlls build from latest WinForms Release/9.0 repo, the issue has been fixed: Running the ConsoleClient application will display "Constructor called." and "Destructor called."
Image

@Olina-Zhang
Copy link
Member

Verified this issue in .NET 9.0 GA test pass with .NET SDK 9.0.100 build, it was fixed as above testing result.
Image

@John-Qiao
Copy link
Member

Verified with .NET SDK 8.0.11 test pass build, it was fixed as above testing result.

@KL-Sven
Copy link
Author

KL-Sven commented Nov 13, 2024

Works like a charm also in the realworld application. Good job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants