Click here to Skip to main content
14,700,235 members
Articles » Platforms, Frameworks & Libraries » Win32/64 SDK & OS » General
Tip/Trick
Posted 3 Aug 2017

Tagged as

Stats

41.9K views
67 bookmarked

Using 64-bit DLLs in 32-bit Processes with Out-of-process COM

Rate me:
Please Sign up or sign in to vote.
4.82/5 (29 votes)
1 Jul 2020CPOL
Brief description of how to access 64-bit DLLs from 32-bit processes using a COM bridge
This article shows how to build a 64-bit COM server which is accessible from a 32-bit process to circumvent the process architecture restrictions. Then we make a (simple) 32-bit client to consume our 64-bit COM server component.

Introduction

During application migration tasks, usually a common problem is to use 32-bit DLLs within 64-bit processes as not all used (or even 3rd party) components might be available in a 64-bit version. There are several articles available around in the web which describe how to achieve this.

This article describes the opposite way - using a 64-bit DLL within a 32-bit process using a COM bridge.

Background

In general, the .NET Framework does not support accessing DLLs of different process architectures vice versa by referencing those DLLs within the project directly. Trying to do so will likely end up in a System.BadImageFormatException! Following this Microsoft article about Interprocess Communication between 32-bit and 64-bit applications, there is a little hint on achieving this using a COM bridge approach - but typically, how to do it in detail is not described.

The following example shows how to built a 64-bit COM server which is accessible from a 32-bit process to circumvent the process architecture restrictions.

64-bit COM Server

First of all, every .NET assembly DLL is a COM DLL by default if ensured both 2 lines:

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(true)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f2149837-10a0-44cf-a0d9-987aa62eb0b2")]

Now go on and define a sample class which should be accessible from outside through COM:

using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace BitComTest
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [GuidAttribute("D698BA94-AEFF-3D4F-9D11-BC6DE81D330B")]
    public class ComServer
    {
        /// <summary>
        /// Default constructor - necessary for using with COM
        /// </summary>
        public ComServer() { }

        /// <summary>
        /// Test method to be called by COM sonsumer
        /// </summary>
        public void TestMe()
        {
            MessageBox.Show("Hello from the 64-bit world!");
        }

        /// <summary>
        /// Test function to be called by COM consumer
        /// </summary>
        /// <param name="text">Any text message</param>
        /// <returns>4711 fixed returncode</returns>
        public int TestMeWithResult(string text)
        {
            MessageBox.Show("Hello from the 64-bit world, you provided the text:\n" + text);
            return 4711;
        }
    }
}

Now you're almost done with the COM server component - just don't forget to set the target processor architecture to x64 in order to build a 64-bit forced DLL. In order to register the DLL to be accessible through COM, you have to use the framework tool reagasm.exe - remember to use the 64-bit version to register the DLL in the correct registry hive, i.e.:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe BitComTest.dll /codebase

Don't forget the /codebase switch - you even get a warning on using this without having a strong name for your assembly, it will enter the codebase (DLL target filepath) into the corresponding registry key.

Now comes the magic part. After registering the COM server like shown above, you even would get a ClassNotRegisteredException while trying to use it within a 32-bit client. This is because actually the 32-bit world does not know about the 64-bit COM server by default. To get the ring closure, you have to modify the registry - what else :-). This is slightly easy as the key part is around the CLSID which is set by our COM server using the GuidAttribute attribute.

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\AppID\{D698BA94-AEFF-3D4F-9D11-BC6DE81D330B}]
"DllSurrogate"=""

[HKEY_CLASSES_ROOT\CLSID\{D698BA94-AEFF-3D4F-9D11-BC6DE81D330B}]
"AppID"="{D698BA94-AEFF-3D4F-9D11-BC6DE81D330B}"

Those 2 additional entries define the CLSID as an AppID - so the component will be visible within the 32-bit world. Using the entry DllSurrogate will instantiate the COM server as an out-of-process server using the corresponding processor architecture of the COM server DLL (in this case x64).

32-bit COM Client

Now that all things are prepared in the 64-bit world, we need a (simple) 32-bit client to consume our 64-bit COM server component. An easy example could look like this:

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace _32BitClient
{
    class Program
    {
        static void Main(string[] args)
        {
            // Access COM Object through registered Class Id
            Type ComType = Type.GetTypeFromProgID("BitComTest.ComServer");

            // Create an instance of the COM object
            // This will invoke the default constructor of class ComServer
            object ComObject = Activator.CreateInstance(ComType);

            // Calling the Method "TestMe" from 64-Bit COM server
            ComType.InvokeMember("TestMe", BindingFlags.InvokeMethod, null, ComObject, null);

            // Calling the Method "TestMeWithResult" 
            // from 64-Bit COM server passing through a text
            // an retrieve the resulting int return value
            object[] methodArgs = new object[1];
            methodArgs[0] = "Greetings from the 32-bit world!";
            int result = (int)ComType.InvokeMember("TestMeWithResult", 
                                                   BindingFlags.InvokeMethod, null, 
                                                   ComObject, methodArgs);
            MessageBox.Show("Result of \"TestMeWithResult\" is: " + result.ToString());
            
            // Don't forget to release the late bound COM object,
            // otherwise the surrogate process (dllhost.exe) would live further ...
           if (Marshal.IsComObject(ComObject))
                Marshal.ReleaseComObject(ComObject);
        }
    }
}

