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

Mojtaba_Hakim 321 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 ?

Developer technologies | Visual Studio | Debugging
Windows for business | Windows Client for IT Pros | User experience | Other
Developer technologies | .NET | Other
Developer technologies | Visual Studio | Other
Developer technologies | Visual Studio | Other
A family of Microsoft suites of integrated development tools for building applications for Windows, the web, mobile devices and many other platforms. Miscellaneous topics that do not fit into specific categories.
Developer technologies | C#
Developer technologies | 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.
0 comments No comments
{count} vote

Answer accepted by question author
  1. RLWA32 51,366 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.

2 additional answers

Sort by: Most helpful
  1. RLWA32 51,366 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. Anonymous
    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' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.