Home > Net >  64bit C# .Net Wrapper for 32bit C# .Net DLL
64bit C# .Net Wrapper for 32bit C# .Net DLL

Time:11-09

I have a 32bit Software written in C# who Communicates with many different devices. Because of memory problems i upgraded to a 64bit System, no big Deal for the C# Software itself. But for some of the implemented devices i had to change the way of implementation, it worked for all expect for one! There i have a DLL which is written in C# 32bit, who is responsible for the communication to the device. Made by the supplier. I asked the supplier for a 64bit version but unfortunately its not possible for them to give me one.

My Idea was to create an Wrapper to make the DLL available to my 64bit Software. I have seen that there are where many other people with a similar problem, but they always hat to Wrap an unmanaged DLL. So my tried to write an wrapper who use COM to get the work done. But failed while implementing the C# COM Server into my C# Client. Here is the Idea what is tried: https://blog.mattmags.com/2007/06/30/accessing-32-bit-dlls-from-64-bit-code/

Another Idea was to use a open source Project who can this topic with DLLImports: https://github.com/CodefoundryDE/LegacyWrapper

There i could load it with DLLImport but i could not find the EntryPoint to my needed functions. The question here is, if i'm completly on the wrong way and i can not load a managed DLL into C# with DLLImport or if i missed something and i just need to adjust the parameters. Here is the Code i used so far (i changed the Names of the DLL)

    [LegacyDllImport(@"C:\Program Files (x86)\Company\Device\API.dll")]
    public interface IClassA : IDisposable
    {        
        [LegacyDllMethod(CallingConvention = CallingConvention.Winapi)]
        bool MethodA();        
    }

CodePudding user response:

I used the example: https://learn.microsoft.com/de-de/samples/dotnet/samples/out-of-process-com-server/

Here is the Git Link: https://github.com/dotnet/samples/tree/main/core/extensions/OutOfProcCOM

to create an out of process com server to handle the bitness difference.

i "only" had to get familiar with the concept and had to change the the call of the Server a bit. I changed the value of "CLSCTX_LOCAL_SERVER" from 0x4 to x40004 to force the call of a x86 Server!

 private class Ole32
    {
        // https://docs.microsoft.com/windows/win32/api/wtypesbase/ne-wtypesbase-clsctx
        public const int CLSCTX_LOCAL_SERVER = 0x40004;//0x4;

        // https://docs.microsoft.com/windows/win32/api/combaseapi/nf-combaseapi-cocreateinstance
        [DllImport(nameof(Ole32))]
        public static extern int CoCreateInstance(
            [In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
            IntPtr pUnkOuter,
            uint dwClsContext,
            [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
            [MarshalAs(UnmanagedType.IUnknown)] out object ppv);
    }

CodePudding user response:

As addition to the @CyberMochi answer. In particular case of x86-server and x64-client we don't need to call CoCreateInstance explicitly, as in case of bitness missmatch the standard .net COM interop mechanisms can do all the things automatically for us.

So, with the same sample (https://github.com/dotnet/samples/tree/main/core/extensions/OutOfProcCOM) I done the following:

  1. (optional) Migrated to net6

  2. Explicitly set bitnes for client (<PlatformTarget>x64</PlatformTarget>) and server (ExeServer.csproj: <PlatformTarget>x86</PlatformTarget>)

  3. Built and registered server with "<path-to-samples>\ExeServer\bin\Debug\net6.0\ExeServer" /regserver (this need to be executed from elevated/admin command line)

  4. Removed IServer declaration from the client project as the all information needed will be extracted from a tlb.

  5. Reference the Server.Contract.tlb (from \ExeServer\bin\Debug\net6.0 folder) in the client project - "Add COM reference" into solution explorer. This added the following into csproj

       <ItemGroup>
         <COMReference Include="ServerLib">
           <VersionMinor>0</VersionMinor>
           <VersionMajor>0</VersionMajor>
           <Guid>46f3feb2-121d-4830-aa22-0cda9ea90dc3</Guid>
           <Lcid>0</Lcid>
           <WrapperTool>tlbimp</WrapperTool>
           <Isolated>false</Isolated>
           <EmbedInteropTypes>true</EmbedInteropTypes>
         </COMReference>
       </ItemGroup>
    
  6. Use the server from the client with the code

         var server = new ServerLib.Server();
         var pi = server.ComputePi();
         Console.WriteLine(pi); 
    

Some additional notes:

  1. You can use per-user registration of the COM server. This will not require admin priveleges. But you will need to rewrite registration code - see here for details: Registering a COM without Admin rights
  2. Instead of COM reference you can manually create COM interop DLL from the tlb with a tlbimp tool and reference this interop dll. This will speedup a build process.
  • Related