欢迎光临散文网 会员登陆 & 注册

C语言编译成DLL文件,编译成EXE文件,执行简单功能

2023-06-13 13:56 作者:LiSunSDK  | 我要投稿

一、简介

在联合开发过程中,用c语言写好功能函数,给其他上位机程序调用。


二、步骤

1. 先编写c语言文件。用CRC8举例。crc8_2f.c crc8_2f.h


```c

#include <stdint.h>

#include <stdio.h>


/* Constant array CRC8 */

static const uint8_t LIB_Crc8Table1[16] = {

    0x42u, 0x6du, 0x1cu, 0x33u, 0xfeu, 0xd1u, 0xa0u, 0x8fu,

    0x15u, 0x3au, 0x4bu, 0x64u, 0xa9u, 0x86u, 0xf7u, 0xd8u

};


static const uint8_t LIB_Crc8Table2[16] = {

    0x42u, 0xecu, 0x31u, 0x9fu, 0xa4u, 0x0au, 0xd7u, 0x79u,

    0xa1u, 0x0fu, 0xd2u, 0x7cu, 0x47u, 0xe9u, 0x34u, 0x9au

};


/**

 * @brief This function calculates a CRC8 over the data buffer

 * @param LIB_TempInputCrc8_cp[in]: pointer to the input data

 * @param LIB_TempLengthCrc8_u16[in]: Length of the input data

 * @return Calculated CRC8

 * @details Local variables

 *          Loop over all byte

 *              Execute CRC algorithm

 *          Return inverted result

 * @ReqKey MOD_LIB-64, MOD_LIB-65

 */

uint8_t CRC8Calculation(const uint8_t* data, const uint16_t len) {

    /* Local Variables */

    uint8_t LIB_TempCrc8_u8 = 0xFFu;

    uint16_t LIB_TempIndexCrc8_u16;


    /* Loop over all bytes */

    for (LIB_TempIndexCrc8_u16 = 0u;

         LIB_TempIndexCrc8_u16 < len;

         LIB_TempIndexCrc8_u16++) {

        /* CRC Algorithm */

        LIB_TempCrc8_u8 = data[LIB_TempIndexCrc8_u16] ^ LIB_TempCrc8_u8;

        LIB_TempCrc8_u8 = (LIB_Crc8Table1[LIB_TempCrc8_u8 & 0x0Fu]) ^

                          (LIB_Crc8Table2[LIB_TempCrc8_u8 >> 4u]);

    }


    return (LIB_TempCrc8_u8 ^ 0xFF);

}


```


```c

#include <stdint.h>

#include <stdio.h>

#include <string.h>

#ifndef CRC8_2F_H_

#define CRC8_2F_H_


uint8_t CRC8Calculation(void* data, uint16_t size);

#endif

```


2. 编译成DLL文件

cmd 执行下面命令:

```bash

gcc -shared crc8_2f.c -o crc8_2f.dll

```


需要安装gcc编译器**mingw32**。


3. 给上位机调用

(1)C#


```csharp


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Runtime.InteropServices;

 

namespace CallTheDll01

{

    class Program

    {

        // 在此处使用 crc8_2f.dll 文件的绝对路径

        [DllImport(@"D:\crc8_2f.dll",CallingConvention=CallingConvention.Cdecl)]

        public static extern byte CRC8Calculation(void* data, ushort size);

 

        // 上面已经使用了 crc8_2f.dll 文件的绝对路径,

        // 在此处可以只写该 dll文件名,但为了保险起见,还是最好写待调用dll文件的绝对路径名

        [DllImport("crc8_2f.dll", EntryPoint = "CRC8Calculation",CallingConvention =CallingConvention.Cdecl)]

        public static extern byte CRC8_Cal(void* data, ushort size);

        static void Main(string[] args)

        {

        byte[] data = new byte[] {3, 32, 35, 6, 12, 21, 122};

            Console.WriteLine("{0}", CRC8Calculation(data, 7));

            Console.WriteLine("{0}", CRC8_Cal(data, 7));

            Console.ReadKey();

        }

    }

```


(2) 易语言


```bash

.版本 2


.DLL命令 read, 整数型, "crc8_2f.dll", "@CRC8Calculation", 公开, @代表使用__stdcall,否则报错-堆栈错误

    .参数 buff, 字节集, 传址

    .参数 len, 整数型


```


 三、编译成EXE

## 1. 编写一个c文件。 merge_hex.c(例:hex文件合并)


