Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

C# 集成 C++ 的方法和实践 - P/Invoke(平台调用)- 1

10 篇文章 0 订阅

环境:


P/Invoke(平台调用):

C#可以通过P/Invoke调用C++编写的DLL中的函数。

1.1 适用范围:

P/Invoke 是一种在 C# 程序中调用非托管代码(如 C++ 动态链接库)的方式。这种方法适用于函数调用相对简单的情况。

1.2 步骤:

  • 在 C++ 中编写算法并编译生成 DLL。
  • 在 C# 项目中使用 DllImport 属性引入 DLL。

 1.3 案例程序:

1.3.1 新建一个ExportedFunctions.cpp【函数调用法】

// MathFunctions.cpp
#include "MathFunctions.h"

int Add(int a, int b) {
    return a + b;
}

特点

  • 使用了extern "C",这告诉编译器按照C语言的方式处理函数名,避免了名称修饰。
  • 使用了__declspec(dllexport),这指示编译器导出该函数,使其在DLL中可见。
  • 这是一个自由函数(不属于任何类),可以直接被P/Invoke调用。

1.3.2 新建一个 ExportedFunctions.h

// MathFunctions.h
#pragma once

extern "C" {
    __declspec(dllexport) int Add(int a, int b);
}

 1.3.3 在C#中调用动态库的函数:

using System;
using System.Runtime.InteropServices;

class Program
{
    // 使用DllImport属性声明DLL中的函数
    [DllImport("MathFunctions.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int Add(int a, int b);

    static void Main(string[] args)
    {
        // 调用DLL中的Add函数
        int result = Add(5, 10);
        Console.WriteLine("The result of adding 5 and 10 is: " + result);
    }
}

2 VS STUDIO 生成DLL的DllMain模板给出的意义:

2.1 dllmain.cpp文件

包含了DllMain函数的框架。DllMain是DLL的入口点,它是一个特殊的函数,由Windows操作系统在DLL的生命周期中的关键时刻自动调用。这个函数的原型由Windows API定义,其作用是处理DLL的各种加载和卸载事件。

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

DllMain函数的参数如下:

  • HMODULE hModule:被加载DLL的模块句柄。
  • DWORD ul_reason_for_call:调用原因代码,指示为什么调用DllMain
  • LPVOID lpReserved:保留参数,用于特定调用原因的附加信息。

ul_reason_for_call参数可以有以下几种值:

  • DLL_PROCESS_ATTACH:DLL被加载到地址空间中时调用。这是初始化DLL设置的好地方,例如全局变量的初始化。
  • DLL_THREAD_ATTACH:一个新线程被创建到包含DLL的进程中时调用。这允许DLL为每个线程设置特定的数据。
  • DLL_THREAD_DETACH:一个线程结束时调用,不再需要DLL的服务。这可以用来清理线程特定的数据。
  • DLL_PROCESS_DETACH:DLL从进程的地址空间卸载时调用。这是执行清理工作,如释放资源和注销全局变量的好地方。

DllMain函数中,每个case对应一个调用原因。在默认情况下,Visual Studio生成的模板代码中,这些case下没有任何操作,只是简单的break语句。这意味着DLL在加载和卸载时不会执行任何特别的操作。如果你需要在DLL加载或卸载时执行特定的初始化或清理代码,你可以在相应的case下添加你的代码。例如:

switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
    // 初始化代码,如分配资源
    break;
case DLL_THREAD_ATTACH:
    // 线程特定初始化代码
    break;
case DLL_THREAD_DETACH:
    // 线程退出时的清理代码
    break;
case DLL_PROCESS_DETACH:
    // 进程退出时的清理代码,如释放资源
    break;
}

3 在VS 2019中,融合DllMain模板和P/Invoke(平台调用)

 3.1 在C#中进行集成:

将编译好的DLL文件放在你的C#项目可以访问到的位置。

我现在项目目录下,构建了一个lib目录,

然后,在C#中引入dll,

添加,编译好的C++库


问题:

1 尝试引入DLL

解决:

当您使用P/Invoke调用非托管代码(如C++ DLL)时,不需要注册DLL或将其作为COM组件。 

确保dll文件位于C#项目的输出目录中(如bin/Debugbin/Release),或者将DLL文件路径添加到系统PATH环境变量中。

 2 无法找到入口:

Error: 无法在 DLL“AAMED_DLL_DEMO1.dll”中找到名为“Add”的入口点。
 

 笔者的地址在下面:

D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\bin\HostX64\x64 

 执行命令如下:

 .\dumpbin.exe /EXPORTS K:\Prj_MotosCatch\Prj_Src\AAMED_LIB_Demo\AAMED_DLL_DEMO1\x64\Debug\AAMED_DLL_DEMO1.dll

结果:

PS D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\bin\HostX64\x64> .\dumpbin.exe /EXPORTS K:\Prj_MotosCatch\Prj_Src\AAMED_LIB_Demo\AAMED_DLL_DEMO1\x64\Debug\AAMED_DLL_DEMO1.dll
Microsoft (R) COFF/PE Dumper Version 14.20.27525.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file K:\Prj_MotosCatch\Prj_Src\AAMED_LIB_Demo\AAMED_DLL_DEMO1\x64\Debug\AAMED_DLL_DEMO1.dll

File Type: DLL

  Summary

        1000 .00cfg
        1000 .data
        2000 .idata
        1000 .msvcjmc
        3000 .pdata
        3000 .rdata
        1000 .reloc
        1000 .rsrc
        9000 .text
       10000 .textbss

 确实没有看到add的函数入口

修正代码,之前想按CLASS来写不行:

然后,重新执行:

PS D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\bin\HostX64\x64> .\dumpbin.exe /EXPORTS K:\Prj_MotosCatch\Prj_Src\AAMED_LIB_Demo\AAMED_DLL_DEMO1\x64\Debug\AAMED_DLL_DEMO1.dll
Microsoft (R) COFF/PE Dumper Version 14.20.27525.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file K:\Prj_MotosCatch\Prj_Src\AAMED_LIB_Demo\AAMED_DLL_DEMO1\x64\Debug\AAMED_DLL_DEMO1.dll

File Type: DLL

  Section contains the following exports for AAMED_DLL_DEMO1.dll

    00000000 characteristics
    FFFFFFFF time date stamp
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 0001133E Add = @ILT+825(Add)

  Summary

        1000 .00cfg
        1000 .data
        2000 .idata
        1000 .msvcjmc
        3000 .pdata
        3000 .rdata
        1000 .reloc
        1000 .rsrc
        9000 .text
       10000 .textbss

这时候,已经能看到Add的函数定义了,运行后结果正常,可以运行DLL的函数内容。


本文的案例代码:需要知识付费:

https://download.csdn.net/download/yellow_hill/89396682

  • 16
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Franklin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值