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

如何将外部C++ DLL合并到C# EXE生成单一可执行文件?

将外部C++ DLL嵌入C# WinForm EXE的解决方案

步骤1:正确配置DLL的嵌入资源

  • 在Visual Studio中选中processFiles.dll,在属性面板设置:
    • 生成操作:嵌入的资源
    • 复制到输出目录:不复制

步骤2:添加资源提取工具类

因为DllImport只能加载磁盘上的文件,所以需要先把嵌入的DLL提取到临时目录,添加以下代码:

using System;
using System.IO;
using System.Reflection;

public static class DllExtractor
{
    public static void ExtractDll(string resourceName, string outputPath)
    {
        using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
        {
            if (stream == null)
                throw new FileNotFoundException("未找到嵌入的DLL资源", resourceName);

            using (FileStream fileStream = new FileStream(outputPath, FileMode.Create))
            {
                stream.CopyTo(fileStream);
            }
        }
    }
}

步骤3:调整DLL调用逻辑

3.1 提前提取DLL

在程序启动时(比如Program.cs的Main方法,或Form1_Load开头)执行提取操作:

string tempDllPath = Path.Combine(Path.GetTempPath(), "processFiles.dll");
// 仅当临时文件不存在时提取,避免重复操作
if (!File.Exists(tempDllPath))
{
    // 资源名称格式:项目命名空间.DLL文件名,例如你的项目叫WinFileProcessor,就是WinFileProcessor.processFiles.dll
    // 不确定名称的话,可以用Assembly.GetExecutingAssembly().GetManifestResourceNames()打印所有资源名确认
    DllExtractor.ExtractDll("YourProjectNamespace.processFiles.dll", tempDllPath);
}

3.2 修改DLL调用方式

有两种可选方案:

方案一:动态修改DllImport路径

// 先定义动态导入的方法
[DllImport("", CharSet = CharSet.Unicode, EntryPoint = "startActions")]
public static extern void startActions();

// 在调用前设置DLL搜索路径
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool SetDllDirectory(string lpPathName);

// 在Form1_Load中调用:
SetDllDirectory(Path.GetDirectoryName(tempDllPath));
startActions();

方案二:完全动态加载(更灵活)

替换原来的静态DllImport,用手动加载的方式:

// 定义委托匹配DLL函数签名
private delegate void StartActionsDelegate();

// 导入系统API用于加载DLL
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr LoadLibrary(string lpFileName);

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

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

// 在Form1_Load中调用:
IntPtr dllHandle = LoadLibrary(tempDllPath);
if (dllHandle == IntPtr.Zero)
    throw new System.ComponentModel.Win32Exception();

try
{
    var startActionsFunc = (StartActionsDelegate)Marshal.GetDelegateForFunctionPointer(
        GetProcAddress(dllHandle, "startActions"),
        typeof(StartActionsDelegate));
    startActionsFunc();
}
finally
{
    FreeLibrary(dllHandle);
}

关键注意事项

  • 资源名称必须准确:可以通过Assembly.GetExecutingAssembly().GetManifestResourceNames()输出所有嵌入资源的名称,核对你的DLL对应的名称。
  • 平台位数匹配:如果你的C++ DLL是x86或x64专属版本,需要在项目属性的生成选项卡中设置对应的平台目标,避免位数不匹配导致加载失败。
  • 临时目录权限:确保程序有写入系统临时目录的权限,一般默认环境下都满足,受限环境需额外处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:21:12