```c

#include <direct.h>

#include <memory.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>


/**

 * @brief  得到文件行

 * @param  path: 文件路径

 * @retval 文件行数(hex文件每行44列)

 */

int GetFileLIine(char* path) {

    int i = 0;

    //    char j = 0;

    char str[45];

    FILE* fp;

    //    printf("Path: %s \n",path);

    if ((fp = fopen(path, "r")) == NULL)

        printf("fail to open the file path:%s! \n", path);


    while (fgets(str, 45, fp)) {

        i++;

    }

    fclose(fp);

    return i;

}


/**

 * @brief  路径处理

 * @param  ParaPath: 

 * @param  TargetPath: 目标路径

 * @param  flag:  1表示遇到'\'需要进行增加一个'\'处理, 0表示不需要处理

 * @retval 

 */

int FileNameHandle(char* ParaPath, char* TargetPath, int flag) {

    char* CurrentPath;

    int i = 0, j = 0, k = 0;

    int PathLevel = 0, PathLast = 0;


    // 获取传入的参数路径有多少个上级目录,也就是"..\"的个数

    for (i = 0; (ParaPath[i] == '\\') || (ParaPath[i] == '.'); i++) {

        if ((ParaPath[i] == '.') && (ParaPath[i - 1] == '.')) {

            PathLevel++;

        }

    }

    // printf("ParaPath:%s\n",ParaPath);

    // printf("PathLevel:%d  i is:%d\n",PathLevel,i);


    // 获取当前绝对路径

    if ((CurrentPath = getcwd(NULL, 0)) == NULL) {

        perror("getcwd error");

    }

    // printf("CurrentPath: %s\n",CurrentPath);


    // 当前绝对路径字符串由后往前遍历,根据上级目录个数PathLevel,去掉多余路径,得到参数路径的绝对路径

    for (i = strlen(CurrentPath) - 1; PathLast < PathLevel; i--) {

        if (CurrentPath[i] == '\\') {

            PathLast++;

        }

    }

    // printf("PathLast:%d  i is:%d\n",PathLast,i);


    // 将处理后的当前绝对路径,赋值到目标路径的前面

    for (j = 0, k = 0; j <= i; j++) {

        TargetPath[k++] = CurrentPath[j];

        if (flag)

            if (CurrentPath[j] == '\\')

                TargetPath[k++] = '\\';

    }

    TargetPath[k] = '\0';

    // printf("TargetPath:%s\n",TargetPath);


    for (i = 0; ParaPath[i] != '\0'; i++) {

        if (ParaPath[i] != '.') {

            TargetPath[k++] = ParaPath[i];

            if (flag)

                if (ParaPath[i] == '\\')

                    TargetPath[k++] = ParaPath[i];

        }

        if ((ParaPath[i] == '.') && ((ParaPath[i - 1] != '.') && (ParaPath[i + 1] != '.')))

            TargetPath[k++] = ParaPath[i];

    }

    TargetPath[k] = '\0';


    // printf("TargetPath:%s\n",TargetPath);

    free(CurrentPath);

    return k;

}


int FileHandle(char* path1, char* path2, char* path3, char* path4) {

    FILE* fp1;

    FILE* fp2;

    FILE* fp3;

    char str[45];

    char* mergeflie;

    int i = 0;

    int k1 = 0, k2 = 0;


    char CurrentPath[2048];


    FileNameHandle(path4, CurrentPath, 0);


    k1 = GetFileLIine(path1);

    k2 = GetFileLIine(path2);

    mergeflie = (char*)malloc((k1 + k2) * 45);

    mergeflie[0] = '\0';


    if ((fp1 = fopen(path1, "r")) == NULL)

        printf("fail to open the file path:%s! \n", path1);


    for (i = 0; i < k1 - 2; i++) {

        fgets(str, 45, fp1);

        strcat(mergeflie, str);

    }

    fclose(fp1);

    // printf("Path: %s,line number:%d \n",path1,i);


    if ((fp2 = fopen(path2, "r")) == NULL)

        printf("fail to open the file path:%s! \n", path2);


    // printf("k2-1:%d\n",k2-1);


    fgets(str, 45, fp2);

    for (i = 0; i < k2 - 1; i++) {

        fgets(str, 45, fp2);

        strcat(mergeflie, str);

    }

    fclose(fp2);


    i = strlen(mergeflie);

    mergeflie[i] = '\n';


    if ((fp3 = fopen(path3, "w")) == NULL)

        printf("fail to open the file path:%s! \n", path3);

    else {

        fwrite(mergeflie, strlen(mergeflie), 1, fp3);

        printf("creat %s success!\n", CurrentPath);  // 打印参数传入的原始路径

    }


    fclose(fp3);


    free(mergeflie);

    return 0;

}


int main(int argc, char** argv) {

    char path[3][2048];


    if (argc < 4) {

        printf("error!\n");

        printf("参数缺失\n");

        return -1;

    }

    FileNameHandle(argv[1], path[0], 1);  // bootloader path

    FileNameHandle(argv[2], path[1], 1);  // app path

    FileNameHandle(argv[3], path[2], 1);  // mergeHex path

    FileHandle(path[0], path[1], path[2], argv[3]);

    return 0;

}


```


 2. 编译文件


```bash

gcc merge_hex.c -o mergeHEX2.exe

```


## 3. 合并脚本.bat


```bash

echo off

mergeHEX2.exe .\BOOT.hex .\MCU.hex .\boot_app.hex

pause


```

用于合并hex文件的小工具,通过批处理脚本调用传参,在MDK中,可以在魔术棒的User选项卡设置编译后调用批处理脚本,使用起来非常方便.


C语言编译成DLL文件,编译成EXE文件,执行简单功能的评论 (共 条)

分享到微博请遵守国家法律