You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于DllImport调用供应商DLL时无需复制DLL的多连接方案问询

Solution for Multiple Connections Without Duplicating Supplier DLLs

Great question! The behavior you're seeing tells me the supplier's DLL is using global internal state—it tracks a single connection context per loaded DLL instance. Duplicating the DLL works because each copy gets loaded as a separate, isolated instance with its own state. But there's a cleaner way to do this without copying files or recompiling every time.

1. Dynamic DLL Loading with LoadLibrary + GetProcAddress

This is the most straightforward fix. Instead of using DllImport (which loads the DLL once at startup), you'll load the DLL dynamically each time you need a new connection. Every call to LoadLibrary on the same DLL file creates a separate instance with its own global state.

Here's how to implement this in C#:

First, define delegates that match the signature of the DLL's exported functions:

using System;
using System.Runtime.InteropServices;

// Match the exact signature of AllocateHandle
private delegate bool AllocateHandleDelegate(out uint handle, string connectionDetails);
// Match the exact signature of DeallocateHandle
private delegate bool DeallocateHandleDelegate(uint handle);

Then, use Windows API functions to load the DLL, get function pointers, and clean up:

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadLibrary(string dllPath);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FreeLibrary(IntPtr hModule);

// Helper class to manage a single DLL instance and its connection
public class SupplierConnection : IDisposable
{
    private readonly IntPtr _dllHandle;
    private readonly AllocateHandleDelegate _allocateHandle;
    private readonly DeallocateHandleDelegate _deallocateHandle;
    public uint ConnectionHandle { get; private set; }

    public SupplierConnection(string dllPath, string connectionDetails)
    {
        // Load a new instance of the DLL
        _dllHandle = LoadLibrary(dllPath);
        if (_dllHandle == IntPtr.Zero)
        {
            throw new System.ComponentModel.Win32Exception();
        }

        // Get pointers to the exported functions
        IntPtr allocatePtr = GetProcAddress(_dllHandle, "AllocateHandle");
        IntPtr deallocatePtr = GetProcAddress(_dllHandle, "DeallocateHandle");

        if (allocatePtr == IntPtr.Zero || deallocatePtr == IntPtr.Zero)
        {
            FreeLibrary(_dllHandle);
            throw new InvalidOperationException("Could not find exported functions in DLL.");
        }

        // Convert pointers to delegates
        _allocateHandle = Marshal.GetDelegateForFunctionPointer<AllocateHandleDelegate>(allocatePtr);
        _deallocateHandle = Marshal.GetDelegateForFunctionPointer<DeallocateHandleDelegate>(deallocatePtr);

        // Initialize the connection
        if (!_allocateHandle(out ConnectionHandle, connectionDetails))
        {
            FreeLibrary(_dllHandle);
            throw new InvalidOperationException("Failed to allocate handle for connection.");
        }
    }

    public void Dispose()
    {
        // First release the handle using this DLL instance's DeallocateHandle
        if (ConnectionHandle != 0)
        {
            _deallocateHandle(ConnectionHandle);
            ConnectionHandle = 0;
        }

        // Then unload the DLL instance
        if (_dllHandle != IntPtr.Zero)
        {
            FreeLibrary(_dllHandle);
        }
    }
}

To use this:

// Create two separate connections to different addresses, no DLL duplication needed!
using var conn1 = new SupplierConnection(@"C:\Path\To\Supplier.dll", "10.1.1.1");
using var conn2 = new SupplierConnection(@"C:\Path\To\Supplier.dll", "10.1.1.2");

// Use conn1.ConnectionHandle and conn2.ConnectionHandle with other DLL functions (you'd extend the SupplierConnection class to wrap those too)

Key notes:

  • Each SupplierConnection instance uses its own loaded DLL copy, so their states don't interfere.
  • Always call Dispose() (or use using statements) to clean up the handle and unload the DLL.
  • You'll need to wrap any other DLL functions you need in the same way, using delegates and GetProcAddress.

2. Check for Supplier API Alternatives

Before diving into dynamic loading, double-check the supplier's documentation or reach out to their support. Some DLLs offer a way to create multiple connections explicitly—for example:

  • Functions that accept a custom context object (instead of relying on global state)
  • An extended AllocateHandle method that takes an instance ID or additional parameters to isolate connections

If such an API exists, this will be a much cleaner solution than dynamic loading.

3. AppDomain Isolation (Advanced)

For more complex scenarios, you could create a separate AppDomain for each connection. Each AppDomain loads its own copy of the DLL, so they're fully isolated. However, this approach adds significant complexity:

  • Data passed between AppDomains must be serializable
  • Managing AppDomains and cleanup is more involved

Dynamic loading is almost always preferable unless you have specific reasons to use AppDomains.


内容的提问来源于stack exchange,提问作者Tvde1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:46:21