How to Use 32-bit COM DLL in a 64-bit WPF .NET Core 6 Application?

Mojtaba_Hakim 301 Reputation points
2024-08-06T02:08:01.25+00:00

I have a Class Library project in .NET Core named "LIBTOOBA" with the following setup:

Project File (LIBTOOBA.csproj):

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <PlatformTarget>AnyCPU</PlatformTarget>
  </PropertyGroup>

  <ItemGroup>
    <Reference Include="Interop.TSMSLIB_TLB">
      <HintPath>DLLS\Interop.TSMSLIB_TLB.dll</HintPath>
      <EmbedInteropTypes>True</EmbedInteropTypes>
    </Reference>
  </ItemGroup>

</Project>

Details about the DLL:

  • Name: Interop.TSMSLIB_TLB
  • Works on Platform target: x86

Class Definitions:

namespace LIBTOOBA
{
    class Authentication
    {
        //...
    }

    class Proxy
    {
        //...
    }

    using TSMSLIB_TLB;

    class TSMS
    {
        private Authentication a = new Authentication();
        public Authentication A
        {
            set { this.a = value; }
            get { return this.a; }
        }

        private TSMS_Tooba t = new TSMS_Tooba();
        public TSMS_Tooba T
        {
            set { this.t = value; }
            get { return this.t; }
        }

        public void init()
        {
            t.UserName = this.a.UserName;
            t.Password = this.a.PassWord;
            t.LibKey = this.a.LibKey;
            t.ProxyServer = this.p.Server;
            t.ProxyPort = this.p.Port;
            t.ProxyUserName = this.p.UserName;
            t.ProxyPassword = this.p.PassWord;
        }
    }
}

Main Class:

namespace LIBTOOBA
{
    public class CL_TOOBASMS
    {
        private readonly TSMS CL_SMS;

        public CL_TOOBASMS(string userName, string password, string libKey)
        {
            // Validate inputs
            if (string.IsNullOrWhiteSpace(userName))
                throw new ArgumentException("Username cannot be null or empty", nameof(userName));
            if (string.IsNullOrWhiteSpace(password))
                throw new ArgumentException("Password cannot be null or empty", nameof(password));
            if (string.IsNullOrWhiteSpace(libKey))
                throw new ArgumentException("LibKey cannot be null or empty", nameof(libKey));

            CL_SMS = new TSMS();

            try
            {
                CL_SMS.A.UserName = userName;
                CL_SMS.A.PassWord = password;
                CL_SMS.A.LibKey = libKey;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("Failed to set SMS library credentials.", ex);
            }
        }

        public (string Number, int Credit, int UsedCredit, string LastDate) GetMyAccountInfo()
        {
            //...
            return (number, credit, usedCredit, lastDate);
        }

        public string GetDeliveryInfo(string sendToNumber, string sendEvent)
        {
            //...
            return delivery;
        }

        public string SendSMS(string sendToNumber, string sendMsg)
        {
            //...
            return sendEventTxt;
        }
    }
}

My Issue: I have a WPF .NET Core 6 Application with Platform target set to AnyCPU (x64). When I add the "LIBTOOBA" library and try to run the application, I get the following error:

System.Runtime.InteropServices.COMException: 'Retrieving the COM class factory for component with CLSID {83A108DD-D51F-43AF-9290-00541698F0F9} failed due to the following error: 80040154 Class not registered (0x80040154 (REGDB_E_CLASSNOTREG)).'

There is no x64 version of the Interop.TSMSLIB_TLB.dll.

If I change my WPF Platform target to x86, it runs successfully. However, I want to keep my WPF .NET Core 6 Application on Platform target AnyCPU (x64). How can I bypass this issue?

Potential Solutions I am Considering:

  • "Side-by-side" COM activation: Load the 32-bit COM component in a 64-bit process
  • PInvoke (Platform Invoke) to call functions directly from unmanaged DLLs
  • Separate 32-bit process for COM Interop
  • Use CorFlags to force x86 execution
  • Create a C++/CLI wrapper