Don't forget to set the target processor architecture to x86 in order to build a 32-bit forced assembly!

Once you have started the client and instantiated the COM server, you'll notice an additional dllhost.exe process within the Taskmanager. It should look like this:

Image 1

This indicates a running 64-bit process (dllhost.exe) as an out-of-process COM Surrogate!

In addition, the expected output looks like this:

Image 2Image 3 Image 4

History

  • 2017-08-02: Initial post
  • 2017-08-05: Updated somehow misleading article title
  • 2019-07-24: Editorial refresh

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Carsten Keltsch
Technical Lead IBM
Germany Germany
Technical Lead IT Specialist for Cognitive Input Analytics and Input Management at IBM

Comments and Discussions

 
QuestionHow to return a class objet from 64bit com out proc? Pin
srajesh_nkl24-Apr-20 1:25
Membersrajesh_nkl24-Apr-20 1:25 
QuestionCan this be used to call existing 64bit iFilters from 32bit processes? Pin
GoodJuJu21-Apr-20 1:00
professionalGoodJuJu21-Apr-20 1:00 
AnswerRe: Can this be used to call existing 64bit iFilters from 32bit processes? Pin
Carsten Keltsch23-Apr-20 0:11
MemberCarsten Keltsch23-Apr-20 0:11 
Questionregistry path? Pin
Paul Gutten16-Apr-20 4:18
MemberPaul Gutten16-Apr-20 4:18 
AnswerRe: registry path? Pin
Carsten Keltsch23-Apr-20 0:20
MemberCarsten Keltsch23-Apr-20 0:20 
QuestionNeed help on 64 bit COM server from Windows Service Pin
srajesh_nkl26-Mar-20 21:41
Membersrajesh_nkl26-Mar-20 21:41 
AnswerRe: Need help on 64 bit COM server from Windows Service Pin
Carsten Keltsch6-Apr-20 2:40
MemberCarsten Keltsch6-Apr-20 2:40 
GeneralRe: Need help on 64 bit COM server from Windows Service Pin
srajesh_nkl22-Apr-20 23:36
Membersrajesh_nkl22-Apr-20 23:36 
QuestionMixed mode assembly is built against version 'v2.0.50727' of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information. Pin
Member 1453285628-Dec-19 21:24
MemberMember 1453285628-Dec-19 21:24 
QuestionDifferent GUID? Pin
Ben Quan7-Nov-19 7:58
MemberBen Quan7-Nov-19 7:58 
AnswerRe: Different GUID? Pin
Carsten Keltsch6-Apr-20 2:18
MemberCarsten Keltsch6-Apr-20 2:18 
GeneralRe: Different GUID? Pin
Member 1404467230-Jun-20 7:18
MemberMember 1404467230-Jun-20 7:18 
GeneralRe: Different GUID? Pin
Carsten Keltsch1-Jul-20 3:21
MemberCarsten Keltsch1-Jul-20 3:21 
QuestionHow can we get back the events from the COM server? Pin
ikcelam5-Apr-19 4:37
Memberikcelam5-Apr-19 4:37 
AnswerRe: How can we get back the events from the COM server? Pin
Carsten Keltsch6-Apr-20 2:36
MemberCarsten Keltsch6-Apr-20 2:36 
QuestionCan this be inverted? Pin
B.O.B.9-Jan-19 5:50
MemberB.O.B.9-Jan-19 5:50 
AnswerRe: Can this be inverted? Pin
Carsten Keltsch6-Apr-20 2:23
MemberCarsten Keltsch6-Apr-20 2:23 
QuestionNot just .NET Pin
R.D.H.7-Aug-17 11:02
MemberR.D.H.7-Aug-17 11:02 
Praiseout-of-process COM server Pin
Randor 4-Aug-17 22:07
professional Randor 4-Aug-17 22:07 
QuestionRe: out-of-process COM server Pin
Carsten Keltsch5-Aug-17 9:08
MemberCarsten Keltsch5-Aug-17 9:08 
AnswerRe: out-of-process COM server Pin
Randor 8-Aug-17 5:19
professional Randor 8-Aug-17 5:19 
GeneralRe: out-of-process COM server Pin
joelmoore4-Jun-19 5:27
Memberjoelmoore4-Jun-19 5:27 
GeneralRe: out-of-process COM server Pin
Randor 12-Jun-19 23:33
professional Randor 12-Jun-19 23:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.