Any suggestions or guidance on how to implement one of these solutions or another approach would be greatly appreciated.

I want to keep my WPF .NET Core 6 Application on Platform target AnyCPU (x64) , How can I bypass that ?

Windows
Windows
A family of Microsoft operating systems that run across personal computers, tablets, laptops, phones, internet of things devices, self-contained mixed reality headsets, large collaboration screens, and other devices.
5,408 questions
.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,864 questions
Visual Studio
Visual Studio
A family of Microsoft suites of integrated development tools for building applications for Windows, the web and mobile devices.
5,132 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,940 questions
Visual Studio Debugging
Visual Studio Debugging
Visual Studio: A family of Microsoft suites of integrated development tools for building applications for Windows, the web and mobile devices.Debugging: The act or process of detecting, locating, and correcting logical or syntactical errors in a program or malfunctions in hardware. In hardware contexts, the term troubleshoot is the term more frequently used, especially if the problem is major.
1,000 questions
0 comments No comments
{count} votes

Accepted answer
  1. RLWA32 45,571 Reputation points
    2024-08-07T10:16:36.57+00:00

    I created a 32-bit COM in-process COM server in C++ and registered it. The only functions it exports are those used for COM registration. The registration did not include the entries to APPID and CLSID that I described in my earlier post.

    As expected, a 64-bit .Net 6.0 C# console application threw a class not registered exception.

    Sample console application -

    using System.Diagnostics.Contracts;
    using System.Runtime.InteropServices;
    using System;
    using TestServerLib;
    
    namespace CSNet6Client
    {
        internal class Program
        {
            static void Main(string[] args)
            {
                Guid clsid = new Guid("ec20d466-7a4e-467b-b86a-71de9287d82f");
                Guid iid = new Guid("e171eac0-d8c1-4800-a8eb-e47329976806");
    
                try
                {
                    Type t = Type.GetTypeFromCLSID(clsid);
    
                    ITestObj server = (ITestObj)Activator.CreateInstance(t);
    
                    int plusresult = server.Add(10, 10);
                    Console.WriteLine($"10 + 10 = {plusresult}");
    
                    int minusresult = server.Subtract(100, 53);
                    Console.WriteLine($"100 - 53 = {minusresult}");
    
                    string s = server.Name;
                    Console.WriteLine($"Name is {s}");
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
    }
    

    Before adding registry entries for use of DllSurrogate -

    enter image description here Then I edited the registry to add the necessary information so that the 32-bit COM server would run in the system surrogate process (dllhost.exe).

    Results of running the 64-bit .Net 6.0 application using DllSurrogate to host 32-bit COM server- by the way, I fixed a typo in the code that printed the subtraction but didn't bother to rerun the code and post an updated image.

    32bitWithSurrogate

    No changes were made to the C# code. The magic was in using the DllSurrogate.

    1 person found this answer helpful.
    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. RLWA32 45,571 Reputation points
    2024-08-06T02:29:30.4166667+00:00

    Generally speaking, the simplest solution to enable using a 32-bit COM DLL by 64-bit process is to add the registry entries so that the 32-bit in process server is loaded by the system's DllSurrogate. Then, the COM client application can request out of process instantiation of the desired COM object. Refer to https://learn.microsoft.com/en-us/windows/win32/com/dllsurrogate and also to https://learn.microsoft.com/en-us/windows/win32/com/appid-clsid

    0 comments No comments

  2. Hongrui Yu-MSFT 1,995 Reputation points Microsoft Vendor
    2024-08-07T05:48:10.1566667+00:00

    Hi,@Mojtaba_Hakim. Welcome to Microsoft Q&A. 

    It could be resolved by registering Interop.TSMSLIB_TLB.dll in the regsvr32.exe.

     

    Open the command prompt -> jump into the Interop.TSMSLIB_TLB.dll -> run the command regsvr32 Interop.TSMSLIB_TLB.dll.

     

    Supporting Documents:

    1. .net - How to repair COMException error 80040154? - Stack Overflow
    2. c# - HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)) - Stack Overflow

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.